從 0 開始學習 Three.js : 場景搭建

飛天麵條發表於2018-03-20

什麼是三維視覺化頁面

我們常見的網頁,比如掘金、知乎、微博等都是平面的,只有長寬兩個維度。三維視覺化頁面增加了一個新的維度--深度,利用 HTML5 的 WebGL 介面,通過 JavaScript 程式設計, 在網頁中展示三維模型。

三維視覺化頁面的魅力

三維模型相比文字描述或者二維圖片,更加符合日常生活中人們觀察世界的感受,能給使用者提供浸入式的產品體驗。一些複雜的模型及資料,通過三維視覺化的手段,也能更加準確完整的傳遞所要表達的資訊。

一個精彩的 Demo:Solar-System-Motion-Simulator

什麼是 Three.js

Three.js 是一個 JavaScript 3D 庫,它將底層的 WebGL 進行了封裝。簡單呼叫 Three.js 的介面,就可以快速方便的構建三維視覺化頁面。

我相信你肯定聽說過 WebGL,也聽說過 canvas。如果沒有聽過這兩個名詞,可以去 MDN 簡單瞭解一下,不熟悉 WebGL 和 canvas 不會對學習 Three.js 產生任何阻礙。

同樣的,不瞭解圖形學的知識也不會阻礙你使用 Three.js 。

學習 Three.js 需要什麼知識

什麼都不需要。準確的說,只要你能看懂中文(因為本文是中文寫作的),還記得三角函式的知識(不記得你也可以查),會一點點 JavaScript(因為我也只會一點點 JavaScript)就夠了,不需要瞭解 Webpack、sass 、vue、react 等工具和框架的任何知識。

開始學習吧

我知道你已經迫不及待地想要敲上幾行程式碼,一覽 Three.js 的魅力了。但在這之前,我們先要弄明白兩個關鍵問題:

  • 三維場景有什麼
  • 如何將三維場景展示在二維平面中

從 0 開始學習 Three.js : 場景搭建

想像一下拍攝上圖時的樣子:我們先要找到一個拍攝的場地,另外還得有一臺相機。然後準備一些棋子、一個棋盤,把棋子和棋盤擺放在場地中,準備好燈光,拿起攝像機,調整好攝像機的位子和角度。按下快門。

三維視覺化網頁的建立和這個步驟完全重合。

let scene = new THREE.Scene();//準備拍攝的場地
let camera = new THREE.PerspectiveCamera(fov,aspectRatio,nearPlane,farPlane);//買了個相機
camera.position.set(x,y,z)//把照相機放到(x,y,z)處
camera.lookAt(new THREE.Vector3(0,0,0)//照相機看向座標(0,0,0)
let light = new THREE.PointLight( 0xff0000, 1, 100 );//Light 在有些時候並不是必須的。
let chessman = createChessman();//準備好棋子
chessman.position(a,b,c)//把棋子放到座標(x,y,z)處
let chessboard = createChessboard();//準備好棋盤
chessboard.position(e,d,f)//把棋子放到座標(e,d,f)處
scene.add(chessman);//把棋子放到空間中
scene.add(chessboard);//把棋盤放到空間中
let renderer = new THREE.WebGLRenderer();//一個渲染器,不要深究於此
renderer.render(scene,camera);//按下快門,咔嚓~拍照完成!
複製程式碼

上面的程式碼中肯定有許多你不明白的地方,不要擔心,現在只需要感性的認識到搭建一個 Three.js 場景和現實生活中照相的步驟是一樣的就可以了。

Three.js 的 hello world

學習程式設計的第一步都是 「Hello World」。Three.js 的 「Hello World」是在網頁中生成一個立方體。

從 0 開始學習 Three.js : 場景搭建
現在,開啟你的編輯器,一步一步跟著做吧。

承載場景的元素

<script src="three.js"><script>
<div id="container"></div>
複製程式碼

先引入 three.js 並在 HTML 中建立一個承載場景的元素#container

Three.js 下載到本地,或者使用 CDN (https://cdn.bootcss.com/three.js/90/three.js) 引入。

如果你熟悉 NPM 等工具的話,可以參考這個import-via-module

生成場景

let scene = new THREE.Scene();
複製程式碼

一行程式碼生成 Three.js 的場景。

生成照相機

Three.js 中的照相機有四種:CubeCamera、OrthographicCamera、PerspectiveCamera 和 StereoCamera。 其中常用的是 PerspectiveCamera 和 OrthographicCamera。

OrthographicCamera 是正交相機。

從 0 開始學習 Three.js : 場景搭建
正交相機拍攝的物體不會被縮放,平行線永遠保持平行。多用在物理建模等需要精確尺寸的模型中。

PerspectiveCamera 是投影相機。

從 0 開始學習 Three.js : 場景搭建
投影相機和人眼一樣有近大遠小的效果,平行線不一定平行。多用在模擬現實場景的模型中。(本文中的模型都會採用投影相機)。

關注一下 PerspectiveCamera 的四個引數:fov、aspect、near、far。

fov 是上圖中的 θ ,常用的數字是45 和 60。

aspect 是寬長比,多用#container的比例。

near 是離攝影機近的面到攝影機的距離。一般為1等很小的數字。

far 是離攝影機遠的面到攝影機的距離。一般設定為 1000、10000等較大的數字。

通過這4個引數,就可以確定一個四稜臺。在四稜臺內的物體會被渲染,而超出四稜臺範圍內的物體就被裁剪掉了。

let camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
複製程式碼

three.js 的座標系

在生成 camera 的程式碼中,你應該注意到 near 被設定為了1,far 被設定為了1000。這並不是一個錯誤,千萬不要寫成 1px,1000px。three.js 的座標系中表示的距離並不是真實的距離,而是一種比例關係,1和1000表示的是 far 比 near 距 camera 遠1000 倍。

three.js 的座標系符合右手定則。

從 0 開始學習 Three.js : 場景搭建
可以按照上圖去比一下試試。

我是看著電腦螢幕記住的:電腦螢幕向右是 x 正半軸,電腦螢幕向上是 y 正半軸,垂直螢幕向外是 z 正半軸。

還有一點要記住的是,新生成的任何物體,預設初始位置都是幾何中心位於(0,0,0)。camera 預設看向 z 軸負半軸。

camera.position.set(0, 0, 10);
複製程式碼

把 camera 往 x 軸正半軸挪一點。不然 camera 預設在(0,0,0),看向 z 軸負半軸。是拍不到位於 (0,0,0) 的物體的。

先搞個渲染器

渲染器這一塊比較複雜,還好 three.js 做了十分徹底的封裝。我們只需要用就 ok 了。在 Three.js 中,你只會用到 WebGLRenderer

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
複製程式碼

把 renderer 的大小設定為與 scene 一致是一個不錯的選擇。 如果你在 MDN 查了 WebGL 相關的資料的話,一定知道需要在<canvas>元素中使用 WebGL。

可以藉由 Three.js 在 DOM 中引入<canvas>,

document.getElementById('container').appendChild(renderer.domElement);
複製程式碼

也可以顯式的在 HTML 頁面插入<canvas> 我比較喜歡前一種,簡單一些。

準備就緒,開始產生立方體

如果前面的步驟都沒問題了,生成一個立方體就是一瞬間的事情。

let cubeGeometry = new THREE.BoxGeometry(1,1,1);
let cubeMaterial = new THREE.MeshBasicMaterial({
    color:0xff0000;
});
let cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
scene.add(cube);
renderer.render(scene,camera);
複製程式碼

super fast !!!

注意 .BoxGeometry,你可能會在較老的資料上看到是 .CubeGeometry,那是很久以前的事情了。現在生成長方體/立方體用 .BoxGeometry

在 Three.js 中生成一個物體只需要三步:

  1. 設定物體的形狀
  2. 設定物體的材質
  3. 把形狀和材質結合起來

最後要把生成的物體通過 scene的add()方法新增到 scene 中。renderer 直接渲染 scene 和 camera 就 OK 了。

至於什麼是形狀,什麼是材質,如何把形狀和材質結合起來,又是很長一部分內容。我會放在其它部分詳細講解。


一些可能遇到的問題

1.頁面沒有效果。檢查瀏覽器是否支援 WebGL

在 JS 檔案中引入

if (Detector.webgl) {
    // Initiate function or other initializations here
    animate();
} else {
    var warning = Detector.getWebGLErrorMessage();
    document.getElementById('container').appendChild(warning);
}
複製程式碼

2.頁面沒有效果。檢查瀏覽器console 是否報錯。

3.頁面沒有效果。檢查 Three.js 資源是否成功引用。

相關文章