WebGL&Three.js工做原理

1、咱們講什麼?

咱們講兩個東西:
一、WebGL背後的工做原理是什麼?
二、以Three.js爲例,講述框架在背後扮演什麼樣的角色?javascript

 

2、咱們爲何要了解原理?

咱們假定你對WebGL已經有必定了解,或者用Three.js作過了一些東西,這個時候,你可能碰到了這樣一些問題:
一、不少東西仍是作不出來,甚至沒有任何思路;
二、碰到bug沒法解決,甚至沒有方向;
三、性能出現問題,徹底不知道如何去優化。
這個時候,咱們須要瞭解更多。java

 

3、先了解一個基礎概念 

一、什麼是矩陣?
簡單說來,矩陣用於座標變換,以下圖:
web


二、那它具體是怎麼變換的呢,以下圖:
編程


三、舉個實例,將座標平移2,以下圖:
瀏覽器

 

若是這時候,你仍是沒有理解,沒有關係,你只須要知道,矩陣用於座標變換。緩存

 

4、WebGL的工做原理

4.一、WebGL API

在瞭解一門新技術前,咱們都會先看看它的開發文檔或者API。
查看Canvas的繪圖API,咱們會發現它能畫直線、矩形、圓、弧線、貝塞爾曲線。
因而,咱們看了看WebGL繪圖API,發現:
框架

它只能會點、線、三角形?必定是我看錯了。
沒有,你沒看錯。
性能

就算是這樣一個複雜的模型,也是一個個三角形畫出來的。優化

 

4.二、WebGL繪製流程

簡單說來,WebGL繪製過程包括如下三步:
一、獲取頂點座標
二、圖元裝配(即畫出一個個三角形)
三、光柵化(生成片元,即一個個像素點)


接下來,咱們分步講解每一個步驟。spa

 

4.2.一、獲取頂點座標

頂點座標從何而來呢?一個立方體還好說,若是是一個機器人呢?
沒錯,咱們不會一個一個寫這些座標。
每每它來自三維軟件導出,或者是框架生成,以下圖:

寫入緩存區是啥?
沒錯,爲了簡化流程,以前我沒有介紹。
因爲頂點數據每每成千上萬,在獲取到頂點座標後,咱們一般會將它存儲在顯存,即緩存區內,方便GPU更快讀取。

 

4.2.二、圖元裝配

咱們已經知道,圖元裝配就是由頂點生成一個個圖元(即三角形)。那這個過程是自動完成的嗎?答案是並不是徹底如此。
爲了使咱們有更高的可控性,即自由控制頂點位置,WebGL把這個權力交給了咱們,這就是可編程渲染管線(不用理解)。
WebGL須要咱們先處理頂點,那怎麼處理呢?咱們先看下圖:

咱們引入了一個新的名詞,叫「頂點着色器」,它由opengl es編寫,由javascript以字符串的形式定義並傳遞給GPU生成。
好比以下就是一段頂點着色器代碼:

1
2
3
4
attribute vec4 position;
void  main() {
   gl_Position = position; 
}

attribute修飾符用於聲明由瀏覽器(javascript)傳輸給頂點着色器的變量值;
position即咱們定義的頂點座標;
gl_Position是一個內建的傳出變量。
這段代碼什麼也沒作,若是是繪製2d圖形,沒問題,但若是是繪製3d圖形,即傳入的頂點座標是一個三維座標,咱們則須要轉換成屏幕座標。
好比:v(-0.5, 0.0, 1.0)轉換爲p(0.2, -0.4),這個過程相似咱們用相機拍照。

 

4.2.2.一、頂點着色器處理流程


回到剛纔的話題,頂點着色器是如何處理頂點座標的呢?

如上圖,頂點着色器會先將座標轉換完畢,而後由GPU進行圖元裝配,有多少頂點,這段頂點着色器程序就運行了多少次。
你可能留意到,這時候頂點着色器變爲:

1
2
3
4
5
attribute vec4 position;
uniform mat4 matrix;
void  main() {
   gl_Position = position * matrix; 
}

這就是應用了矩陣matrix,將三維世界座標轉換成屏幕座標,這個矩陣叫投影矩陣,由javascript傳入,至於這個matrix怎麼生成,咱們暫且不討論。

 

4.2.三、光柵化

和圖元裝配相似,光柵化也是可控的。

在圖元生成完畢以後,咱們須要給模型「上色」,而完成這部分工做的,則是運行在GPU的「片元着色器」來完成。
它一樣是一段opengl es程序,模型看起來是什麼質地(顏色、漫反射貼圖等)、燈光等由片元着色器來計算。
以下是一段簡單的片元着色器代碼:

1
2
3
4
precision mediump  float
void  main( void ) {
     gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

gl_FragColor即輸出的顏色值。

 

4.2.3.一、片元着色器處理流程

片元着色器具體是如何控制顏色生成的呢?

如上圖,頂點着色器是有多少頂點,運行了多少次,而片元着色器則是,生成多少片元(像素),運行多少次。

 

4.三、WebGL的完整工做流程

至此,實質上,WebGL經歷了以下處理流程:
一、準備數據階段
在這個階段,咱們須要提供頂點座標、索引(三角形繪製順序)、uv(決定貼圖座標)、法線(決定光照效果),以及各類矩陣(好比投影矩陣)。
其中頂點數據存儲在緩存區(由於數量巨大),以修飾符attribute傳遞給頂點着色器;
矩陣則以修飾符uniform傳遞給頂點着色器。
二、生成頂點着色器
根據咱們須要,由Javascript定義一段頂點着色器(opengl es)程序的字符串,生成而且編譯成一段着色器程序傳遞給GPU。
三、圖元裝配
GPU根據頂點數量,挨個執行頂點着色器程序,生成頂點最終的座標,完成座標轉換。
四、生成片元着色器
模型是什麼顏色,看起來是什麼質地,光照效果,陰影(流程較複雜,須要先渲染到紋理,能夠先不關注),都在這個階段處理。
五、光柵化
能過片元着色器,咱們肯定好了每一個片元的顏色,以及根據深度緩存區判斷哪些片元被擋住了,不須要渲染,最終將片元信息存儲到顏色緩存區,最終完成整個渲染。


 

5、Three.js究竟作了什麼?

咱們知道,three.js幫咱們完成了不少事情,可是它具體作了什麼呢,他在整個流程中,扮演了什麼角色呢?
咱們先簡單看一下,three.js參與的流程:

 


黃色和綠色部分,都是three.js參與的部分,其中黃色是javascript部分,綠色是opengl es部分。
咱們發現,能作的,three.js基本上都幫咱們作了。

  • 輔助咱們導出了模型數據;
  • 自動生成了各類矩陣;
  • 生成了頂點着色器;
  • 輔助咱們生成材質,配置燈光;
  • 根據咱們設置的材質生成了片元着色器。

並且將webGL基於光柵化的2D API,封裝成了咱們人類能看懂的 3D API。

 

5.一、Three.js頂點處理流程

從WebGL工做原理的章節中,咱們已經知道了頂點着色器會將三維世界座標轉換成屏幕座標,但實際上,座標轉換不限於投影矩陣。
以下圖:

以前WebGL在圖元裝配以後的結果,因爲咱們認爲模型是固定在座標原點,而且相機在x軸和y軸座標都是0,其實正常的結果是這樣的:

 

5.1.一、模型矩陣

如今,咱們將模型順時針旋轉Math.PI/6,全部頂點位置確定都變化了。

1
box.rotation.y = Math.PI/6;

可是,若是咱們直接將頂點位置用javascript計算出來,那性能會很低(頂點一般成千上萬),並且,這些數據也很是不利於維護。
因此,咱們用矩陣modelMatrix將這個旋轉信息記錄下來。

 

5.1.二、視圖矩陣

而後,咱們將相機往上偏移30。

1
camera.position.y = 30;

同理,咱們用矩陣viewMatrix將移動信息記錄下來。

 

5.1.三、投影矩陣

這是咱們以前介紹過的了,咱們用projectMatrix記錄。

 

5.1.四、應用矩陣

而後,咱們編寫頂點着色器:

1
gl_Position = position * modelMatrix * viewMatrix * projectionMatrix;

這樣,咱們就在GPU中,將最終頂點位置計算出來了。
實際上,上面全部步驟,three.js都幫咱們完成了。

 

5.二、片元着色器處理流程

咱們已經知道片元着色器負責處理材質、燈光等信息,但具體是怎麼處理呢?
以下圖:

 

5.三、three.js完整運行流程:


 

當咱們選擇材質後,three.js會根據咱們所選的材質,選擇對應的頂點着色器和片元着色器。three.js中已經內置了咱們經常使用着色器。

相關文章
相關標籤/搜索