點擊查看官方文檔javascript
下面是翻譯的內容(稍做修改)html
先了解一下Three.js應用程序的結構。Three.js應用程序須要建立一堆對象並將它們鏈接在一塊兒。下圖表示一個小three.js應用程序的圖。
java
關於上圖的注意事項canvas
Renderer 渲染器,將一個場景和一個攝像機傳遞給渲染器,它就會將攝像機截錐內的3D場景部分做爲2D圖像呈現給畫布。數組
有一個樹狀結構的場景圖,其中包括各類物體,如Scene對象,多個 Mesh對象,Light對象,Group,Object3D,和Camera對象。一個Scene對象定義了場景圖的根,而且包含諸如背景色和霧化度之類的屬性。這些對象定義了分層的父/子樹狀結構,並表示對象出如今何處,以及如何定向。瀏覽器
注意,上圖中的Camera相機,佔場景圖中的一半。這是爲了表示在three.js中,與其餘對象不一樣。攝像機沒必要在場景圖中才能正常工做。與其餘對象同樣,Camera 做爲其餘對象的子對象,將相對於其父對象移動和定向。less
Mesh 網格對象,表示用特定的材質繪製特定的幾何圖形。Material對象和Geometry對象均可以被多個網格對象使用。例如,要在不一樣的位置繪製2個藍色立方體,咱們可能須要2個網格對象來表示每一個立方體的位置和方向。咱們只須要一個Geometry來保存一個立方體的頂點數據,一個Material來指定藍色。兩個網格對象能夠引用相同的Geometry對象和相同的Material對象函數
Geometry 幾何對象,表示某些幾何形狀的頂點數據,例如球體,立方體,平面,狗,貓,人,樹,建築物等。Three.js提供了許多內置的幾何圖元。同時也能夠建立自定義幾何圖形以及,或者從文件加載幾何圖形(如***.obj文件)。動畫
Material 表面材質對象,標識繪製幾何圖形的表面屬性,包括要使用的顏色及其光澤程度等。1個Material還能夠引用一個或多個Texture對象,這些對象能夠用於例如將圖像包裝到幾何圖形的表面上。ui
Texture 紋理對象,一般表示從圖像文件加載,從畫布生成或從另外一個場景渲染的圖像。
Light 燈光對象,表明不一樣類型的燈光。
下面製做一個最小的「Cube」場景,以下所示
<script type="module"> // 1.直接使用線上資源 import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js'; // 2.直接使用本地 three.js import *as THREE from "./three.js/build/three.js" // 3.使用本地 three.module.js // 本地啓服務(http-server等), import 才能訪問本地 three.module.js import *as THREE from "./three.js/build/three.module.js" </script>
script標籤中 type="module" 很重要。這使咱們可以使用import關鍵字來加載three.js。還有其餘方法能夠加載three.js,可是從r106版本開始,建議使用模塊。模塊的優勢是能夠輕鬆導入所需的其餘模塊。這使咱們沒必要手動加載它們依賴的額外腳本。
<body> <canvas id="c"></canvas> </body>
< script type = "module" > import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js'; function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({ canvas }); ... } main(); </script>
在查找畫布以後,咱們建立了一個WebGLRenderer。渲染器負責獲取你提供的全部數據並將其呈現到畫布上。過去有其餘渲染器,好比CSSRenderer, CanvasRenderer,未來可能會有WebGL2Renderer或WebGPURenderer。目前使用WebGLRenderer使用WebGL渲染3D到畫布。
注意這裏有一些注意的細節。若是你沒有傳遞一個畫布到three.js,它會爲你建立一個,但你必須把它添加到你的文檔。在哪裏添加它取決於你的用例,你必須改變你的代碼,因此咱們發現傳遞一個畫布給three.js感受更靈活。
我能夠將畫布放在任何地方,代碼會找到它,就好像我有代碼能夠將畫布插入到文檔中,若是個人用例發生變化,我可能須要更改代碼。
接下來,咱們須要一臺照相機。下面代碼將建立一個PerspectiveCamera(透視相機)。
const fov = 75; // 視場角 const aspect = 2; // canvas 默認的寬高比例 默認 300/150 = 2 const near = 0.1; const far = 5; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
fov 是 field of view 的縮寫,表示視場角。在這種狀況下,垂直尺寸爲75度。注意,Three.js中的大多數角度都以 弧度 表示,但因爲某些緣由,透視相機取 度。下圖(網上截的圖)中的ω,就表示視場角。
aspect 是畫布的顯示方面。咱們將在另外一篇文章中詳細介紹 ,但默認狀況下,畫布尺寸爲300x150像素,因此寬高比爲300/150=2。
near 和 far 表示將要渲染在相機前面的空間範圍。該範圍以前或以後的任何內容都會被裁剪(不繪製)。
fov、aspect、near、far四個值,定義了一個「視錐」。視錐是3d形狀的名稱,它的形狀像一個金字塔,頂端被切掉。換句話說,將「視錐」這個詞視爲另外一種3D形狀,例如球體,立方體,棱鏡,視錐。
近平面和遠平面的高度由視場肯定。兩個平面的寬度由視場和外觀肯定。
定義的視錐內部的全部內容都將被繪製。視錐外面的都不繪製。
相機默認是向下看-Z軸,向上看+Y軸。咱們把立方體放在原點,因此咱們須要把攝像機從原點日後移一點,這樣才能看到任何東西。
camera.position.z = 2;
在上圖中,咱們能夠看到咱們的攝像機在z = 2處。它沿着-Z軸向下看。咱們的截錐從攝像機前面0.1個單位開始,到攝像機前面5個單位。由於在這個圖中,咱們是向下看的,視野是受角度影響的。咱們的畫布的寬度是它的高度的兩倍,因此整個視野將比咱們指定的75度的垂直視野寬得多。
接下來建立一個scene。three.js中的一個場景,能夠當作是一種場景圖形式的根。任何你想要讓three.js繪製的東西,都須要添加到場景中。
const scene = new THREE.Scene();
接下來,咱們建立一個包含盒子數據的BoxGeometry。
幾乎任何咱們想要在Three.js中顯示的東西,都須要定義構成3D對象的頂點的幾何圖形。
const boxWidth = 1; const boxHeight = 1; const boxDepth = 1; const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
而後咱們建立一個基本材質並設置它的顏色。顏色可使用標準的CSS樣式6位十六進制顏色值來指定。
const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 })
而後建立一個網格。在three.js中,網格表明了一個幾何體(物體的形狀)和一個材質(如何繪製物體,閃亮的仍是平坦的,什麼顏色,應用什麼紋理)的組合等。以及該對象在場景中的位置、方向和比例。
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
而後,咱們能夠經過調用渲染器的render函數,並將場景和攝像機傳遞給它,來渲染場景
renderer.render(scene, camera);
沿着-Z軸觀察的而立方體自己是與軸對齊的,因此咱們只能看到一個面。用動畫讓它旋轉,就能夠看清3D繪製的效果。
使用瀏覽器的window.requestAnimationFrame進行渲染。
function render(time) { time *= 0.001; // 轉化一下時間 cube.rotation.x = time; // 繞x軸旋轉網格 cube.rotation.y = time; // 繞y軸旋轉網格 renderer.render(scene, camera); // renderer渲染 requestAnimationFrame(render); } requestAnimationFrame(render);
雖然好了一點,但仍是很難看到3d效果。添加一些照明會有幫助,因此讓咱們添加一盞燈。three.js中有許多種類的light
const color = 0xFFFFFF; // 光的顏色 const intensity = 1; // 光照強度 const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); // 燈的位置 scene.add(light);
定向燈有一個位置和一個目標。二者都默認爲0, 0, 0。在本例中,咱們將燈光的位置設置爲-1, 2, 4,這樣它的位置好,就稍微在相機的左邊、上面和後面一些。定向燈的目標座標仍然是(0, 0, 0),因此它會照向原點。
咱們還須要換Materail。基本的Material不受光線的影響。讓咱們把它改爲MeshPhongMaterial,它會受到光線的影響。
它如今應該是比較清晰的3D視圖了。爲了好玩,咱們再加兩個方塊。咱們讓每一個立方體使用相同的幾何圖形,但製做不一樣的材質,所以每一個立方體能夠是不一樣的顏色。
首先,將建立一個函數,用指定的顏色建立一個新的Material,而後加上指定的Geometry,建立一個Mesh,並將其添加到場景中,並設置其在x軸上的位置。
function makeInstance(geometry, color, x) { const material = new THREE.MeshPhongMaterial({ color }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); cube.position.x = x; return cube; }
而後咱們將使用三種不一樣的顏色和X軸位置調用三次函數, 將生成的Mesh實例存在一個數組中。
const cubes = [ makeInstance(geometry, 0x44aa88, 0), makeInstance(geometry, 0x8844aa, -2), makeInstance(geometry, 0xaa8844, 2), ];
最後在渲染函數中,旋轉三個立方體。給每一個立方體設置了稍微不一樣的旋轉角度。
function render(time) { time *= 0.001; cubes.forEach((cube, ndx) => { const speed = 1 + ndx * .1; const rot = time * speed; cube.rotation.x = rot; cube.rotation.y = rot; }); ... }
<canvas id="c"></canvas>
<script type="module"> import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js'; function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({ canvas }); const scene = new THREE.Scene(); { const fov = 75; const aspect = 2; const near = 0.1; const far = 5; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.z = 2; } { const color = 0xFFFFFF; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); } scene.add(light); { const boxWidth = 1; const boxHeight = 1; const boxDepth = 1; const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth); } function makeInstance(geometry, color, x) { const material = new THREE.MeshPhongMaterial({ color }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); cube.position.x = x; return cube; } const cubes = [ makeInstance(geometry, 0x44aa88, 0), makeInstance(geometry, 0x8844aa, -2), makeInstance(geometry, 0xaa8844, 2), ]; function render(time) { time *= 0.001; cubes.forEach((cube, ndx) => { const speed = 1 + ndx * .1; const rot = time * speed; cube.rotation.x = rot; cube.rotation.y = rot; }); renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); } main(); </script>