一、webgl與three.js
我們知道canvas、svg等是2D繪圖的,那么如果想要使用js進行3D繪圖,可以嗎? 答案是肯定的!實際上主流的3D開發使用的是c++,但是隨着技術的發展,JavaScript目前已經是無孔不入了,包括web(vue/react)、移動端(RN/weex)、客戶端(electron/nw)、后端(nw)、人工智能(tensorflow.js),而three.js就是使用JavaScript進行3d繪圖的框架了,而three.js是對webgl進行封裝的,所以,實際上webgl是3D繪圖的基礎,但我們使用three.js開發會更加高效。遺憾的是,目前僅有部分主流瀏覽器支持webgl,但還是值得我們探索和在合適的場景下使用的。而three.js也是非常容易從字面理解的,three就是3d,js就是JavaScript,所以three.js就是使用JavaScript進行3d開發。
在github上可以找到three.js,可以看到,three.js目前star數已經達到了4萬之多,足以說明其流行程度。 下面是three.js的github目錄:
可以看到,three.js更新非常頻繁,這里主要介紹一下各個目錄。 build目錄是生成的我們直接引用的three.js和three.min.js文件;docs目錄中羅列了three.js相關文檔;editor目錄是一些簡單編輯程序;example目錄是three.js實現的一些例子; src目錄是該項目的源代碼;test目錄是項目的測試代碼;utils目錄存放一些腳本。
二、如何使用
使用非常簡單,首先我們進入build目錄中的three.min.js,然后點擊raw按鈕,就可以得到一個url(https://raw.githubusercontent.com/mrdoob/three.js/dev/build/three.min.js),最后我們在html文件中引入這個js文件即可,注意:github鏈接較慢,我們可以復制js代碼到本地,然后引入,如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>three.js</title> <script src="./three.js"></script> </head> <body> </body> </html>
接着,我們在chrome瀏覽器中打開F12,在console控制台中輸入THREE,然后回車,可以得到下面的結果:
即THREE是three.js暴露出來的一個對象,其中有很多屬性和方法可以調用。
三、核心概念
在three.js中,核心的便是場景(scene)、相機(camera)、渲染器(renderer),有了這三者,才能使用相機將場景渲染到網頁上去。
(1)場景
描述3D使用的就是場景,使用THREE.Scene()構造,注意,THREE是對象,而Scene是構造函數,所以首字母都是大寫的。
(2)相機
相機就像我們的眼睛,從不同的角度看,那么看到的場景也就不一樣。另外,場景是一樣的,而相機有多種拍照方式,所以,需要我們根據需要調整。而最常用的就是透視相機,即THREE.PerspectiveCamera(),同樣的,THREE是對象,PerspectiveCamera是構造函數,首字母大寫,且是駝峰式命名方法。
(3)渲染器
即在網頁上顯示什么元素,都是需要渲染出來的,使用THREE.WebGLRenderer,且在使用過程中,需要使用domElement掛載到頁面上,后面的例子會講解。
而對於這三者,我們可以認為場景是一個容器,可以將一些物體如cube放在這個容器中;而相機的作用就是對這個選擇合適的角度容器拍攝得到一張照片;渲染器的作用是把相機拍到的照片放到瀏覽器中顯示,如下所示:
四、實例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>three.js</title> <style> * { margin: 0; padding: 0; } </style> <script src="./three.js"></script> </head> <body> <script> var scene = new THREE.Scene(); var axes = new THREE.AxesHelper(100); scene.add(axes); var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000); camera.position.x = 100; camera.position.y = 100; camera.position.z = 100; camera.lookAt(scene.position); var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(0x111111); renderer.setSize(window.innerWidth, window.innerHeight); var geometry = new THREE.CubeGeometry(10, 10, 10); var material = new THREE.MeshBasicMaterial({color: 0xff0000}); var cube = new THREE.Mesh(geometry, material); cube.position.x = 0; cube.position.y = 0; cube.position.z = 0; scene.add(cube); document.body.append(renderer.domElement); renderer.render(scene, camera); </script> </body> </html>
- 創立一個Scene(場景),這個場景是three.js所依賴的基礎,是需要首先創立。
- 有了場景 ,我們就可以創建一個AxesHelper(坐標軸),然后add到場景中。
- 接着創建一個PerspectiveCamera(相機),並且指定相機的位置。
- 有了場景、坐標軸、相機之后,就可以創建3D物體了,而3D物體的是由Geometry(幾何圖形)和Material(材料)組成,然后添加物體到指定的位置,最后添加到場景中。
- 最后,我們需要將DOM與3D結合起來,然后進行渲染即可。
於是,我們可以看到,使用three.js還是很簡單的,就是場景、坐標軸、相機、渲染引擎、事物、掛載。最后結果如下:
如上所示是靜態的,如果需要時動態的,就需要用到渲染循環了,主要用到的函數是requestAnimationFrame,如下,僅僅替換了極少的代碼:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>three.js</title> <style> * { margin: 0; padding: 0; } </style> <script src="./three.js"></script> </head> <body> <script> var scene = new THREE.Scene(); var axes = new THREE.AxesHelper(100); scene.add(axes); var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000); camera.position.x = 100; camera.position.y = 100; camera.position.z = 100; camera.lookAt(scene.position); var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(0x111111); renderer.setSize(window.innerWidth, window.innerHeight); var geometry = new THREE.CubeGeometry(10, 10, 10); var material = new THREE.MeshBasicMaterial({color: 0xff0000}); var cube = new THREE.Mesh(geometry, material); cube.position.x = 0; cube.position.y = 0; cube.position.z = 0; requestAnimationFrame(function () { cube.position.x++; }); scene.add(cube); document.body.append(renderer.domElement); function render() { cube.rotation.x += 0.1; cube.rotation.y += 0.1; renderer.render(scene, camera); requestAnimationFrame(render); } render(); </script> </body> </html>
如下所示,通過requestAnimationFrame在配合cude的rotation屬性使用,就可以讓這個cube旋轉起來了。
另外,對於相機的設置,我們還可以設置up屬性,即camera.up.x = 0; camera.up.y = 0; camera.up.z = 0;即camera的position屬性可以確定相機位置,lookAt可以確定看的方向,但是相機拍攝是我們這樣豎着拍攝還是橫着拍攝呢,這就取決於你設置camera的上方了,使用camera.up屬性來設置。