簡介
GLSL
(OpenGL Shading Language) 全稱 OpenGL 着色語言,是用來在 OpenGL 中着色編程的語言,也即開發人員寫的短小的自定義程序,他們是在圖形卡的 GPU上執行的,代替了固定的渲染管線的一部分,使渲染管線中不同層次具有可編程性。 GLSL
其使用 C 語言作為基礎高階着色語言,避免了使用匯編語言或硬件規格語言的復雜性。
基礎語法
注釋
單行注釋:// 多行注釋:/* */
變量命名
GLSL的變量命名方式與C語言類似。變量的名稱可以使用字母,數字以及下划線,但變量名不能以數字開頭,還有變量名不能以gl_作為前綴,這個是GLSL保留的前綴,用於GLSL的內部變量。當然還有一些GLSL保留的名稱是不能夠作為變量的名稱的。
變量命名
GLSL
的變量命名方式與 C 語言類似,可使用字母,數字以及下划線,不能以數字開頭。還需要注意的是,變量名不能以 gl_
作為前綴,這個是 GLSL
保留的前綴,用於 GLSL
的內部變量。
表達式
運算符
優先級(越小越高) | 運算符 | 說明 | 結合性 |
---|---|---|---|
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 | II | 邏輯或 | L - R |
15 | ? : | 三目運算符 | L - R |
16 | = += -= *= /= | 賦值與復合賦值 | L - R |
17 | , | 順序分配運算 | L - R |
左值與右值:
左值:表示一個儲存位置,可以是變量,也可以是表達式,但表達式最后的結果必須是一個儲存位置.
右值:表示一個值, 可以是一個變量或者表達式再或者純粹的值.
操作符的優先級:決定含有多個操作符的表達式的求值順序,每個操作的優先級不同.
操作符的結合性:決定相同優先級的操作符是從左到右計算,還是從右到左計算。
操作符
GLSL語言的操作符與C語言相似。如下表(操作符的優先級從高到低排列)
操作符 | 描述 |
---|---|
() | 用於表達式組合,函數調用,構造 |
[] | 數組下標,向量或矩陣的選擇器 |
. | 結構體和向量的成員選擇 |
++ -- | 前綴或后綴的自增自減操作符 |
+ – ! | 一元操作符,表示正 負 邏輯非 |
* / | 乘 除操作符 |
+ - | 二元操作符 表示加 減操作 |
<> <= >= == != | 小於,大於,小於等於, 大於等於,等於,不等於 判斷符 |
&& || ^^ | 邏輯與 ,或, 異或 |
?: | 條件判斷符 |
= += –= *= /= | 賦值操作符 |
, | 表示序列 |
求地址的& 和 解引用的 * 操作符不再GLSL中出現,因為GLSL不能直接操作地址。
類型轉換操作也是不允許的。
位操作符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操作符,將來可能會被使用。
求模操作(%,%=)也是保留的。
數組訪問
數組的下標從0開始。合理的范圍是[0, size - 1]。跟C語言一樣。如果數組訪問越界了,那行為是未定義的。如果着色器的編譯器在編譯時知道數組訪問越界了,就會提示編譯失敗。
vec4 myColor, ambient, diffuse[6], specular[6];
myColor = ambient + diffuse[4] + specular[4];
語句
流控制
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;
discard
片段着色器中有一種特殊的控制流成為discard。使用discard會退出片段着色器,不執行后面的片段着色操作。片段也不會寫入幀緩沖區。
if (ture)
discard;
分量訪問
分量訪問符 | 符號描述 |
---|---|
(x,y,z,w) | 與位置相關的分量 |
(r,g,b,a) | 與顏色相關的分量 |
(s,t,p,q) | 與紋理坐標相關的分量 |
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預編譯指令
以 # 開頭的是預編譯指令,常用的有:
#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
數據類型
基礎數據類型
類型 | 描述 |
---|---|
void | 跟 C 語言的 void 類似,表示空類型。作為函數的返回類型,表示這個函數不返回值。 |
bool | 布爾類型,true 或 false,以及可以產生布爾型的表達式。 |
int | 有符號整型 |
uint | 無符號整形 |
float | 浮點型 |
紋理采樣類型
類型 | 描述 |
---|---|
sampler1D | 用於內建的紋理函數中引用指定的 1D紋理的句柄。只可以作為一致變量或者函數參數使用 |
sampler2D | 二維紋理句柄 |
sampler3D | 三維紋理句柄 |
samplerCube | cube map 紋理句柄 |
sampler1DShadow | 一維深度紋理句柄 |
sampler2DShadow | 二維深度紋理句柄 |
聚合類型(向量和矩陣類型)
向量類型
類型 | 描述 |
---|---|
vec2,vec3,vec4 | 2分量、3分量和4分量浮點向量 |
ivec2,ivec3,ivec4 | 2分量、3分量和4分量整數向量 |
uvec2,uvec3,uvec4 | 2分量、3分量和4分量無符號整數向量 |
bvec2,vbec3,bvec4 | 2分量、3分量和4分量布爾向量 |
A、向量聲明--4分量的float 類型向量
vec4 V1;
B、聲明向量並對其進行構造
vec4 V2 = vec4(1,2,3,4);
C、向量運算
vec4 v;
vec4 vOldPos = vec4(1,2,3,4);
vec4 vOffset = vec4(1,2,3,4);
//注意:接下來假設所有參與運算的變量已定義並賦值。
v = vOldPos + vOffset;
v = vNewPos;
v += vec4(10,10,10,10);
v = vOldPos * vOffset;
v *= 5;
D、向量元素的獲取(成分選擇)
向量中單獨的成分可以通過 {x,y,z,w}, {r,g,b,a} 或者 {s,t,p,q} 的記法來表示。這些不同的記法用於 頂點,顏色,紋理坐標。在成分選擇中,你不可以混合使用這些記法。其中 {s,t,p,q} 中的 p 替換了紋理的 r 坐標,因為與顏色 r 重復了。下面是用法舉例: 例如有向量 v1 和 v2:
vec3 v1 = {0.5, 0.35, 0.7};
vec4 v2 = {0.1, 0.2, 0.3, 0.4};
可以通過 {x,y,z,w}, {r,g,b,a} 或者 {s,t,p,q} 來取出向量中的元素值。 通過 x,y,z,w:
v2.x = 3.0f;
v2.xy = vec2(3.0f,4.0f);
v2.xyz = vec3(3,0f,4,0f,5.0f);
通過 r,g,b,a:
v2.r = 3.0f;
v2.rgba = vec4(1.0f,1.0f,1.0f,1.0f);
通過 s,t,q,r:
v2.stqr = vec2(1.0f, 0.0f, 0.0f, 1.0f);
錯誤示例:
float myQ = v1.q;// 出錯,數組越界訪問,q代表第四個元素
float myRY = v1.ry; // 不合法,混合使用記法
向量還支持一次性對所有分量操作
v1.x = v2.x +5.0f;
v1.y = v2.y +4.0f;
v1.z = v2.z +3.0f;
v1.xyz = v2.xyz + vec3(5.0f,4.0f,3.0f);
(2)矩陣類型
類型 | 描述 |
---|---|
mat2 或 mat2x2 | 2x2的浮點數矩陣類型 |
mat3 或 mat3x3 | 3x3的浮點數矩陣類型 |
mat4 或 mat4x4 | 4x4的浮點數矩陣類型 |
mat2x3 | 2列3行的浮點矩陣(OpenGL的矩陣是列主順序的) |
mat2x4 | 2列4行的浮點矩陣 |
mat3x2 | 3列2行的浮點矩陣 |
mat3x4 | 3列4行的浮點矩陣 |
mat4x2 | 4列2行的浮點矩陣 |
mat4x3 | 4列3行的浮點矩陣 |
創建矩陣:
mat4 m1,m2,m3;
構造單元矩陣:
mat4 m2 = mat4(1.0f,0.0f,0.0f,0.0f
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f);
或者
mat4 m4 = mat4(1.0f);
向量矩陣運算
1、不同類型 float 與 int 間的運算:**
float 與 int 之間進行運算,需要進行一次顯示轉換,以下表達式都是正確的:
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);
AB=[a1,1a1,2a2,1a2,2][b1,1b1,2b2,1b2,2]=[a1,1b1,1+a1,2b2,1a1,1b1,2+a1,2b2,2a2,1b1,1+a2,2b2,1a2,1b1,2+a2,2b2,2]
4、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.)
5、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);
結構體
結構體可以組合基本類型和數組來形成用戶自定義的類型。在定義一個結構體的同時,你可以定義一個結構體實例。或者后面再定義。
struct fogStruct {
vec4 color;
float start;
float end;
vec3 points[3]; // 固定大小的數組是合法的
} fogVar;
可以通過 = 為結構體賦值,或者使用 ==,!= 來判斷兩個結構體是否相等。
fogVar = fogStruct(vec4(1.0,0.0,0.0,1.0),0.5,2.0);
vec4 color = fogVar.color;
float start = fogVar.start;
構造函數
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
中只可以使用一維的數組。數組的類型可以是一切基本類型或者結構體。下面的幾種數組聲明是合法的:
float floatArray[4];
vec4 vecArray[2];
float a[4] = float[](1.0,2.0,3.0,4.0);
vec2 c[2] = vec2[2](vec2(1.0,2.0),vec2(3.0,4.0));
數組類型內建了一個length()
函數,可以返回數組的長度。
lightPositions.length() // 返回數組的長度
類型轉換
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要求任何表達式左右兩側(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;
精度限定
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;
}
修飾符
1、變量存儲限定符
限定符 | 描述 |
---|---|
(默認的可省略)只是普通的本地變量,可讀可寫,外部不可見,外部不可訪問 | |
const | 常量值必須在聲明時初始化,它是只讀的不可修改的 |
varying | 頂點着色器的輸出,主要負責在 vertex 和 fragment 之間傳遞變量。例如顏色或者紋理坐標,(插值后的數據)作為片段着色器的只讀輸入數據。必須是全局范圍聲明的全局變量。可以是浮點數類型的標量,向量,矩陣。不能是數組或者結構體。 |
uniform | 一致變量。在着色器執行期間一致變量的值是不變的。與 const 常量不同的是,這個值在編譯時期是未知的是由着色器外部初始化的。一致變量在頂點着色器和片段着色器之間是共享的。它也只能在全局范圍進行聲明。 |
attribute | 表示只讀的頂點數據,只用在頂點着色器中。數據來自當前的頂點狀態或者頂點數組。它必須是全局范圍聲明的,不能再函數內部。一個 attribute 可以是浮點數類型的標量,向量,或者矩陣。不可以是數組或則結構體 |
centorid varying | 在沒有多重采樣的情況下,與 varying 是一樣的意思。在多重采樣時,centorid varying 在光柵化的圖形內部進行求值而不是在片段中心的固定位置求值。 |
invariant | (不變量)用於表示頂點着色器的輸出和任何匹配片段着色器的輸入,在不同的着色器中計算產生的值必須是一致的。所有的數據流和控制流,寫入一個 invariant 變量的是一致的。編譯器為了保證結果是完全一致的,需要放棄那些可能會導致不一致值的潛在的優化。除非必要,不要使用這個修飾符。在多通道渲染中避免 z-fighting 可能會使用到。 |
2、函數參數限定符
GLSL
允許自定義函數,但參數默認是以值形式(in
限定符)傳入的,也就是說任何變量在傳入時都會被拷貝一份,若想以引用方式傳參,需要增加函數參數限定符。
限定符 | 描述 |
---|---|
in | 用在函數的參數中,表示這個參數是輸入的,在函數中改變這個值,並不會影響對調用的函數產生副作用。(相當於C語言的傳值),這個是函數參數默認的修飾符 |
out | 用在函數的參數中,表示該參數是輸出參數,值是會改變的。 |
inout | 用在函數的參數,表示這個參數即是輸入參數也是輸出參數。 |
其中使用 inout 方式傳遞的參數便與其他 OOP 語言中的引用傳遞類似,參數可讀寫,函數內對參數的修改會影響到傳入參數本身。 eg:
vec4 getPosition(out vec4 p){
p = vec4(0.,0.,0.,1.);
return v4;
}
void doubleSize(inout float size){
size= size * 3.0 ;
}
內置變量和函數
內置變量
內置變量可以與固定函數功能進行交互。在使用前不需要聲明。
頂點着色器可用的內置變量
名稱 | 類型 | 描述 |
---|---|---|
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 | 輸出的深度用於隨后的像素操作,如果這個值沒有被寫,則使用固定功能管線的深度值代替 |
內置函數
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)+ya |
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);
相關鏈接
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf
https://www.khronos.org/registry/OpenGL-Refpages/gl4/
[3、作者吃代碼的兔子窩的《初探 GLSL 着色器(二)》](