在webgl中,調用了OpenGL-ES-2.0的API,而在OpenGL-ES專為嵌入式設備設計,其和其它設備一樣,都是使用GLSL(GL Shading Language)來編寫片段程序並執行於GPU的着色器上,來完成對對象的渲染。GLSL在其中起着相當重要的作用,所以要玩好webgl,我們就得把GLSL搞懂,本文主要介紹shader的基礎使用及組成。
整個管線處理過程:
1.指定幾何對象
- 頂點數組(直接將頂點數據傳送至shader里)
- 頂點索引(將頂點數據保存於緩沖區中,用索引來從緩沖區獲取數據傳入shader)
2.逐個頂點操作
3.圖元組裝
根據指定的圖元組裝方式將若干頂點組成一個圖元,OpenGL支持的幾何圖元有點、線、不閉合折線、閉合折線、多邊形、三角形、線型連續填充三角形、扇形連續填充三角形、四邊形以及連續填充四邊形。
而webgl支持的圖元為POINTS(點), LINE_STRIP(不閉合折線), LINE_LOOP(閉合折線), LINES(獨立的線段), TRIANGLE_STRIP(頂點按順序相連的三角形), TRIANGLE_FAN(扇形順序組合三角形), TRIANGLES(每三個頂點組合成一個三角形)。
繪制三角形序列的三種方式解釋了三種三角形繪制方法之間的不同。
4.圖元處理
5.柵格化(生成片元fragment)
6.片元處理
7.逐個片元操作
8.幀緩沖區操作
在這八個步驟中,我們最重要的是對頂點和片元的操作,在整個管線中,我們可以加入的自己程序的部分則是頂點着色器和片元着色器部分。
着色器
頂點着色器:
操作的是頂點值和其關聯的數據,它可完成下面這些操作:
- 頂點變換
- 法線變換以及規格化
- 紋理坐標生成
- 紋理坐標變換
- 光照
- 彩色材質應用
頂點着色器必須計算坐標在裁剪空間中的齊次位置並將結果存儲在特殊的輸出變量gl_Position中,它還有特殊的輸出變量gl_ClipVertex,gl_PointSize。
頂點處理器的輸出將被發送到后續的處理階段,即:圖元組裝,用戶裁剪,平截裁剪,透視划分,視口貼圖,多邊形偏移,多邊形模式,陰影模式,消隱等。
片元着色器:
處理片元值及其相關聯數據,它可執行傳統的圖形操作,如:
在插值等到的值上的操作
- 訪問紋理
- 應用紋理
- 霧化
- 顏色匯總
片元着色器其有特殊的輸入變量gl_FragCoord(片元的窗口相對坐標)和gl_FrontFacing(正面圖元為true,反之為false),經過計算顏色和深度將這些值寫入特殊的輸出變量gl_FragColor和gl_FragDepth中,或者完全丟棄(使用discard關鍵字)片元。
片元處理器的一大優點是它可以任意多次地訪問紋理內存,並可以任意方式結合所讀取的值,一次紋理訪問的結果可作為執行另一次紋理訪問的基礎。
有三個精度可選擇:lowp highp mediump
精度可指定於變量或設置默認精度
頂點着色器中的float和init默認精度為highp
片元着色器中float沒有默認精度,所以必須為其指定默認精度,如:precision mediump float;
着色器多個執行是可並行發生的,針對每個頂點都會執行一次頂點着色器,針對每個片元都會執行一次片元着色器。
限定符
我們要向着色器中傳入數據,則要了解其里面變量的組成和輸入方式
屬性變量(attribute):
這些變量代表了非常頻繁地從應用程序傳遞到頂點處理器的值,只應用於程序中定義頂點數據,所以只允許作為頂點着色器的一部分,該值可以像每個頂點那樣經常變動
一致變量(uniform):
用來將數據值從應用程序傳遞到頂點處理器或片元處理器,一致變量通常用來提供不頻繁變動的值。
易變變量(varying):
定義了從頂點處理器傳遞到片元處理器的數據。
常量變量(const):
如C中的常量變量
數據類型
標量:
支持使用浮點數(float)、整數(int)和布爾值(bool)
矢量:
浮點數矢量:
vec2 (2個浮點數的矢量)
vec3 (3個浮點數的矢量)
vec4 (4個浮點數的矢量)
整數矢量:
ivec2 (2個整數的矢量)
ivec3 (3個整數的矢量)
ivec4 (4個整數的矢量)
布爾矢量:
bvec2 (2個布爾值的矢量)
bvec3 (3個布爾值的矢量)
bvec4 (4個布爾值的矢量)
矩陣:
mat2 (2×2的浮點數矩陣)
mat3 (3×3的浮點數矩陣)
mat4 (4×4的浮點數矩陣)
mat矩陣就像是一個vec數組,它也可以使用數組來進行訪問。
取樣器:
sampler1D (訪問一個一維紋理)
sampler2D (訪問一個二維紋理)
sampler3D (訪問一個三維紋理)
samplerCube (訪問一個立方貼圖紋理)
sampler1DShadow (訪問一個帶對比的一維深度紋理)
sampler2DShadow (訪問一個帶對比的二維深度紋理)
只能通過uniform限定的取樣器從應用程序接收取樣器
使用時: uniform sampler2D texture;
操作
如果要對矢量進行部分操作,則可用訪問矢量中的部分來使用,在shader中,共有三組組合供使用:
- x y z w
- s t p q
- r g b a
這四個值只是分別讀取矢量中的第一個、第二個、第三個、第四個值,只是為了編寫方便,語義化了三組組合,分別為坐標、紋理、顏色,但是使用它們去讀取出來的值是一樣的,如:
vec4 values = vec4(1.0,2.0,3.0,4.0); values.z; //3.0 values.p; //3.0 values.b; //3.0
values[2]; //3.0
這三組使用時必須成組出現,不能混組出現,如:
vec4 values = vec4(1.0,2.0,3.0,4.0); vec2 combination1 = values.xy; //同一組,正確 vec3 combination2 = values.rgb; //同一組,正確 vec3 combination3 = values.xt; //不同組,不正確
對矩陣的讀取可以像數組一樣:
vec2 x,y; mat2 matrix; x = matrix[0]; y = matrix[1];
運算
對於矢量的計算:
vec3 v,u,w; w = v + u; //計算過程等價於 w.x = v.x + u.x; w.y = v.y + u.y; w.z = v.z + w.z;
對於矩陣和矢量的計算:
//該過程遵守線性代數中的計算規定,即做點乘的兩個矩陣,前一個矩陣的行數等於后一個矩陣的列數 vec4 v,u; mat4 m; v * m; //行矢量與矩陣相乘 m * v; //矩陣與列矢量相乘 m * m; //矩陣與矩陣相乘
運算順序:
//當多個矩陣同時施加加頂點矢量上時,則要以相反的順序矩陣相乘 //如想實現先Ma再Mb的運算 vec4 v,u; mat4 Ma,Mb; u = Mb * (Ma * v); //即 u = (Mb * Ma) * v; //即 u = Mb * Ma * v;
與C和C++差異
着色語言作為一種處理數字的語言,而不是處理字符或字符串數據的語言,在其中沒有包含對指針、字符串、字符或基於這些類型的任何操作支持。
並且為了使編譯器和圖形硬件的實現負擔更小,該語言不支持雙精度浮點數、字節、短整數、長整數或者這些類型的無符號變化形式。
其包括了C++的一些重要語言特性:支持函數重載,支持基本類型bool。
注:
在向頂點着色器中進行傳值時,頂點着色器會從緩存中依次讀取每個頂點,如果使用的是頂點數組方法:
如傳入:new Float32Array([1.0,1.0,1.0,0.0,
0.5,0.5,0.5,0.0]);
那么在shader中,假設有attribute vec4 position;
會從緩存中依次讀取四個數來作為position進行處理,則總共執行了兩次頂點着色器,共兩個頂點。
如果在shader中有attribute vec2 position;
則會從緩存中依次讀取兩個數來作為position進行處理,共四個頂點,頂點着色器執行四次。
附:
WebGL-1.0參考卡片:http://files.cnblogs.com/files/zhiyishou/webgl-reference-card-1_0.pdf
OpenGL-ES-2.0參考卡片:http://files.cnblogs.com/files/zhiyishou/OpenGL-ES-2_0-Reference-card.pdf
The end.