今天由位元組跳動的“yancy”童鞋給大家重磅推出一篇
WebGL
的乾貨接下來讓我們開啟奇幻旅程,進入
3D
的世界。
本文作者:yancy
1. 認識3D
首先我們要介紹的是幾個概念,這是我們要進入到
3D
不可或缺的內容。認識一下它們吧。
1.1 視點,視線,目標點,上方向
這幾個概念在
WebGL
中屬於最常見的內容。
視點:可以簡易的理解為眼睛,也叫觀察點
目標點:可以理解為我們要看的物體(任何物體)
上方向:頭頂的方向。
實際生活中,我們的目光總是以我們的眼睛為起始點,到達我們想要看到的物體,同時,隨著我們觀察的角度不同,物體也會呈現不一樣的形態。以一張圖說明吧。
如此幾個內容,創建出了
3D
世界的基本顯示模型,由此可見其重要程度。後面我們也會說到如何在
WebGL
中設定這幾個內容。也會有的小夥伴把
視點稱為相機
,
目標點稱為畫布
。其實是一樣的道理。按照自己的理解記憶就好。
1.2 可視範圍
可視範圍指的是我們所能看到的最大範圍。如:一般情況下我們看不到自己身後的事物。眾所周知,三維物體具有深度的概念。在我們的理解中,深度就是
z
軸。雖然我們可以將物體放置在三維空間中的任何位置,但是在
WebGL
中,可視範圍之外的物體是不被繪製的,這也是為了節省開銷。
1.3 可視空間
水平視角、垂直視角、可視深度
定義了可視空間的概念。可視空間分為兩種。
正射投影:與物體的遠近無關,通常用在建築設計和建模上。
透視投影:我們平時觀察的真實世界都是透視投影。更有深度的感覺。
1.3 著色器
如果想渲染
3D
圖形,就需要經過一系列的步驟,這些步驟稱為渲染管線。在開發
WebGL
程式時,我們就需要透過著色器語言跟GPU進行溝通,用來設定我們需要渲染和顯示的圖形。由此可見:著色器是編寫
WebGL
時最重要的一點(沒有之一)。我們之所以能生成並操作
3D
影象,都是因為著色器在起作用。
WebGL
中著色器分為兩種。
頂點著色器和片元著色器
。
1。3。1 頂點著色器
這裡的頂點代表的是組成物體的每一個點。*
頂點著色器的功能主要是將位置資料經過矩陣變換、計算光照之後生成頂點顏色、變換紋理座標。並將生成的資料輸出到片元著色器。
1。3。2 片元著色器
片元著色器的作用是將
光柵化階段
生成的每個片元,計算出每個片元的最終元素。
注:*
由於著色器內容比較重要,這裡我們先引入這兩個概念,先簡單理解就可以,後面專門對著色器進行分享。
2. 繪製圖形
2.1 獲取繪圖上下文
瞭解了第一小節的內容之後,我們開始進入到
WebGL
開發實戰中。還記得
Canvas
中第一步需要幹什麼嗎?沒錯,需要獲取
Canvas
元素和繪圖上下文。
WebGL
開發也不例外,也需要首先獲取元素和繪圖上下文。形如下方程式碼所示:
2.2 初始化著色器
2。2。1。 編寫著色器程式碼
獲取到繪圖上下文之後,我們需要初始化
WebGL
的著色器了,
著色器程式碼是以字串的形式嵌入到渲染程式中
,所以我們需要編寫兩個著色器的字串。
兩個著色器程式碼都是以字串的形式存在,並在執行渲染時嵌入到渲染流程內。說明:
void main() {}
: 建立一個主函式。
gl_Position
: 指定繪製的座標,接收一個擁有4個浮點分量的
vec4
資料。分別代表
x,y,z,w
資料
gl_PointSize
: 表示要繪製圖形的尺寸大小。
gl_FragColor
: 定義圖形顏色,
1。0 0。0 0。0 1。0
分別代表
r g b a
2。2。2。 建立著色器
當然,只是編寫完著色器程式碼依然不能完成渲染工作,接下來我們就需要將著色器新增到渲染流程內
2。2。3。 著色器編譯
完成上述兩步之後,我們就需要將著色器程式碼新增到著色器中。看下例子。
2。2。4。 建立 program
完成編譯之後,我們需要將著色器新增到渲染程式中。
2。2。5。 繪製圖形
完成上述步驟之後,就可以繪製我們的圖形了。這裡我們以一個點為例。在畫布上繪製一個點出來。
gl。drawArrays(gl。POINTS, 0, 1);
此時就可以開啟頁面,看到我們繪製的這個點了。總結程式碼:
3. 渲染管線
3.1 基礎內容介紹
WebGL
的渲染依賴底層
GPU
的渲染能力。所以
WebGL
渲染流程和
GPU
內部的渲染管線是相符的。
渲染管線的作用是將3D模型轉換為2維影象。*
在早期,渲染管線是不可程式設計的,叫做
固定渲染管線
,工作的細節流程已經固定,修改的話需要調整一些引數。現代的
GPU
所包含的渲染管線為
可程式設計渲染管線
,可以透過程式設計
GLSL,著色器語言
來控制一些渲染階段的細節。
3.2 渲染過程
(心理承受弱的同學可跳過此小節)*
WebGL
的渲染過程分為以下幾項:
頂點著色器
圖片裝配
光柵化
片元著色器
逐片段操作(本文不會分享此內容)
裁剪測試
多重取樣操作
背面剔除
模板測試
深度測試
融合
快取
這裡一系列的名詞可能會嚇到很多同學,千萬別被名詞嚇到喲,接下來的過程中會詳細說明。也希望透過本文可以讓大家理解基本的渲染流程。附圖解一張,助大家理解。
4. 頂點著色器
頂點著色器的作用是透過計算獲得最終的頂點座標*
, 如:
A ——> () => {…………} ==> A1
:座標
A
經過一系列的計算,最終獲取座標
A1
B ——> () => {…………} ==> B1
:座標
B
經過一系列的計算,最終獲取座標
B1
…………頂點著色器計算出來的座標將會渲染到最終的顯示畫布上。此外,頂點著色器還會計算如下內容:
顏色、紋理座標、頂點尺寸……
在頂點著色器階段通常會涉及到三個型別的變數。
attribute
:針對單一頂點生效。
通常用於:頂點位置、頂點大小等內容
uniform
:影響所有頂點
通常用於:旋轉、平移、縮放等位置變換、顏色處理等內容。
varying
:可透過頂點著色器傳入到片元著色器。像
attribute
這個變數之前我們就用到過,用來設定了頂點的位置和大小。 回顧一下
其他的兩個變數暫時沒有用到,接下來的內容裡會用到這兩種型別的變數。敬請期待
5. 圖元裝配和光柵化
什麼是圖元?*
官方解釋:
描述各種圖形元素的函式叫做圖元,描述幾何元素的稱為幾何圖元(點,線段或多邊形)。點和線是最簡單的幾何圖元
經過頂點著色器計算之後的座標會被組裝成
組合圖元
。
接下來透過一組圖解來看看渲染器如何進行圖元裝配和光柵化
通俗解釋
圖元就是一個點、一條線段、或者是一個多邊形。*
5.1 圖元裝配
什麼是圖元裝配呢?簡單理解就是說將我們設定的頂點、顏色、紋理等內容組裝稱為一個可渲染的多邊形的過程。
注意:*
如何組裝取決於
gl。drawArrays(type, count)
中的
type
型別,本文最後有詳細的內容。在之前的文章裡,我們就使用
gl。POINTS
來繪製了一個點。
5.2 光柵化
片元:二維圖象上每個點都包含了顏色、深度和紋理資料。這樣一個點稱為片元*
光柵化可以簡單理解為以下內容:透過圖元裝配生成的多邊形,計算畫素並填充,
剔除
不可見的部分,
剪裁
掉不在可視範圍內的部分。最終生成可見的帶有顏色資料的圖形並繪製。光柵化流程圖解:
剔除和剪裁
剔除
:舉一個日常生活中的栗子來說明吧。
在日常生活中,對於不透明物體,背面對於觀察者來說是不可見的。同樣,在
WebGL
中,我們也可以設定物體的背面不可見,那麼在渲染過程中,就會將不可見的部分剔除,不參與繪製。節省渲染開銷。
剪裁
:同樣舉例子來說明
日常生活中不論是在看電視還是觀察物體,都會有一個可視範圍,在可視範圍之外的事物我們是看不到的。類似的,圖形生成後,有的部分可能位於可視範圍之外,這一部分會被剪裁掉,不參與繪製。以此來提高效能。
6. 片元著色器
接收光柵化階段生成的片元,在光柵化階段中,已經計算出每個片元的顏色資訊,這一階段會將片元做逐片元挑選的操作,處理過的片元會繼續向後面的階段傳遞。
逐片元挑選
透過模板測試和深度測試來確定片元是否要顯示,測試過程中會丟棄掉部分無用的片元內容,然後生成可繪製的二維影象繪製並顯示。
深度測試:
就是對
z
軸的值做測試,值比較小的片元內容會覆蓋值比較大的。(類似於近處的物體會遮擋遠處物體)。
模板測試:
模擬觀察者的觀察行為,可以接為映象觀察。標記所有映象中出現的片元,最後只繪製有標記的內容。
7. 例項分析
下面結合2。2。5的程式碼,我們進行流程分析,加深理解。
分析:*
首先建立了兩個變數
VERTEX_SHADER 頂點著色器
和
FRAGMENT_SHADER 片元著色器
。這兩個內容會透過下面的程式碼新增到頂點著色器和片元著色器中。
之後透過
gl。createShader()
建立了兩個著色器。傳入不同的引數即可建立不同的著色器。建立並關聯著色器的步驟比較複雜。當你熟悉這個過程之後,可以將這個過程的程式碼封裝起來作為備用。
接下來,透過
將著色器程式碼新增到著色器中、編輯著色器、建立程式物件、將著色器新增到程式物件中、關聯程式物件、使用程式物件
這一系列的步驟初始化著色器和程式物件。
當所有的前置工作準備就緒之後,就可以呼叫
gl。drawArrays()
方法來繪製想要的圖形。
7.1 gl.drawArrays(type, first, count)
1。
type
代表要繪製的圖形形狀,值有以下幾種:
gl.POINTS
: 要繪製一系列的點
gl.LINES
: 要繪製了一系列未連線直線段(單獨行)
gl.LINE_STRIP
: 要繪製一系列連線的線段
*
gl。LINE_LOOP *
: 要繪製一系列連線的線段。它還連線第一個和最後一個頂點,以形成一個環
gl.TRIANGLES
: 一系列單獨的三角形
gl.TRIANGLE_STRIP
: 繪製一個三角帶
gl.TRIANGLE_FAN
: 繪製一個扇形(三角扇)
2。
first
代表從哪個點開始
3。
count
代表需要使用幾個點
栗子:
其他的形狀可以自己嘗試…………會有意想不到的效果。
文章為原創文章,若有侵權請聯絡;