終于迎來周末,此前的文章一直圍繞 2D、Canvas 和 SVG 展開。在 7 月份,我計(jì)劃輸出三篇萬字長文,系統(tǒng)地帶領(lǐng)大家學(xué)習(xí)可視化表達(dá)的三種方式:SVG、Canvas 和 WebGL。而這便是第一篇關(guān)于 3D 的文章。
讀完本篇文章,你將收獲以下內(nèi)容:對(duì) Three.js 框架有一個(gè)簡單理解并入門;學(xué)習(xí) Three.js 中的 Raycaster,主要通過鼠標(biāo)判斷當(dāng)前選擇的物體;以一個(gè)簡單實(shí)例,帶領(lǐng)大家用 Three.js 實(shí)現(xiàn)簡單的可視化地球案例。
一、3D 框架的選擇 ——Three.js
為何選擇 Three.js? 官網(wǎng)對(duì) Three.js 的介紹極為簡潔:“Javascript 3D library”。OpenGL 是一個(gè)跨平臺(tái)的 3D/2D 繪圖標(biāo)準(zhǔn),WebGL 則是 OpenGL 在瀏覽器上的實(shí)現(xiàn)。雖然 Web 前端開發(fā)人員可以直接使用 WebGL 接口進(jìn)行編程,但 WebGL 只是非?;A(chǔ)的繪圖 API,要求編程人員具備大量數(shù)學(xué)知識(shí)和繪圖知識(shí)才能完成 3D 編程任務(wù),且代碼量龐大。Three.js 對(duì) WebGL 進(jìn)行了封裝,使得前端開發(fā)人員即便不懂計(jì)算機(jī)圖形學(xué),只要理解了 Three.js 的一些基本概念,也能輕松進(jìn)行 Web 3D 開發(fā),降低了門檻,同時(shí)大大提升了效率。總結(jié)而言,不懂計(jì)算機(jī)圖形學(xué)也能借助 Three.js 進(jìn)行開發(fā)。
二、Three.js 的基本要素 —— 場(chǎng)景 定義如下:場(chǎng)景是一個(gè)三維空間,是所有物品的容器??梢园褕?chǎng)景想象成一個(gè)空房間,我們可以往里面放置要呈現(xiàn)的物體、相機(jī)、光源等。用代碼表示為:const scene = new THREE.Scene (); 可以將其想象成一個(gè)房間,能夠往里面添加各種物體,如正方體、矩形等。實(shí)際上,Three.js 中的各種元素之間的關(guān)系是一個(gè)樹形結(jié)構(gòu)。
三、Three.js 的基本要素 —— 相機(jī) 相機(jī):Three.js 必須往場(chǎng)景中添加一個(gè)相機(jī),相機(jī)用于確定位置、方向和角度,相機(jī)所看到的內(nèi)容就是我們最終在屏幕上看到的內(nèi)容。在程序運(yùn)行過程中,可以調(diào)整相機(jī)的位置、方向和角度。Three.js 中的相機(jī)分為兩種,即正交相機(jī)和透視相機(jī)。接下來為大家一一介紹,但在理解照相機(jī)之前,需要先理解一個(gè)概念 —— 視椎體。
透視相機(jī):視錐體是攝像機(jī)可見的空間,看上去像截掉頂部的金字塔。視錐體由六個(gè)裁剪面圍成,構(gòu)成視錐體的四個(gè)側(cè)面稱為上、下、左、右面,分別對(duì)應(yīng)屏幕的四個(gè)邊界。為了防止物體離攝像機(jī)過近,設(shè)置近切面;同時(shí)為了防止物體離攝像機(jī)太遠(yuǎn)而不可見,設(shè)置遠(yuǎn)切面。
《Three.js 關(guān)鍵要素詳解》 一、透視相機(jī) 視錐體是攝像機(jī)可見的空間,形似截掉頂部的金字塔。它由六個(gè)裁剪面圍成,其中四個(gè)側(cè)面稱為上、下、左、右面,分別對(duì)應(yīng)屏幕的四個(gè)邊界。為防止物體離攝像機(jī)過近,設(shè)置近切面;同時(shí)為避免物體離攝像機(jī)太遠(yuǎn)而不可見,設(shè)置遠(yuǎn)切面。
從圖中可以看出,由棱臺(tái)組成的六個(gè)面之內(nèi)的物體是可以被看到的。影響透視照相機(jī)大小的因素包括:攝像機(jī)視錐體垂直視野角度、攝像機(jī)視錐體近端面、攝像機(jī)視錐體遠(yuǎn)端面以及攝像機(jī)視錐體長寬比(表示輸出圖像的寬和高之比)。
在 Three.js 中對(duì)應(yīng)的照相機(jī)代碼為:const camera = new THREE.PerspectiveCamera (45, width /height, 1, 1000)。透視相機(jī)最大的特點(diǎn)是符合人眼觀察事物的特點(diǎn),即近大遠(yuǎn)小。其背后的實(shí)現(xiàn)原理是相機(jī)會(huì)有一個(gè)投影矩陣,該矩陣把視錐體轉(zhuǎn)換成一個(gè)正方體,使得遠(yuǎn)截面的點(diǎn)縮小,近距離的點(diǎn)放大。
二、正交相機(jī) 正交相機(jī)的特點(diǎn)是視錐體為一個(gè)立方體。在這種投影模式下,無論物體距離相機(jī)遠(yuǎn)近,在最終渲染的圖片中物體的大小都保持不變。這對(duì)于渲染 2D 場(chǎng)景或者 UI 元素非常有用。
在 Three.js 中的代碼為:const camera = new THREE.OrthographicCamera (width /-2, width / 2, height / 2, height /-2, 1, 1000)。
三、Three.js 的基本要素 —— 網(wǎng)格 在計(jì)算機(jī)世界中,一條弧線是由有限個(gè)點(diǎn)構(gòu)成的有限條線段連接得到的。當(dāng)線段數(shù)量越多,長度越短,達(dá)到無法察覺是線段時(shí),就出現(xiàn)了一條平滑的弧線。計(jì)算機(jī)的三維模型也類似,只不過線段變成了平面,普遍用三角形組成的網(wǎng)格來描述,這種模型稱之為 Mesh 模型。
Three.js 背后所有的圖形在進(jìn)行渲染之前,都會(huì)進(jìn)行三角化,然后交給 WebGL 去渲染。Three.js 提供了一些常見的幾何形狀,有三維的也有二維的,如長方體、球體、長方形、圓形等。如果默認(rèn)提供的形狀不能滿足需求,也可以自定義通過定義頂點(diǎn)和頂點(diǎn)之間的連線繪制自定義幾何形狀,更復(fù)雜的模型還可以用建模軟件建模后導(dǎo)入。
組成的 mesh 由兩個(gè)部分組成:材質(zhì)(Material)和幾何體(Geometry)。Three.js 提供了幾種有代表性的材質(zhì),常用的有漫反射、鏡面反射兩種材質(zhì),還可以引入外部圖片,貼到物體表面,成為紋理貼圖。
四、Three.js 的基本要素 —— 燈光 假如沒有光,攝像機(jī)看不到任何東西,因此需要往場(chǎng)景添加光源。為了更接近真實(shí)世界,Three.js 支持模擬不同光源,展現(xiàn)不同光照效果,有點(diǎn)光源、平行光、聚光燈、環(huán)境光等。
AmbientLight(環(huán)境光):環(huán)境光會(huì)均勻照亮場(chǎng)景中的所有物體,但不能用來投射陰影,因?yàn)樗鼪]有方向。例如:const light = new THREE.AmbientLight (0x404040); //soft white light。
平行光(DirectionalLight):平行光是沿著特定方向發(fā)射的光,表現(xiàn)像是無限遠(yuǎn),從它發(fā)出的光線都是平行的。常用來模擬太陽光的效果。例如:const directionalLight = new THREE.DirectionalLight (0xffffff, 0.5)。
點(diǎn)光源(PointLight):從一個(gè)點(diǎn)向各個(gè)方向發(fā)射的光源,常見例子是模擬燈泡發(fā)出的光。例如:const light = new THREE.PointLight (0xff0000, 1, 100)。
聚光燈(SpotLight):光線從一個(gè)點(diǎn)沿一個(gè)方向射出,隨著光線照射變遠(yuǎn),光線圓錐體的尺寸也逐漸增大。例如:const spotLight = new THREE.SpotLight (0xffffff)。還有一些其他的燈光,感興趣的小伙伴可以自行去 Three.js 官網(wǎng)查看。
更多詳情:
https://github.com/wzf1997/blog/issues/8