基本類型:
| 類型 | 說明 |
|---|---|
| void | 空類型,即不返回任何值 |
| bool | 布爾類型 true,false |
| int | 帶符號的整數 signed integer |
| float | 帶符號的浮點數 floating scalar |
| vec2, vec3, vec4 | n維浮點數向量 n-component floating point vector |
| bvec2, bvec3, bvec4 | n維布爾向量 Boolean vector |
| ivec2, ivec3, ivec4 | n維整數向量 signed integer vector |
| mat2, mat3, mat4 | 2x2, 3x3, 4x4 浮點數矩陣 float matrix |
| sampler2D | 2D紋理 a 2D texture |
| samplerCube | 盒紋理 cube mapped texture |
基本結構和數組:
| 類型 | 說明 |
|---|---|
| 結構 | struct type-name{} 類似c語言中的 結構體 |
| 數組 | float foo[3] glsl只支持1維數組,數組可以是結構體的成員 |
向量的分量訪問:
glsl中的向量(vec2,vec3,vec4)往往有特殊的含義,比如可能代表了一個空間坐標(x,y,z,w),或者代表了一個顏色(r,g,b,a),再或者代表一個紋理坐標(s,t,p,q) 所以glsl提供了一些更人性化的分量訪問方式.
vector.xyzw 其中xyzw 可以任意組合
vector.rgba 其中rgba 可以任意組合
vector.stpq 其中rgba 可以任意組合
vec4 v=vec4(1.0,2.0,3.0,1.0); float x = v.x; //1.0 float x1 = v.r; //1.0 float x2 = v[0]; //1.0 vec3 xyz = v.xyz; //vec3(1.0,2.0,3.0) vec3 xyz1 = vec(v[0],v[1],v[2]); //vec3(1.0,2.0,3.0) vec3 rgb = v.rgb; //vec3(1.0,2.0,3.0) vec2 xyzw = v.xyzw; //vec4(1.0,2.0,3.0,1.0); vec2 rgba = v.rgba; //vec4(1.0,2.0,3.0,1.0);
運算符:
| 優先級(越小越高) | 運算符 | 說明 | 結合性 |
|---|---|---|---|
| 1 | () | 聚組:a*(b+c) | N/A |
| 2 | [] () . ++ -- | 數組下標__[],方法參數__fun(arg1,arg2,arg3),屬性訪問__a.b__,自增/減后綴__a++ a--__ | L - R |
| 3 | ++ -- + - ! | 自增/減前綴__++a --a__,正負號(一般正號不寫)a ,-a,取反__!false__ | R - L |
| 4 | * / | 乘除數學運算 | L - R |
| 5 | + - | 加減數學運算 | L - R |
| 7 | < > <= >= | 關系運算符 | L - R |
| 8 | == != | 相等性運算符 | L - R |
| 12 | && | 邏輯與 | L - R |
| 13 | ^^ | 邏輯排他或(用處基本等於!=) | L - R |
| 14 | || | 邏輯或 | L - R |
| 15 | __? :__ | 三目運算符 | L - R |
| 16 | = += -= *= /= | 賦值與復合賦值 | L - R |
| 17 | , | 順序分配運算 | L - R |
ps 左值與右值:
左值:表示一個儲存位置,可以是變量,也可以是表達式,但表達式最后的結果必須是一個儲存位置.
右值:表示一個值, 可以是一個變量或者表達式再或者純粹的值.
操作符的優先級:決定含有多個操作符的表達式的求值順序,每個操作的優先級不同.
操作符的結合性:決定相同優先級的操作符是從左到右計算,還是從右到左計算。
基礎類型間的運算:
glsl中,沒有隱式類型轉換,原則上glsl要求任何表達式左右兩側(l-value),(r-value)的類型必須一致 也就是說以下表達式都是錯誤的:
int a =2.0; //錯誤,r-value為float 而 lvalue 為int. int a =1.0+2; float a =2; float a =2.0+1; bool a = 0; vec3 a = vec3(1.0, 2.0, 3.0) * 2;
下面來分別說說可能遇到的情況:
1.float 與 int:
float與float , int與int之間是可以直接運算的,但float與int不行.它們需要進行一次顯示轉換.即要么把float轉成int: int(1.0) ,要么把int轉成float: float(1) ,以下表達式都是正確的:
int a=int(2.0); float a= float(2); int a=int(2.0)*2 + 1; float a= float(2)*6.0+2.3;
2.float 與 vec(向量) mat(矩陣):
vec,mat這些類型其實是由float復合而成的,當它們與float運算時,其實就是在每一個分量上分別與float進行運算,這就是所謂的逐分量運算.glsl里 大部分涉及vec,mat的運算都是逐分量運算,但也並不全是. 下文中就會講到特例.
逐分量運算是線性的,這就是說 vec 與 float 的運算結果是還是 vec.
int 與 vec,mat之間是不可運算的, 因為vec和mat中的每一個分量都是 float 類型的. 無法與int進行逐分量計算.
下面枚舉了幾種 float 與 vec,mat 運算的情況
vec3 a = vec3(1.0, 2.0, 3.0); mat3 m = mat3(1.0); float s = 10.0; vec3 b = s * a; // vec3(10.0, 20.0, 30.0) vec3 c = a * s; // vec3(10.0, 20.0, 30.0) mat3 m2 = s * m; // = mat3(10.0) mat3 m3 = m * s; // = mat3(10.0)
3. vec(向量) 與 vec(向量):
兩向量間的運算首先要保證操作數的階數都相同.否則不能計算.例如: vec3*vec2 vec4+vec3 等等都是不行的.
它們的計算方式是兩操作數在同位置上的分量分別進行運算,其本質還是逐分量進行的,這和上面所說的float類型的 逐分量運算可能有一點點差異,相同的是 vec 與 vec 運算結果還是 vec, 且階數不變.
vec3 a = vec3(1.0, 2.0, 3.0); vec3 b = vec3(0.1, 0.2, 0.3); vec3 c = a + b; // = vec3(1.1, 2.2, 3.3) vec3 d = a * b; // = vec3(0.1, 0.4, 0.9)
3. vec(向量) 與 mat(矩陣):
要保證操作數的階數相同,且vec與mat間只存在乘法運算.
它們的計算方式和線性代數中的矩陣乘法相同,不是逐分量運算.
vec2 v = vec2(10., 20.); mat2 m = mat2(1., 2., 3., 4.); vec2 w = m * v; // = vec2(1. * 10. + 3. * 20., 2. * 10. + 4. * 20.) ... vec2 v = vec2(10., 20.); mat2 m = mat2(1., 2., 3., 4.); vec2 w = v * m; // = vec2(1. * 10. + 2. * 20., 3. * 10. + 4. * 20.)
向量與矩陣的乘法規則如下:
4. mat(矩陣) 與 mat(矩陣):
要保證操作數的階數相同.
在mat與mat的運算中, 除了乘法是線性代數中的矩陣乘法外.其余的運算任為逐分量運算.簡單說就是只有乘法是特殊的,其余都和vec與vec運算類似.
mat2 a = mat2(1., 2., 3., 4.); mat2 b = mat2(10., 20., 30., 40.); mat2 c = a * b; //mat2(1.*10.+3.*20.,2.*10.+4.*20.,1.* 30.+3.*40.,2.* 30.+4.*40.); mat2 d = a+b;//mat2(1.+10.,2.+20.,3.+30.,4.+40);
矩陣乘法規則如下:
變量限定符:
| 修飾符 | 說明 |
|---|---|
| none | (默認的可省略)本地變量,可讀可寫,函數的輸入參數既是這種類型 |
| const | 聲明變量或函數的參數為只讀類型 |
| attribute | 只能存在於vertex shader中,一般用於保存頂點或法線數據,它可以在數據緩沖區中讀取數據 |
| uniform | 在運行時shader無法改變uniform變量, 一般用來放置程序傳遞給shader的變換矩陣,材質,光照參數等等. |
| varying | 主要負責在vertex 和 fragment 之間傳遞變量 |
const:
和C語言類似,被const限定符修飾的變量初始化后不可變,除了局部變量,函數參數也可以使用const修飾符.但要注意的是結構變量可以用const修飾, 但結構中的字段不行.
const變量必須在聲明時就初始化 const vec3 v3 = vec3(0.,0.,0.)
局部變量只能使用const限定符.
函數參數只能使用const限定符.
struct light { vec4 color; vec3 pos; //const vec3 pos1; //結構中的字段不可用const修飾會報錯. }; const light lgt = light(vec4(1.0), vec3(0.0)); //結構變量可以用const修飾
attribute:
attribute變量是全局且只讀的,它只能在vertex shader中使用,只能與浮點數,向量或矩陣變量組合, 一般attribute變量用來放置程序傳遞來的模型頂點,法線,顏色,紋理等數據它可以訪問數據緩沖區 (還記得__gl.vertexAttribPointer__這個函數吧)
attribute vec4 a_Position;
uniform:
uniform變量是全局且只讀的,在整個shader執行完畢前其值不會改變,他可以和任意基本類型變量組合, 一般我們使用uniform變量來放置外部程序傳遞來的環境數據(如點光源位置,模型的變換矩陣等等) 這些數據在運行中顯然是不需要被改變的.
uniform vec4 lightPosition;
varying:
varying類型變量是 vertex shader 與 fragment shader 之間的信使,一般我們在 vertex shader 中修改它然后在fragment shader使用它,但不能在 fragment shader中修改它.
//頂點着色器 varying vec4 v_Color; void main(){ ... v_Color = vec4(1.,1.,1.,1); } //片元着色器 ... varying vec4 v_Color; void main() { gl_FragColor = v_Color; } ...
要注意全局變量限制符只能為 const、attribute、uniform和varying中的一個.不可復合.
函數參數限定符:
函數的參數默認是以拷貝的形式傳遞的,也就是值傳遞,任何傳遞給函數參數的變量,其值都會被復制一份,然后再交給函數內部進行處理. 我們可以為參數添加限定符來達到傳遞引用的目的,glsl中提供的參數限定符如下:
| 限定符 | 說明 |
|---|---|
| < none: default > | 默認使用 in 限定符 |
| in | 復制到函數中在函數中可讀寫 |
| out | 返回時從函數中復制出來 |
| inout | 復制到函數中並在返回時復制出來 |
in 是函數參數的默認限定符,最終真正傳入函數形參的其實是實參的一份拷貝.在函數中,修改in修飾的形參不會影響到實參變量本身.
out 它的作用是向函數外部傳遞新值,out模式下傳遞進來的參數是write-only的(可寫不可讀).就像是一個"坑位",坑位中的值需要函數給他賦予. 在函數中,修改out修飾的形參會影響到實參本身.
inout inout下,形參可以被理解為是一個帶值的"坑位",及可讀也可寫,在函數中,修改inout修飾的形參會影響到實參本身.
glsl的函數:
glsl允許在程序的最外部聲明函數.函數不能嵌套,不能遞歸調用,且必須聲明返回值類型(無返回值時聲明為void) 在其他方面glsl函數與c函數非常類似.
vec4 getPosition(){
vec4 v4 = vec4(0.,0.,0.,1.); return v4; } void doubleSize(inout float size){ size= size*2.0 ; } void main() { float psize= 10.0; doubleSize(psize); gl_Position = getPosition(); gl_PointSize = psize; }
構造函數:
glsl中變量可以在聲明的時候初始化,float pSize = 10.0 也可以先聲明然后等需要的時候在進行賦值.
聚合類型對象如(向量,矩陣,數組,結構) 需要使用其構造函數來進行初始化. vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
//一般類型 float pSize = 10.0; float pSize1; pSize1=10.0; ... //復合類型 vec4 color = vec4(0.0, 1.0, 0.0, 1.0); vec4 color1; color1 =vec4(0.0, 1.0, 0.0, 1.0); ... //結構 struct light { float intensity; vec3 position; }; light lightVar = light(3.0, vec3(1.0, 2.0, 3.0)); //數組 const float c[3] = float[3](5.0, 7.2, 1.1);
類型轉換:
glsl可以使用構造函數進行顯式類型轉換,各值如下:
bool t= true; bool f = false; int a = int(t); //true轉換為1或1.0 int a1 = int(f);//false轉換為0或0.0 float b = float(t); float b1 = float(f); bool c = bool(0);//0或0.0轉換為false bool c1 = bool(1);//非0轉換為true bool d = bool(0.0); bool d1 = bool(1.0);
精度限定:
glsl在進行光柵化着色的時候,會產生大量的浮點數運算,這些運算可能是當前設備所不能承受的,所以glsl提供了3種浮點數精度,我們可以根據不同的設備來使用合適的精度.
在變量前面加上 highp mediump lowp 即可完成對該變量的精度聲明.
lowp float color;
varying mediump vec2 Coord;
lowp ivec2 foo(lowp mat3);
highp mat4 m;
我們一般在片元着色器(fragment shader)最開始的地方加上 precision mediump float; 便設定了默認的精度.這樣所有沒有顯式表明精度的變量 都會按照設定好的默認精度來處理.
如何確定精度:
變量的精度首先是由精度限定符決定的,如果沒有精度限定符,則要尋找其右側表達式中,已經確定精度的變量,一旦找到,那么整個表達式都將在該精度下運行.如果找到多個, 則選擇精度較高的那種,如果一個都找不到,則使用默認或更大的精度類型.
uniform highp float h1;
highp float h2 = 2.3 * 4.7; //運算過程和結果都 是高精度 mediump float m; m = 3.7 * h1 * h2; //運算過程 是高精度 h2 = m * h1; //運算過程 是高精度 m = h2 – h1; //運算過程 是高精度 h2 = m + m; //運算過程和結果都 是中等精度 void f(highp float p); // 形參 p 是高精度 f(3.3); //傳入的 3.3是高精度
invariant關鍵字:
由於shader在編譯時會進行一些內部優化,可能會導致同樣的運算在不同shader里結果不一定精確相等.這會引起一些問題,尤其是vertx shader向fragmeng shader傳值的時候. 所以我們需要使用invariant 關鍵字來顯式要求計算結果必須精確一致. 當然我們也可使用 #pragma STDGL invariant(all)來命令所有輸出變量必須精確一致, 但這樣會限制編譯器優化程度,降低性能.
#pragma STDGL invariant(all) //所有輸出變量為 invariant invariant varying texCoord; //varying在傳遞數據的時候聲明為invariant
限定符的順序:
當需要用到多個限定符的時候要遵循以下順序:
1.在一般變量中: invariant > storage > precision
2.在參數中: storage > parameter > precision
我們來舉例說明:
invariant varying lowp float color; // invariant > storage > precision void doubleSize(const in lowp float s){ //storage > parameter > precision float s1=s; }
預編譯指令:
以 # 開頭的是預編譯指令,常用的有:
#define #undef #if #ifdef #ifndef #else
#elif #endif #error #pragma #extension #version #line
比如 #version 100 他的意思是規定當前shader使用 GLSL ES 1.00標准進行編譯,如果使用這條預編譯指令,則他必須出現在程序的最開始位置.
內置的宏:
__LINE__ : 當前源碼中的行號.
__VERSION__ : 一個整數,指示當前的glsl版本 比如 100 ps: 100 = v1.00
GL_ES : 如果當前是在 OPGL ES 環境中運行則 GL_ES 被設置成1,一般用來檢查當前環境是不是 OPENGL ES.
GL_FRAGMENT_PRECISION_HIGH : 如果當前系統glsl的片元着色器支持高浮點精度,則設置為1.一般用於檢查着色器精度.
實例:
1.如何通過判斷系統環境,來選擇合適的精度:
#ifdef GL_ES // #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #endif
2.自定義宏:
#define NUM 100 #if NUM==100 #endif
內置的特殊變量
glsl程序使用一些特殊的內置變量與硬件進行溝通.他們大致分成兩種 一種是 input類型,他負責向硬件(渲染管線)發送數據. 另一種是output類型,負責向程序回傳數據,以便編程時需要.
在 vertex Shader 中:
output 類型的內置變量:
| 變量 | 說明 | 單位 |
|---|---|---|
highp vec4 gl_Position; |
gl_Position 放置頂點坐標信息 | vec4 |
mediump float gl_PointSize; |
gl_PointSize 需要繪制點的大小,(只在gl.POINTS模式下有效) | float |
在 fragment Shader 中:
input 類型的內置變量:
| 變量 | 說明 | 單位 |
|---|---|---|
mediump vec4 gl_FragCoord; |
片元在framebuffer畫面的相對位置 | vec4 |
bool gl_FrontFacing; |
標志當前圖元是不是正面圖元的一部分 | bool |
mediump vec2 gl_PointCoord; |
經過插值計算后的紋理坐標,點的范圍是0.0到1.0 | vec2 |
output 類型的內置變量:
| 變量 | 說明 | 單位 |
|---|---|---|
mediump vec4 gl_FragColor; |
設置當前片點的顏色 | vec4 RGBA color |
mediump vec4 gl_FragData[n] |
設置當前片點的顏色,使用glDrawBuffers數據數組 | vec4 RGBA color |
內置的常量
glsl提供了一些內置的常量,用來說明當前系統的一些特性. 有時我們需要針對這些特性,對shader程序進行優化,讓程序兼容度更好.
在 vertex Shader 中:
1.const mediump int gl_MaxVertexAttribs>=8
gl_MaxVertexAttribs 表示在vertex shader(頂點着色器)中可用的最大attributes數.這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 8 個.
2.const mediump int gl_MaxVertexUniformVectors >= 128
gl_MaxVertexUniformVectors 表示在vertex shader(頂點着色器)中可用的最大uniform vectors數. 這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 128 個.
3.const mediump int gl_MaxVaryingVectors >= 8
gl_MaxVaryingVectors 表示在vertex shader(頂點着色器)中可用的最大varying vectors數. 這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 8 個.
4.const mediump int gl_MaxVertexTextureImageUnits >= 0
gl_MaxVaryingVectors 表示在vertex shader(頂點着色器)中可用的最大紋理單元數(貼圖). 這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 甚至可以一個都沒有(無法獲取頂點紋理)
5.const mediump int gl_MaxCombinedTextureImageUnits >= 8
gl_MaxVaryingVectors 表示在 vertex Shader和fragment Shader總共最多支持多少個紋理單元. 這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 8 個.
在 fragment Shader 中:
1.const mediump int gl_MaxTextureImageUnits >= 8
gl_MaxVaryingVectors 表示在 fragment Shader(片元着色器)中能訪問的最大紋理單元數,這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 8 個.
2.const mediump int gl_MaxFragmentUniformVectors >= 16
gl_MaxFragmentUniformVectors 表示在 fragment Shader(片元着色器)中可用的最大uniform vectors數,這個值的大小取決於 OpenGL ES 在某設備上的具體實現, 不過最低不能小於 16 個.
3.const mediump int gl_MaxDrawBuffers = 1
gl_MaxDrawBuffers 表示可用的drawBuffers數,在OpenGL ES 2.0中這個值為1, 在將來的版本可能會有所變化.
glsl中還有一種內置的uniform狀態變量, gl_DepthRange 它用來表明全局深度范圍.
結構如下:
struct gl_DepthRangeParameters { highp float near; // n highp float far; // f highp float diff; // f - n }; uniform gl_DepthRangeParameters gl_DepthRange;
除了 gl_DepthRange 外的所有uniform狀態常量都已在glsl 1.30 中廢棄.
流控制
glsl的流控制和c語言非常相似,這里不必再做過多說明,唯一不同的是片段着色器中有一種特殊的控制流discard. 使用discard會退出片段着色器,不執行后面的片段着色操作。片段也不會寫入幀緩沖區。
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 (true) discard;
內置函數庫
glsl提供了非常豐富的函數庫,供我們使用,這些功能都是非常有用且會經常用到的. 這些函數按功能區分大改可以分成7類:
通用函數:
下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 說明 |
|---|---|
| T abs(T x) | 返回x的絕對值 |
| T sign(T x) | 比較x與0的值,大於,等於,小於 分別返回 1.0 ,0.0,-1.0 |
| T floor(T x) | 返回<=x的最大整數 |
| T ceil(T x) | 返回>=等於x的最小整數 |
| T fract(T x) | 獲取x的小數部分 |
| T mod(T x, T y) T mod(T x, float y) |
取x,y的余數 |
| T min(T x, T y) T min(T x, float y) |
取x,y的最小值 |
| T max(T x, T y) T max(T x, float y) |
取x,y的最大值 |
| T clamp(T x, T minVal, T maxVal) T clamp(T x, float minVal,float maxVal) |
min(max(x, minVal), maxVal),返回值被限定在 minVal,maxVal之間 |
| T mix(T x, T y, T a) T mix(T x, T y, float a) |
取x,y的線性混合,x*(1-a)+y*a |
| T step(T edge, T x) T step(float edge, T x) |
如果 x<edge 返回 0.0 否則返回1.0 |
| T smoothstep(T edge0, T edge1, T x) T smoothstep(float edge0,float edge1, T x) |
如果x<edge0 返回 0.0 如果x>edge1返回1.0, 否則返回Hermite插值 |
角度&三角函數:
下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 說明 |
|---|---|
| T radians(T degrees) | 角度轉弧度 |
| T degrees(T radians) | 弧度轉角度 |
| T sin(T angle) | 正弦函數,角度是弧度 |
| T cos(T angle) | 余弦函數,角度是弧度 |
| T tan(T angle) | 正切函數,角度是弧度 |
| T asin(T x) | 反正弦函數,返回值是弧度 |
| T acos(T x) | 反余弦函數,返回值是弧度 |
| T atan(T y, T x) T atan(T y_over_x) |
反正切函數,返回值是弧度 |
指數函數:
下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 說明 |
|---|---|
| T pow(T x, T y) | 返回x的y次冪 xy |
| T exp(T x) | 返回x的自然指數冪 ex |
| T log(T x) | 返回x的自然對數 ln |
| T exp2(T x) | 返回2的x次冪 2x |
| T log2(T x) | 返回2為底的對數 log2 |
| T sqrt(T x) | 開根號 √x |
| T inversesqrt(T x) | 先開根號,在取倒數,就是 1/√x |
幾何函數:
下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 說明 |
|---|---|
| float length(T x) | 返回矢量x的長度 |
| float distance(T p0, T p1) | 返回p0 p1兩點的距離 |
| float dot(T x, T y) | 返回x y的點積 |
| vec3 cross(vec3 x, vec3 y) | 返回x y的叉積 |
| T normalize(T x) | 對x進行歸一化,保持向量方向不變但長度變為1 |
| T faceforward(T N, T I, T Nref) | 根據 矢量 N 與Nref 調整法向量 |
| T reflect(T I, T N) | 返回 I - 2 * dot(N,I) * N, 結果是入射矢量 I 關於法向量N的 鏡面反射矢量 |
| T refract(T I, T N, float eta) | 返回入射矢量I關於法向量N的折射矢量,折射率為eta |
矩陣函數:
mat可以為任意類型矩陣.
| 方法 | 說明 |
|---|---|
| mat matrixCompMult(mat x, mat y) | 將矩陣 x 和 y的元素逐分量相乘 |
向量函數:
下文中的 類型 T可以是 vec2, vec3, vec4, 且可以逐分量操作.
bvec指的是由bool類型組成的一個向量:
vec3 v3= vec3(0.,0.,0.); vec3 v3_1= vec3(1.,1.,1.); bvec3 aa= lessThan(v3,v3_1); //bvec3(true,true,true)
| 方法 | 說明 |
|---|---|
| bvec lessThan(T x, T y) | 逐分量比較x < y,將結果寫入bvec對應位置 |
| bvec lessThanEqual(T x, T y) | 逐分量比較 x <= y,將結果寫入bvec對應位置 |
| bvec greaterThan(T x, T y) | 逐分量比較 x > y,將結果寫入bvec對應位置 |
| bvec greaterThanEqual(T x, T y) | 逐分量比較 x >= y,將結果寫入bvec對應位置 |
| bvec equal(T x, T y) bvec equal(bvec x, bvec y) |
逐分量比較 x == y,將結果寫入bvec對應位置 |
| bvec notEqual(T x, T y) bvec notEqual(bvec x, bvec y) |
逐分量比較 x!= y,將結果寫入bvec對應位置 |
| bool any(bvec x) | 如果x的任意一個分量是true,則結果為true |
| bool all(bvec x) | 如果x的所有分量是true,則結果為true |
| bvec not(bvec x) | bool矢量的逐分量取反 |
紋理查詢函數:
圖像紋理有兩種 一種是平面2d紋理,另一種是盒紋理,針對不同的紋理類型有不同訪問方法.
紋理查詢的最終目的是從sampler中提取指定坐標的顏色信息. 函數中帶有Cube字樣的是指 需要傳入盒狀紋理. 帶有Proj字樣的是指帶投影的版本.
以下函數只在vertex shader中可用:
vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod); vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);
以下函數只在fragment shader中可用:
vec4 texture2D(sampler2D sampler, vec2 coord, float bias); vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias); vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias); vec4 textureCube(samplerCube sampler, vec3 coord, float bias);
在 vertex shader 與 fragment shader 中都可用:
vec4 texture2D(sampler2D sampler, vec2 coord);
vec4 texture2DProj(sampler2D sampler, vec3 coord); vec4 texture2DProj(sampler2D sampler, vec4 coord); vec4 textureCube(samplerCube sampler, vec3 coord);
官方的shader范例:
下面的shader如果你可以一眼看懂,說明你已經對glsl語言基本掌握了.
Vertex Shader:
uniform mat4 mvp_matrix; //透視矩陣 * 視圖矩陣 * 模型變換矩陣 uniform mat3 normal_matrix; //法線變換矩陣(用於物體變換后法線跟着變換) uniform vec3 ec_light_dir; //光照方向 attribute vec4 a_vertex; // 頂點坐標 attribute vec3 a_normal; //頂點法線 attribute vec2 a_texcoord; //紋理坐標 varying float v_diffuse; //法線與入射光的夾角 varying vec2 v_texcoord; //2d紋理坐標 void main(void) { //歸一化法線 vec3 ec_normal = normalize(normal_matrix * a_normal); //v_diffuse 是法線與光照的夾角.根據向量點乘法則,當兩向量長度為1是 乘積即cosθ值 v_diffuse = max(dot(ec_light_dir, ec_normal), 0.0); v_texcoord = a_texcoord; gl_Position = mvp_matrix * a_vertex; }
Fragment Shader:
precision mediump float;
uniform sampler2D t_reflectance;
uniform vec4 i_ambient;
varying float v_diffuse; varying vec2 v_texcoord; void main (void) { vec4 color = texture2D(t_reflectance, v_texcoord); //這里分解開來是 color*vec3(1,1,1)*v_diffuse + color*i_ambient //色*光*夾角cos + 色*環境光 gl_FragColor = color*(vec4(v_diffuse) + i_ambient); }




