簡介
我曾在一些實驗中使用 Three.js,這項工具確實能有效簡化在瀏覽器中處理 3D 內容的繁瑣程序。你可以使用它建立攝影機、物件、燈光、材質等,還可以選擇渲染器,也就是說,你可以決定要使用 HTML 5 的畫布、WebGL 還是 SVG 來繪製場景。由於這是開放原始碼,您甚至可以參與專案。不過,現在我會著重介紹我將其當作引擎使用時學到的知識,並向您介紹一些基本概念。
雖然 Three.js 有許多優點,但有時您可能會遇到困難。通常您需要花費大量時間研究範例、進行反向工程,以及 (至少我個人是這樣) 尋找特定功能,有時還要透過 GitHub 提問。順帶一提,如果您有任何問題,Mr. doob 和 AlteredQualia 都能提供極大的幫助!
1. 基本概念
我會假設您至少對 3D 有初步瞭解,並具備合理的 JavaScript 熟練度。如果沒有,建議您先瞭解一下,再嘗試使用這些功能,因為這可能會有點令人困惑。
在 3D 世界中,我們會建立下列部分項目,我會引導您完成建立程序:
- 場景
- 轉譯器
- 相機
- 一或兩個物件 (含材質)
當然,您可以做一些很酷的事情,我希望您能繼續這樣做,並開始在瀏覽器中嘗試 3D。
2. 支援
這裡要簡單說明瀏覽器支援。根據我的經驗,Google Chrome 瀏覽器在支援的轉譯器和基礎 JavaScript 引擎的速度方面,是最好的瀏覽器。Chrome 支援 Canvas、WebGL 和 SVG,而且速度極快。Firefox 緊追在後,第 4 版推出後,JavaScript 引擎似乎比 Chrome 稍慢,但對轉譯技術的支援同樣出色。Opera 和 Safari 正在新增 WebGL 支援,但目前版本僅支援畫布。Internet Explorer (9 以上版本) 僅支援畫布算繪,且據我所知,Microsoft 並未計劃新增 WebGL 功能。
3. 背景資訊
假設您選擇的瀏覽器支援所有轉譯技術,且您想使用 Canvas 或 WebGL 轉譯,因為這些是較標準的選擇。Canvas 的支援範圍比 WebGL 更廣,但值得注意的是,WebGL 是在顯示卡的 GPU 上執行,這表示 CPU 可以專注於其他非轉譯工作,例如您嘗試執行的任何物理或使用者互動。
無論選擇哪種轉譯器,請務必最佳化 JavaScript 效能。3D 對瀏覽器來說並非輕量工作 (而且甚至可以做到這一點),因此請務必瞭解程式碼中的瓶頸,並盡可能移除!
因此,假設您已下載 three.js 並加入 HTML 檔案,該如何設定場景?如下所示:
// set the scene size
var WIDTH = 400,
HEIGHT = 300;
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
// get the DOM element to attach to
// - assume we've got jQuery to hand
var $container = $('#container');
// create a WebGL renderer, camera
// and a scene
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR );
var scene = new THREE.Scene();
// the camera starts at 0,0,0 so pull it back
camera.position.z = 300;
// start the renderer
renderer.setSize(WIDTH, HEIGHT);
// attach the render-supplied DOM element
$container.append(renderer.domElement);
其實不難!
4. 建立網格
現在我們有場景、攝影機和轉譯器 (我在程式碼範例中選擇 WebGL),但沒有實際要繪製的內容。Three.js 支援載入幾種不同的標準檔案類型,如果您是從 Blender、Maya、Cinema4D 或其他軟體輸出模型,這項功能就非常實用。為簡化流程 (畢竟這只是入門指南!),我會說明基本類型。基本圖元是幾何網格,相對基本的網格包括球體、平面、立方體和圓柱體。Three.js 可讓您輕鬆建立下列類型的基本圖元:
// set up the sphere vars
var radius = 50, segments = 16, rings = 16;
// create a new mesh with sphere geometry -
// we will cover the sphereMaterial next!
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(radius,
segments,
rings),
sphereMaterial);
// add the sphere to the scene
scene.add(sphere);
一切順利,但球體的材質呢?在程式碼中,我們使用了變數 sphereMaterial,但尚未定義。首先,我們需要進一步討論材質。
5. 材質
毫無疑問,這是 Three.js 最實用的部分之一。提供多種常見 (且非常實用) 的材質,可套用至網格:
- 「Basic」:表示會算繪「無光照」
- Lambert
- Phong
還有其他選項,但為了簡單起見,我會讓您自行探索。尤其是 WebGL,這些教材可以幫上大忙。這是因為因為在 WebGL 中,你必須為所有要算繪的內容編寫著色器。著色器本身是個龐大的主題,但簡而言之,著色器是以 GLSL (OpenGL 著色語言) 編寫,可指示 GPU 某個項目的外觀。這表示您需要模擬光線、反射等數學運算。這項工作很快就會變得非常複雜。多虧有 Three.js,您不必這麼做,因為它會為您抽象化。不過,如果您想編寫著色器,也可以使用 MeshShaderMaterial,因此這項設定相當靈活。
不過,現在先將 Lambert 材質套用至球體:
// create the sphere's material
var sphereMaterial = new THREE.MeshLambertMaterial(
{
// a gorgeous red.
color: 0xCC0000
});
值得注意的是,建立材質時,除了顏色之外,您還可以指定其他屬性,例如平滑或環境貼圖。請查看 Wiki 頁面,瞭解可在材質上設定的各種屬性,以及引擎提供的任何物件。此外,threejs.org 最近也開始提供更吸引人的 API 檢視畫面。
6. 燈光!
如果現在算繪場景,會看到一個紅色圓圈。雖然我們套用了 Lambert 材質,但場景中沒有光線,因此 Three.js 預設會還原為完整的環境光,這與平面著色相同。我們可以用簡單的光點來解決這個問題:
// create a point light
var pointLight = new THREE.PointLight( 0xFFFFFF );
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
7. 呈現
現在,我們已完成所有設定,可以開始算繪了。但我們實際上需要繼續執行以下操作:
// draw!
renderer.render(scene, camera);
不過,您可能需要多次算繪,因此如果要執行迴圈,建議使用 requestAnimationFrame,這是目前在瀏覽器中處理動畫最聰明的方法。目前尚未完全支援,因此強烈建議您查看 Paul Irish 的 shim。
8. 常見物件屬性
如果花時間查看 Three.js 的程式碼,會發現許多物件都「繼承」自 Object3D。這是一個基礎物件,包含一些非常實用的屬性,例如 position、rotation 和 scale 資訊。具體來說,我們的 Sphere 是繼承自 Object3D 的 Mesh,並新增了專屬屬性:geometry 和 materials。為什麼要提到這些?您不太可能只想在畫面上顯示一個球體,而不做任何動作,因此這些屬性值得研究,因為它們可讓您即時操控網格和材質的基礎細節。
// sphere geometry
sphere.geometry
// which contains the vertices and faces
sphere.geometry.vertices // an array
sphere.geometry.faces // also an array
// its position
sphere.position // has x, y and z properties
sphere.rotation // same
sphere.scale // ... same
9. 不可告人的秘密
我想快速指出 Three.js 的一個小陷阱,那就是如果你修改了網格的頂點,你會發現渲染迴圈中沒有任何變化。這是因為因為 Three.js (據我所知) 會快取網格的資料,做為最佳化。您實際需要做的是向 Three.js 標記某些內容已變更,以便重新計算所需內容。方法如下:
// changes to the vertices
sphere.geometry.__dirtyVertices = true;
// changes to the normals
sphere.geometry.__dirtyNormals = true;
還有其他方法,但我認為這兩種最實用。顯然,您應該只標記已變更的內容,避免不必要的計算。
結論
希望這篇 Three.js 簡介對您有幫助。實際動手嘗試是最好的學習方式,我非常推薦。在瀏覽器中原生執行 3D 內容非常有趣,使用 Three.js 等引擎可以省去許多麻煩,讓您能專心製作一些非常酷炫的作品。為了提供協助,我已在本實驗室文章中整理了原始碼,供您參考。如果您喜歡這篇文章,請透過 Twitter 告訴我,歡迎隨時與我聯絡!