在學(xué)習(xí) Three.js 之前,感性的了解一些基礎(chǔ)的 3D 知識后,后面的學(xué)習(xí)就不會那么糾結(jié)了.
3D 場景前置知識
- 場景(Scene): 場景是[物體,光源等元素]的容器.可以配合
chorme插件使用,拋出window.scene對象,即可實(shí)時(shí)調(diào)整和場景相關(guān)的所有對象數(shù)據(jù),包括物體,光源等. - 相機(jī)(Camera): 場景中的相機(jī),代替人眼去觀察.一個(gè)場景中有且只能有一個(gè)相機(jī),一般常用的是透視相機(jī)(perspectiveCamera),遵循真實(shí)的物理場景法則 -- 遠(yuǎn)小近大. 還有一個(gè)叫正交相機(jī)(一般 2D 平面場景游戲使用的比較多,物體的大小和遠(yuǎn)近無關(guān))
- 物體對象(Mesh): 包括二維物體(點(diǎn),線,面),三維物體和模型等.
- 光源(Light): 場景中的光源,如果場景中不添加光源,那么整個(gè)世界(Scene)將會一片黑暗. 常見的光源包括: 全局光,平行光,點(diǎn)光源(蠟燭).每種光源的表現(xiàn)形式都是不一樣的(聯(lián)想實(shí)際生活場景).
- 渲染器(renderer): 場景渲染器. 在基于瀏覽器的 Three.js 開發(fā)模式中,這里就是指的 WebGL ---> Canvas
- 控制器(Control): 通過鍵盤,鼠標(biāo)等,可以控制相機(jī)的位置,視角等.
下面針對上述的各個(gè)點(diǎn),一個(gè)一個(gè)的來解釋.
場景 (Scene)
場景應(yīng)該很好理解.
我們生活的地球就是一個(gè)場景,場景里有物體(大海,高山,河流,你,我),有光源(太陽光,路燈,手電筒),有攝像機(jī)(你的眼鏡,路邊的監(jiān)控?cái)z像頭)
場景中包含了
- 物體
- 光源
在 Three.js 中,由于我們需要渲染到 HTML 上. 所以這里還多了一個(gè)在現(xiàn)實(shí)中很難聯(lián)想的: 渲染器 renderer
相機(jī) (Camera)
有場景了,瞎子是無法看見的.你需要一雙可以觀察場景的眼鏡.
在 Three.js 中, Camera 相機(jī),就是充當(dāng)眼鏡的角色.
不同于真是世界,每個(gè)人都有一雙眼鏡,可以有無數(shù)個(gè)視角范圍. 但是針對某一個(gè)人來說,它的視角同時(shí)只能有一個(gè).
在 Three.js 中,一個(gè)場景中,有且只能有一個(gè)相機(jī).
在 Three.js 中,我們常用的相機(jī)類型有兩種:
- 正交相機(jī)(orthographic)
- 透視相機(jī)(perspective)
一般情況下,模擬人眼觀察的世界(3D),都是使用透視相機(jī)(perspective) , 它滿足真實(shí)世界里的遠(yuǎn)小近大的規(guī)則. 透視相機(jī)一般用戶渲染 3D 場景
而正交相機(jī)的特點(diǎn)是: 物體渲染的尺寸大小和和觀察它相機(jī)的遠(yuǎn)近無關(guān).也就是說,在場景中移動一個(gè)物體,其大小不會隨著鏡頭的變化而變化. 正交相機(jī)一般用于渲染 2D 場景
關(guān)于透視相機(jī) API 的大致了解
Three.PerspectiveCamera(fov,aspect,near,far)
參數(shù)描述:
-
fov: 可是范圍的角度,也就是視野角度.玩過 fps 游戲的玩家應(yīng)該都能理解這個(gè)參數(shù). 它是一個(gè)度數(shù)的單位. 一般取值范圍在 60 - 90(默認(rèn)60) , 角度越大,你看的范圍也就越寬. -
aspcet: 渲染區(qū)域的縱橫比,也可以理解為相機(jī)的照射范圍的縱橫比. 一般取值為window.innerWidth/window.innerHeight -
near: 最近鏡頭距離(比這個(gè)還近,相機(jī)就照不到 ---> 一般情況下,你看不到你的嘴巴) -
far: 最遠(yuǎn)鏡頭距離(比這個(gè)還遠(yuǎn),相機(jī)就照不到 ---> 一般霧霾天氣下,你看不遠(yuǎn))
參數(shù)的示意圖如下:

創(chuàng)建攝像機(jī)之后,還要對齊進(jìn)行定位(人眼在哪?),以及設(shè)置觀察的角度或者說是方位(往哪看?).
// 偽代碼
camera.position = new THREE.Vector3(x,y,z) // 相機(jī)在哪
camera.lookAt = new THREE.Vector3(x, y, z) // 往哪看.
燈光 (Light)
如果你呆在過絕對黑暗的地方,你就會發(fā)現(xiàn),沒有光源的環(huán)境,絕對是一片漆黑.伸手不見五指.
對于 THREE.js 的世界也是如此.
如果不設(shè)置光源,你將無法看見你之前設(shè)置的任何場景,物體.(有時(shí)候,為什么在瀏覽器里啥都看不見,可以自檢一下,是否是沒有設(shè)置光源,或者光源的顏色就是黑色)
在 THREE.js 中,光源是必須的.如果不設(shè)置光源,瀏覽器的表現(xiàn)形式就是一片漆黑.什么也看不見.
THREE.js 中內(nèi)置的大量的類型. 可以先聯(lián)想真實(shí)世界,感性的理解一下.
-
AmbientLight: 環(huán)境光. 其顏色會均勻的應(yīng)用到場景及其所有對象上.這種光源在游戲開發(fā)的引擎界里成為為環(huán)境光. 這種光沒有特定的方向,不會產(chǎn)生陰影. 通常不會把 AmbientLight 作為場景里的唯一光源. 而是和SpotLight,DirectionalLight等光源一起結(jié)合起來使用,從而達(dá)到柔化陰影,增加真是感的效果. 指定壞境光源時(shí)要相對保守,例如0x0c0c0c. 設(shè)置太亮或者太暗會導(dǎo)致頁面顯示效果不佳. -
PointLight: 3D 空間中的一個(gè)點(diǎn)光源,向所有方向發(fā)射出光線(蠟燭) -
SpotLight: 產(chǎn)生圓錐形光柱的聚光燈. 臺燈,天花板射燈,游戲里的場景燈都是屬于這種光源.. 特別是在你需要使用到陰影的時(shí)候. -
DirectionalLight: 也就是無限光,光線是平行的. 典型的例子就是日光燈.用于模擬遙遠(yuǎn)的,類似于太陽那樣的光源. 該光遠(yuǎn)和SpotLight的最大區(qū)別在于,無限光(太陽),不會隨著距離的變大而變暗. -
HemisphereLight: 特殊光源. 用于創(chuàng)建戶外自然光的效果. 此光源模擬物體表面的反光效果. -
AreaLight: 面光源. 指定一個(gè)發(fā)光的區(qū)域. -
LensFlare: 不是光源, 用于給光源添加鏡頭光暈效果.
Mesh
在 THREE.js 中, Mesh 表示物體.
和真實(shí)世界一樣, 物體是由幾何結(jié)構(gòu)(非標(biāo)準(zhǔn)圓形)和表面材質(zhì)(一看就知道是??)組成.
在計(jì)算機(jī)的2D世界里,一條弧線是有限個(gè)點(diǎn)構(gòu)成有限個(gè)線段連接組成的. 當(dāng)線段的數(shù)量足夠多時(shí),每一條線段的長度就會越短,短的像一個(gè)點(diǎn),與此同時(shí),你等到的弧線就會越完美.
計(jì)算機(jī)的 3D 模型世界也是類似. 只不過線段變成了平面,普遍用很多三角型平面拼接而成的網(wǎng)格模型,我們稱之為 Mesh.
在 THREE.js 的世界中. 材質(zhì) (Material) + 幾何體 (Geometry) = Mesh(物體)
Geometry 類似于物體的骨架.
Material 類似于物體的皮膚.
材質(zhì)的分類

2D 圖形

3D 圖形

加載外部模型
(對 3D 不熟,對幾何體不熟)絕大多數(shù)情況下,我們都是使用設(shè)計(jì)師個(gè)我們提供好的 3D 模型文件,讓 three.js 來直接加載.(比如某個(gè)工廠的廠區(qū)的 3D 模型文件)
我們可以根據(jù)設(shè)計(jì)師提供的 3D 文件格式,來選擇對應(yīng)的 loader , 將外部模型加載進(jìn)來.
加載外部模型是通過 three.js 的加載器(loader) 來實(shí)現(xiàn)的.
加載器把文本/二進(jìn)制數(shù)據(jù)文件轉(zhuǎn)換為 three.js 對象結(jié)構(gòu).
由于 3D 文件格式有很多, three.js 也提供的對應(yīng)的 loader 來處理這些差異化的模型文件. 我們要做的僅僅是使用正確的 loader 加載正確的模型文件即可
3D 文件格式和 loader 對應(yīng)關(guān)系如下:

粒子
THREE.Sprite
在WebGlRenderer渲染器中使用THREE.Sprite創(chuàng)建的粒子可以直接添加到scene中。創(chuàng)建出來的精靈總是面向鏡頭的。即不會有傾斜變形之類透視變化,只有近大遠(yuǎn)小的變
化。
場景交互
Three.js中并沒有直接提供“點(diǎn)擊”功能,一開始使用的時(shí)候我也覺得一臉懵逼,后來才發(fā)現(xiàn)我們可以基于THREE.Raycaster來判斷鼠標(biāo)當(dāng)前對應(yīng)到哪個(gè)物體,用來進(jìn)行碰撞檢測.