一.簡介
這個世界有兩種着色器(Shader):
- Vertex shaders – 在你的場景中,每個頂點都需要調用的程序,稱為“頂點着色器”。假如你在渲染一個簡單的場景:一個長方形,每個角只有一個頂點。於是vertex shader 會被調用四次。它負責執行:諸如燈光、幾何變換等等的計算。得出最終的頂點位置后,為下面的片段着色器提供必須的數據。
- Fragment shaders – 在你的場景中,大概每個像素都會調用的程序,稱為“片段着色器”。在一個簡單的場景,也是剛剛說到的長方形。這個長方形所覆蓋到的每一個像素,都會調用一次fragment shader。片段着色器的責任是計算燈光,以及更重要的是計算出每個像素的最終顏色。
二.變量
GLSL的變量命名方式與C語言類似。變量的名稱可以使用字母,數字以及下划線,但變量名不能以數字開頭,還有變量名不能以gl_作為前綴,這個是GLSL保留的前綴,用於GLSL的內部變量。當然還有一些GLSL保留的名稱是不能夠作為變量的名稱的
三.基本類型
除了布爾型,整型,浮點型基本類型外,GLSL還引入了一些在着色器中經常用到的類型作為基本類型。這些基本類型都可以作為結構體內部的類型。如下表:
類型 描述 void 跟C語言的void類似,表示空類型。作為函數的返回類型,表示這個函數不返回值。 bool 布爾類型,可以是true 和false,以及可以產生布爾型的表達式。 int 整型 代表至少包含16位的有符號的整數。可以是十進制的,十六進制的,八進制的。 float 浮點型 bvec2 包含2個布爾成分的向量 bvec3 包含3個布爾成分的向量 bvec4 包含4個布爾成分的向量 ivec2 包含2個整型成分的向量 ivec3 包含3個整型成分的向量 ivec4 包含4個整型成分的向量 mat2 或者 mat2x2 2x2的浮點數矩陣類型 mat3或者mat3x3 3x3的浮點數矩陣類型 mat4x4 4x4的浮點矩陣 mat2x3 2列3行的浮點矩陣(OpenGL的矩陣是列主順序的) mat2x4 2列4行的浮點矩陣 mat3x2 3列2行的浮點矩陣 mat3x4 3列4行的浮點矩陣 mat4x2 4列2行的浮點矩陣 mat4x3 4列3行的浮點矩陣 sampler1D 用於內建的紋理函數中引用指定的1D紋理的句柄。只可以作為一致變量或者函數參數使用 sampler2D 二維紋理句柄 sampler3D 三維紋理句柄 samplerCube cube map紋理句柄 sampler1DShadow 一維深度紋理句柄 sampler2DShadow 二維深度紋理句柄
構造函數可以用於初始化包含多個成員的變量,包括數組和結構體。構造函數也可以用在表達式中。調用方式如下
vec3 myNormal = vec3(1.0, 1.0, 1.0);
greenTint = myColor + vec3(0.0, 1.0, 0.0);
ivec4 myColor = ivec4(255);
vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);
vec3 v = vec3(1.0, 10.0, 1.0);
vec3 v1 = vec3(v);
vec2 fv = vec2(5.0, 6.0);
四.結構體
結構體可以組合基本類型和數組來形成用戶自定義的類型。在定義一個結構體的同時,你可以定義一個結構體實例。或者后面再定義。
struct surface {float indexOfRefraction; vec3 color;float turbulence; } mySurface; surface secondeSurface;
五.數組
GLSL中只可以使用一維的數組。數組的類型可以是一切基本類型或者結構體
surface mySurfaces[]; vec4 lightPositions[8]; vec4 lightPos[] = lightPositions;const int numSurfaces = 5; surface myFiveSurfaces[numSurfaces];float[5] values;數組的下標從0開始。合理的范圍是[0, size - 1]。跟C語言一樣。如果數組訪問越界了,那行為是未定義的。如果着色器的編譯器在編譯時知道數組訪問越界了,就會提示編譯失敗。
vec4 myColor, ambient, diffuse[6], specular[6];
myColor = ambient + diffuse[4] + specular[4];
六.修飾符
修飾符 描述 const 常量值必須在聲明是初始化。它是只讀的不可修改的。 attribute 表示只讀的頂點數據,只用在頂點着色器中。數據來自當前的頂點狀態或者頂點數組。它必須是全局范圍聲明的,不能再函數內部。一個attribute可以是浮點數類型的標量,向量,或者矩陣。不可以是數組或則結構體 uniform 一致變量。在着色器執行期間一致變量的值是不變的。與const常量不同的是,這個值在編譯時期是未知的是由着色器外部初始化的。一致變量在頂點着色器和片段着色器之間是共享的。它也只能在全局范圍進行聲明。 varying 頂點着色器的輸出。例如顏色或者紋理坐標,(插值后的數據)作為片段着色器的只讀輸入數據。必須是全局范圍聲明的全局變量。可以是浮點數類型的標量,向量,矩陣。不能是數組或者結構體。 centorid varying 在沒有多重采樣的情況下,與varying是一樣的意思。在多重采樣時,centorid varying在光柵化的圖形內部進行求值而不是在片段中心的固定位置求值。 invariant (不變量)用於表示頂點着色器的輸出和任何匹配片段着色器的輸入,在不同的着色器中計算產生的值必須是一致的。所有的數據流和控制流,寫入一個invariant變量的是一致的。編譯器為了保證結果是完全一致的,需要放棄那些可能會導致不一致值的潛在的優化。除非必要,不要使用這個修飾符。在多通道渲染中避免z-fighting可能會使用到。 in 用在函數的參數中,表示這個參數是輸入的,在函數中改變這個值,並不會影響對調用的函數產生副作用。(相當於C語言的傳值),這個是函數參數默認的修飾符 out 用在函數的參數中,表示該參數是輸出參數,值是會改變的。 inout 用在函數的參數,表示這個參數即是輸入參數也是輸出參數。
七.內置變量
頂點着色器可用的內置變量如下表
名稱 類型 描述 gl_Color vec4 輸入屬性-表示頂點的主顏色 gl_SecondaryColor vec4 輸入屬性-表示頂點的輔助顏色 gl_Normal vec3 輸入屬性-表示頂點的法線值 gl_Vertex vec4 輸入屬性-表示物體空間的頂點位置 gl_MultiTexCoordn vec4 輸入屬性-表示頂點的第n個紋理的坐標 gl_FogCoord float 輸入屬性-表示頂點的霧坐標 gl_Position vec4 輸出屬性-變換后的頂點的位置,用於后面的固定的裁剪等操作。所有的頂點着色器都必須寫這個值。 gl_ClipVertex vec4 輸出坐標,用於用戶裁剪平面的裁剪 gl_PointSize float 點的大小 gl_FrontColor vec4 正面的主顏色的varying輸出 gl_BackColor vec4 背面主顏色的varying輸出 gl_FrontSecondaryColor vec4 正面的輔助顏色的varying輸出 gl_BackSecondaryColor vec4 背面的輔助顏色的varying輸出 gl_TexCoord[] vec4 紋理坐標的數組varying輸出 gl_FogFragCoord float 霧坐標的varying輸出
片段着色器的內置變量如下表
名稱 類型 描述 gl_Color vec4 包含主顏色的插值只讀輸入 gl_SecondaryColor vec4 包含輔助顏色的插值只讀輸入 gl_TexCoord[] vec4 包含紋理坐標數組的插值只讀輸入 gl_FogFragCoord float 包含霧坐標的插值只讀輸入 gl_FragCoord vec4 只讀輸入,窗口的x,y,z和1/w gl_FrontFacing bool 只讀輸入,如果是窗口正面圖元的一部分,則這個值為true gl_PointCoord vec2 點精靈的二維空間坐標范圍在(0.0, 0.0)到(1.0, 1.0)之間,僅用於點圖元和點精靈開啟的情況下。 gl_FragData[] vec4 使用glDrawBuffers輸出的數據數組。不能與gl_FragColor結合使用。 gl_FragColor vec4 輸出的顏色用於隨后的像素操作 gl_FragDepth float 輸出的深度用於隨后的像素操作,如果這個值沒有被寫,則使用固定功能管線的深度值代替
八.控制流
循環
與C和C++相似,GLSL語言也提供了for, while, do/while的循環方式。使用continue跳入下一次循環,break結束循環
for (l = 0; l < numLights; l++) {if (!lightExists[l])continue; color += light[l]; }while (i < num) { sum += color[i]; i++; }do{ color += light[lightNum]; lightNum--; }while (lightNum > 0)if/else
color = unlitColor;if (numLights > 0) { color = litColor; }else{ color = unlitColor; }discard
片段着色器中有一種特殊的控制流成為discard。使用discard會退出片段着色器,不執行后面的片段着色操作。片段也不會寫入幀緩沖區
if (color.a < 0.9)
discard;
九.函數
在每個shader中必須有一個main函數。main函數中的void參數是可選的,但返回值是void時必須的。
void main(void) { ... }
GLSL中的函數,必須是在全局范圍定義和聲明的。不能在函數定義中聲明或定義函數。函數必須有返回類型,參數是可選的。參數的修飾符(in, out, inout, const等)是可選的
結構體和數組也可以作為函數的參數。如果是數組作為函數的參數,則必須制定其大小。在調用傳參時,只傳數組名就可以了。
GLSL的函數是支持重載的。函數可以同名但其參數類型或者參數個數不同即可
