GLSL語法基礎



簡介

GLSLOpenGL 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 布爾類型truefalse,以及可以產生布爾型的表達式。
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 重復了。下面是用法舉例: 例如有向量 v1v2:

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 間的運算:**

floatint 之間進行運算,需要進行一次顯示轉換,以下表達式都是正確的:

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

intvec,mat 之間是不可運算的,因為 vecmat 中的每一個分量都是 float 類型的,無法與 int 進行逐分量計算。

下面枚舉了幾種 floatvec,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\*vec2vec4+vec3 等等都是不行的。

它們的計算方式是兩操作數在同位置上的分量分別進行運算,其本質還是逐分量進行的,這和上面所說的 float 類型的逐分量運算可能有一點點差異,相同的是 vecvec 運算結果還是 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(矩陣):

要保證操作數的階數相同,且 vecmat 間只存在乘法運算。 它們的計算方式和線性代數中的矩陣乘法相同,不是逐分量運算

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(矩陣):

要保證操作數的階數相同。

matmat 的運算中,除了乘法是線性代數中的矩陣乘法外,其余的運算仍為逐分量運算。簡單說就是只有乘法是特殊的,其余都和 vecvec 運算類似。

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 頂點着色器的輸出,主要負責在 vertexfragment 之間傳遞變量。例如顏色或者紋理坐標,(插值后的數據)作為片段着色器的只讀輸入數據。必須是全局范圍聲明的全局變量。可以是浮點數類型的標量,向量,矩陣。不能是數組或者結構體。
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);

相關鏈接

GLSL-Card

https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf

https://www.khronos.org/registry/OpenGL-Refpages/gl4/

GLSL基礎

着色語言 GLSL 語法介紹

1、作者吃代碼的兔子窩的《初探 GLSL 着色器(一)》

[3、作者吃代碼的兔子窩的《初探 GLSL 着色器(二)》](

3、作者吃代碼的兔子窩的《初探 GLSL 着色器(二)》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM