GLSL 中文手冊(cè)

GLSL 代表 openGL Shading Language炸客,openGL 著色語(yǔ)言

GLSL 中文手冊(cè)

基本類型:

類型 說(shuō)明
void 空類型,即不返回任何值
bool 布爾類型 true,false
int 帶符號(hào)的整數(shù) signed integer
float 帶符號(hào)的浮點(diǎn)數(shù) floating scalar
vec2, vec3, vec4 n維浮點(diǎn)數(shù)向量 n-component floating point vector
bvec2, bvec3, bvec4 n維布爾向量 Boolean vector
ivec2, ivec3, ivec4 n維整數(shù)向量 signed integer vector
mat2, mat3, mat4 2x2, 3x3, 4x4 浮點(diǎn)數(shù)矩陣 float matrix
sampler2D 2D紋理 a 2D texture
samplerCube 盒紋理 cube mapped texture

基本結(jié)構(gòu)和數(shù)組:

類型 說(shuō)明
結(jié)構(gòu) struct type-name{} 類似c語(yǔ)言中的 結(jié)構(gòu)體
數(shù)組 float foo[3] glsl只支持1維數(shù)組,數(shù)組可以是結(jié)構(gòu)體的成員

向量的分量訪問(wèn):

glsl中的向量(vec2,vec3,vec4)往往有特殊的含義,比如可能代表了一個(gè)空間坐標(biāo)(x,y,z,w),或者代表了一個(gè)顏色(r,g,b,a),再或者代表一個(gè)紋理坐標(biāo)(s,t,p,q)
所以glsl提供了一些更人性化的分量訪問(wèn)方式.

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);

運(yùn)算符:

優(yōu)先級(jí)(越小越高) 運(yùn)算符 說(shuō)明 結(jié)合性
1 () 聚組:a*(b+c) N/A
2 [] () . ++ -- 數(shù)組下標(biāo)[],方法參數(shù)fun(arg1,arg2,arg3),屬性訪問(wèn)a.b,自增/減后綴a++ a-- L - R
3 ++ -- + - ! 自增/減前綴++a --a,正負(fù)號(hào)(一般正號(hào)不寫(xiě))a ,-a,取反!false R - L
4 * / 乘除數(shù)學(xué)運(yùn)算 L - R
5 + - 加減數(shù)學(xué)運(yùn)算 L - R
7 < > <= >= 關(guān)系運(yùn)算符 L - R
8 == != 相等性運(yùn)算符 L - R
12 && 邏輯與 L - R
13 ^^ 邏輯排他或(用處基本等于!=) L - R
14 || 邏輯或 L - R
15 ? : 三目運(yùn)算符 L - R
16 = += -= *= /= 賦值與復(fù)合賦值 L - R
17 , 順序分配運(yùn)算 L - R

ps 左值與右值:

左值:表示一個(gè)儲(chǔ)存位置,可以是變量,也可以是表達(dá)式,但表達(dá)式最后的結(jié)果必須是一個(gè)儲(chǔ)存位置.

右值:表示一個(gè)值, 可以是一個(gè)變量或者表達(dá)式再或者純粹的值.

操作符的優(yōu)先級(jí):決定含有多個(gè)操作符的表達(dá)式的求值順序凰棉,每個(gè)操作的優(yōu)先級(jí)不同.

操作符的結(jié)合性:決定相同優(yōu)先級(jí)的操作符是從左到右計(jì)算,還是從右到左計(jì)算。

基礎(chǔ)類型間的運(yùn)算:

glsl中,沒(méi)有隱式類型轉(zhuǎn)換,原則上glsl要求任何表達(dá)式左右兩側(cè)(l-value),(r-value)的類型必須一致 也就是說(shuō)以下表達(dá)式都是錯(cuò)誤的:

int a =2.0; //錯(cuò)誤,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;

下面來(lái)分別說(shuō)說(shuō)可能遇到的情況:

1.floatint:

float與float , int與int之間是可以直接運(yùn)算的,但float與int不行.它們需要進(jìn)行一次顯示轉(zhuǎn)換.即要么把float轉(zhuǎn)成int: int(1.0)
,要么把int轉(zhuǎn)成float: float(1) ,以下表達(dá)式都是正確的:

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.floatvec(向量) mat(矩陣):

vec,mat這些類型其實(shí)是由float復(fù)合而成的,當(dāng)它們與float運(yùn)算時(shí),其實(shí)就是在每一個(gè)分量上分別與float進(jìn)行運(yùn)算,這就是所謂的逐分量運(yùn)算.glsl里
大部分涉及vec,mat的運(yùn)算都是逐分量運(yùn)算,但也并不全是. 下文中就會(huì)講到特例.

逐分量運(yùn)算是線性的,這就是說(shuō) vec 與 float 的運(yùn)算結(jié)果是還是 vec.

int 與 vec,mat之間是不可運(yùn)算的, 因?yàn)関ec和mat中的每一個(gè)分量都是 float 類型的. 無(wú)法與int進(jìn)行逐分量計(jì)算.

下面枚舉了幾種 float 與 vec,mat 運(yùn)算的情況

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(向量):

兩向量間的運(yùn)算首先要保證操作數(shù)的階數(shù)都相同.否則不能計(jì)算.例如: vec3*vec2 vec4+vec3 等等都是不行的.

它們的計(jì)算方式是兩操作數(shù)在同位置上的分量分別進(jìn)行運(yùn)算,其本質(zhì)還是逐分量進(jìn)行的,這和上面所說(shuō)的float類型的
逐分量運(yùn)算可能有一點(diǎn)點(diǎn)差異,相同的是 vec 與 vec 運(yùn)算結(jié)果還是 vec, 且階數(shù)不變.

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)
image

3. vec(向量)mat(矩陣):

要保證操作數(shù)的階數(shù)相同,且vec與mat間只存在乘法運(yùn)算.

它們的計(jì)算方式和線性代數(shù)中的矩陣乘法相同,不是逐分量運(yùn)算.

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.)


向量與矩陣的乘法規(guī)則如下:

image
image

4. mat(矩陣)mat(矩陣):

要保證操作數(shù)的階數(shù)相同.

在mat與mat的運(yùn)算中, 除了乘法是線性代數(shù)中的矩陣乘法外.其余的運(yùn)算任為逐分量運(yùn)算.簡(jiǎn)單說(shuō)就是只有乘法是特殊的,其余都和vec與vec運(yùn)算類似.

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);

矩陣乘法規(guī)則如下:

image

變量限定符:

修飾符 說(shuō)明
none (默認(rèn)的可省略)本地變量,可讀可寫(xiě),函數(shù)的輸入?yún)?shù)既是這種類型
const 聲明變量或函數(shù)的參數(shù)為只讀類型
attribute 只能存在于vertex shader中,一般用于保存頂點(diǎn)或法線數(shù)據(jù),它可以在數(shù)據(jù)緩沖區(qū)中讀取數(shù)據(jù)
uniform 在運(yùn)行時(shí)shader無(wú)法改變uniform變量, 一般用來(lái)放置程序傳遞給shader的變換矩陣概作,材質(zhì)沪袭,光照參數(shù)等等.
varying 主要負(fù)責(zé)在vertex 和 fragment 之間傳遞變量

const:

和C語(yǔ)言類似,被const限定符修飾的變量初始化后不可變,除了局部變量,函數(shù)參數(shù)也可以使用const修飾符.但要注意的是結(jié)構(gòu)變量可以用const修飾,
但結(jié)構(gòu)中的字段不行.

const變量必須在聲明時(shí)就初始化 const vec3 v3 = vec3(0.,0.,0.)

局部變量只能使用const限定符.

函數(shù)參數(shù)只能使用const限定符.

struct light {
        vec4 color;
        vec3 pos;
        //const vec3 pos1; //結(jié)構(gòu)中的字段不可用const修飾會(huì)報(bào)錯(cuò).
    };
const light lgt = light(vec4(1.0), vec3(0.0)); //結(jié)構(gòu)變量可以用const修飾

attribute:

attribute變量是全局只讀的,它只能在vertex shader中使用,只能與浮點(diǎn)數(shù),向量或矩陣變量組合,
一般attribute變量用來(lái)放置程序傳遞來(lái)的模型頂點(diǎn),法線,顏色,紋理等數(shù)據(jù)它可以訪問(wèn)數(shù)據(jù)緩沖區(qū)
(還記得gl.vertexAttribPointer這個(gè)函數(shù)吧)

attribute vec4 a_Position;

uniform:

uniform變量是全局只讀的,在整個(gè)shader執(zhí)行完畢前其值不會(huì)改變,他可以和任意基本類型變量組合,
一般我們使用uniform變量來(lái)放置外部程序傳遞來(lái)的環(huán)境數(shù)據(jù)(如點(diǎn)光源位置,模型的變換矩陣等等)
這些數(shù)據(jù)在運(yùn)行中顯然是不需要被改變的.

uniform vec4 lightPosition;

varying:

varying類型變量是 vertex shader 與 fragment shader 之間的信使,一般我們?cè)?vertex shader 中修改它然后在fragment shader使用它,但不能在
fragment shader中修改它.

//頂點(diǎn)著色器
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中的一個(gè).不可復(fù)合.

函數(shù)參數(shù)限定符:

函數(shù)的參數(shù)默認(rèn)是以拷貝的形式傳遞的,也就是值傳遞,任何傳遞給函數(shù)參數(shù)的變量,其值都會(huì)被復(fù)制一份,然后再交給函數(shù)內(nèi)部進(jìn)行處理.
我們可以為參數(shù)添加限定符來(lái)達(dá)到傳遞引用的目的,glsl中提供的參數(shù)限定符如下:

限定符 說(shuō)明
< none: default > 默認(rèn)使用 in 限定符
in 復(fù)制到函數(shù)中在函數(shù)中可讀寫(xiě)
out 返回時(shí)從函數(shù)中復(fù)制出來(lái)
inout 復(fù)制到函數(shù)中并在返回時(shí)復(fù)制出來(lái)

in 是函數(shù)參數(shù)的默認(rèn)限定符,最終真正傳入函數(shù)形參的其實(shí)是實(shí)參的一份拷貝.在函數(shù)中,修改in修飾的形參不會(huì)影響到實(shí)參變量本身.

out 它的作用是向函數(shù)外部傳遞新值,out模式下傳遞進(jìn)來(lái)的參數(shù)是write-only的(可寫(xiě)不可讀).就像是一個(gè)"坑位",坑位中的值需要函數(shù)給他賦予.
在函數(shù)中,修改out修飾的形參會(huì)影響到實(shí)參本身.

inout inout下,形參可以被理解為是一個(gè)帶值的"坑位",及可讀也可寫(xiě),在函數(shù)中,修改inout修飾的形參會(huì)影響到實(shí)參本身.

glsl的函數(shù):

glsl允許在程序的最外部聲明函數(shù).函數(shù)不能嵌套,不能遞歸調(diào)用,且必須聲明返回值類型(無(wú)返回值時(shí)聲明為void) 在其他方面glsl函數(shù)與c函數(shù)非常類似.

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;
}

構(gòu)造函數(shù):

glsl中變量可以在聲明的時(shí)候初始化,float pSize = 10.0 也可以先聲明然后等需要的時(shí)候在進(jìn)行賦值.

聚合類型對(duì)象如(向量,矩陣,數(shù)組,結(jié)構(gòu)) 需要使用其構(gòu)造函數(shù)來(lái)進(jìn)行初始化. vec4 color = vec4(0.0, 1.0, 0.0, 1.0);

//一般類型
float pSize = 10.0;
float pSize1;
pSize1=10.0;
...

//復(fù)合類型
vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
vec4 color1;
color1 =vec4(0.0, 1.0, 0.0, 1.0);
...

//結(jié)構(gòu)
struct light {
    float intensity;
    vec3 position;
};
light lightVar = light(3.0, vec3(1.0, 2.0, 3.0));

//數(shù)組
const float c[3] = float[3](5.0, 7.2, 1.1);

類型轉(zhuǎn)換:

glsl可以使用構(gòu)造函數(shù)進(jìn)行顯式類型轉(zhuǎn)換,各值如下:

bool t= true;
bool f = false;

int a = int(t); //true轉(zhuǎn)換為1或1.0
int a1 = int(f);//false轉(zhuǎn)換為0或0.0

float b = float(t);
float b1 = float(f);

bool c = bool(0);//0或0.0轉(zhuǎn)換為false
bool c1 = bool(1);//非0轉(zhuǎn)換為true

bool d = bool(0.0);
bool d1 = bool(1.0);

精度限定:

glsl在進(jìn)行光柵化著色的時(shí)候,會(huì)產(chǎn)生大量的浮點(diǎn)數(shù)運(yùn)算,這些運(yùn)算可能是當(dāng)前設(shè)備所不能承受的,所以glsl提供了3種浮點(diǎn)數(shù)精度,我們可以根據(jù)不同的設(shè)備來(lái)使用合適的精度.

在變量前面加上 highp mediump lowp 即可完成對(duì)該變量的精度聲明.

lowp float color;
varying mediump vec2 Coord;
lowp ivec2 foo(lowp mat3);
highp mat4 m;

我們一般在片元著色器(fragment shader)最開(kāi)始的地方加上 precision mediump float; 便設(shè)定了默認(rèn)的精度.這樣所有沒(méi)有顯式表明精度的變量
都會(huì)按照設(shè)定好的默認(rèn)精度來(lái)處理.

如何確定精度:

變量的精度首先是由精度限定符決定的,如果沒(méi)有精度限定符,則要尋找其右側(cè)表達(dá)式中,已經(jīng)確定精度的變量,一旦找到,那么整個(gè)表達(dá)式都將在該精度下運(yùn)行.如果找到多個(gè),
則選擇精度較高的那種,如果一個(gè)都找不到,則使用默認(rèn)或更大的精度類型.

uniform highp float h1;
highp float h2 = 2.3 * 4.7; //運(yùn)算過(guò)程和結(jié)果都 是高精度
mediump float m;
m = 3.7 * h1 * h2; //運(yùn)算過(guò)程 是高精度
h2 = m * h1; //運(yùn)算過(guò)程 是高精度
m = h2 – h1; //運(yùn)算過(guò)程 是高精度
h2 = m + m; //運(yùn)算過(guò)程和結(jié)果都 是中等精度
void f(highp float p); // 形參 p 是高精度
f(3.3); //傳入的 3.3是高精度


invariant關(guān)鍵字:

由于shader在編譯時(shí)會(huì)進(jìn)行一些內(nèi)部?jī)?yōu)化,可能會(huì)導(dǎo)致同樣的運(yùn)算在不同shader里結(jié)果不一定精確相等.這會(huì)引起一些問(wèn)題,尤其是vertx shader向fragmeng shader傳值的時(shí)候.
所以我們需要使用invariant 關(guān)鍵字來(lái)顯式要求計(jì)算結(jié)果必須精確一致. 當(dāng)然我們也可使用 #pragma STDGL invariant(all)來(lái)命令所有輸出變量必須精確一致,
但這樣會(huì)限制編譯器優(yōu)化程度,降低性能.

#pragma STDGL invariant(all) //所有輸出變量為 invariant
invariant varying texCoord; //varying在傳遞數(shù)據(jù)的時(shí)候聲明為invariant

限定符的順序:

當(dāng)需要用到多個(gè)限定符的時(shí)候要遵循以下順序:

1.在一般變量中: invariant > storage > precision

2.在參數(shù)中: storage > parameter > precision

我們來(lái)舉例說(shuō)明:

invariant varying lowp float color; // invariant > storage > precision

void doubleSize(const in lowp float s){ //storage > parameter > precision
    float s1=s;
}

預(yù)編譯指令:

以 # 開(kāi)頭的是預(yù)編譯指令,常用的有:

#define #undef #if #ifdef #ifndef #else
#elif #endif #error #pragma #extension #version #line

比如 #version 100 他的意思是規(guī)定當(dāng)前shader使用 GLSL ES 1.00標(biāo)準(zhǔn)進(jìn)行編譯,如果使用這條預(yù)編譯指令,則他必須出現(xiàn)在程序的最開(kāi)始位置.

內(nèi)置的宏:

__LINE__ : 當(dāng)前源碼中的行號(hào).

__VERSION__ : 一個(gè)整數(shù),指示當(dāng)前的glsl版本 比如 100 ps: 100 = v1.00

GL_ES : 如果當(dāng)前是在 OPGL ES 環(huán)境中運(yùn)行則 GL_ES 被設(shè)置成1,一般用來(lái)檢查當(dāng)前環(huán)境是不是 OPENGL ES.

GL_FRAGMENT_PRECISION_HIGH : 如果當(dāng)前系統(tǒng)glsl的片元著色器支持高浮點(diǎn)精度,則設(shè)置為1.一般用于檢查著色器精度.

實(shí)例:

1.如何通過(guò)判斷系統(tǒng)環(huán)境,來(lái)選擇合適的精度:

#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

內(nèi)置的特殊變量

glsl程序使用一些特殊的內(nèi)置變量與硬件進(jìn)行溝通.他們大致分成兩種 一種是 input類型,他負(fù)責(zé)向硬件(渲染管線)發(fā)送數(shù)據(jù).
另一種是output類型,負(fù)責(zé)向程序回傳數(shù)據(jù),以便編程時(shí)需要.

在 vertex Shader 中:

output 類型的內(nèi)置變量:

變量 說(shuō)明 單位
highp vec4 gl_Position; gl_Position 放置頂點(diǎn)坐標(biāo)信息 vec4
mediump float gl_PointSize; gl_PointSize 需要繪制點(diǎn)的大小,(只在gl.POINTS模式下有效) float

在 fragment Shader 中:

input 類型的內(nèi)置變量:

變量 說(shuō)明 單位
mediump vec4 gl_FragCoord; 片元在framebuffer畫(huà)面的相對(duì)位置 vec4
bool gl_FrontFacing; 標(biāo)志當(dāng)前圖元是不是正面圖元的一部分 bool
mediump vec2 gl_PointCoord; 經(jīng)過(guò)插值計(jì)算后的紋理坐標(biāo),點(diǎn)的范圍是0.0到1.0 vec2

output 類型的內(nèi)置變量:

變量 說(shuō)明 單位
mediump vec4 gl_FragColor; 設(shè)置當(dāng)前片點(diǎn)的顏色 vec4 RGBA color
mediump vec4 gl_FragData[n] 設(shè)置當(dāng)前片點(diǎn)的顏色,使用glDrawBuffers數(shù)據(jù)數(shù)組 vec4 RGBA color

內(nèi)置的常量

glsl提供了一些內(nèi)置的常量,用來(lái)說(shuō)明當(dāng)前系統(tǒng)的一些特性. 有時(shí)我們需要針對(duì)這些特性,對(duì)shader程序進(jìn)行優(yōu)化,讓程序兼容度更好.

在 vertex Shader 中:

1.const mediump int gl_MaxVertexAttribs>=8

gl_MaxVertexAttribs 表示在vertex shader(頂點(diǎn)著色器)中可用的最大attributes數(shù).這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 8 個(gè).

2.const mediump int gl_MaxVertexUniformVectors >= 128

gl_MaxVertexUniformVectors 表示在vertex shader(頂點(diǎn)著色器)中可用的最大uniform vectors數(shù). 這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 128 個(gè).

3.const mediump int gl_MaxVaryingVectors >= 8

gl_MaxVaryingVectors 表示在vertex shader(頂點(diǎn)著色器)中可用的最大varying vectors數(shù). 這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 8 個(gè).

4.const mediump int gl_MaxVertexTextureImageUnits >= 0

gl_MaxVaryingVectors 表示在vertex shader(頂點(diǎn)著色器)中可用的最大紋理單元數(shù)(貼圖). 這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
甚至可以一個(gè)都沒(méi)有(無(wú)法獲取頂點(diǎn)紋理)

5.const mediump int gl_MaxCombinedTextureImageUnits >= 8

gl_MaxVaryingVectors 表示在 vertex Shader和fragment Shader總共最多支持多少個(gè)紋理單元. 這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 8 個(gè).

在 fragment Shader 中:

1.const mediump int gl_MaxTextureImageUnits >= 8

gl_MaxVaryingVectors 表示在 fragment Shader(片元著色器)中能訪問(wèn)的最大紋理單元數(shù),這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 8 個(gè).

2.const mediump int gl_MaxFragmentUniformVectors >= 16

gl_MaxFragmentUniformVectors 表示在 fragment Shader(片元著色器)中可用的最大uniform vectors數(shù),這個(gè)值的大小取決于 OpenGL ES 在某設(shè)備上的具體實(shí)現(xiàn),
不過(guò)最低不能小于 16 個(gè).

3.const mediump int gl_MaxDrawBuffers = 1

gl_MaxDrawBuffers 表示可用的drawBuffers數(shù),在OpenGL ES 2.0中這個(gè)值為1, 在將來(lái)的版本可能會(huì)有所變化.

glsl中還有一種內(nèi)置的uniform狀態(tài)變量, gl_DepthRange 它用來(lái)表明全局深度范圍.

結(jié)構(gòu)如下:

struct gl_DepthRangeParameters {
 highp float near; // n
 highp float far; // f
 highp float diff; // f - n
 };
 uniform gl_DepthRangeParameters gl_DepthRange;

除了 gl_DepthRange 外的所有uniform狀態(tài)常量都已在glsl 1.30 中廢棄.

流控制

glsl的流控制和c語(yǔ)言非常相似,這里不必再做過(guò)多說(shuō)明,唯一不同的是片段著色器中有一種特殊的控制流discard.
使用discard會(huì)退出片段著色器解愤,不執(zhí)行后面的片段著色操作。片段也不會(huì)寫(xiě)入幀緩沖區(qū)乎莉。

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;


內(nèi)置函數(shù)庫(kù)

glsl提供了非常豐富的函數(shù)庫(kù),供我們使用,這些功能都是非常有用且會(huì)經(jīng)常用到的. 這些函數(shù)按功能區(qū)分大改可以分成7類:

通用函數(shù):

下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法 說(shuō)明
T abs(T x) 返回x的絕對(duì)值
T sign(T x) 比較x與0的值,大于,等于,小于 分別返回 1.0 ,0.0,-1.0
T floor(T x) 返回<=x的最大整數(shù)
T ceil(T x) 返回>=等于x的最小整數(shù)
T fract(T x) 獲取x的小數(shù)部分
T mod(T x, T y)
T mod(T x, float y)
取x,y的余數(shù)
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插值

角度&三角函數(shù):

下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法 說(shuō)明
T radians(T degrees) 角度轉(zhuǎn)弧度
T degrees(T radians) 弧度轉(zhuǎn)角度
T sin(T angle) 正弦函數(shù),角度是弧度
T cos(T angle) 余弦函數(shù),角度是弧度
T tan(T angle) 正切函數(shù),角度是弧度
T asin(T x) 反正弦函數(shù),返回值是弧度
T acos(T x) 反余弦函數(shù),返回值是弧度
T atan(T y, T x)
T atan(T y_over_x)
反正切函數(shù),返回值是弧度

指數(shù)函數(shù):

下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法 說(shuō)明
T pow(T x, T y) 返回x的y次冪 xy
T exp(T x) 返回x的自然指數(shù)冪 ex
T log(T x) 返回x的自然對(duì)數(shù) ln
T exp2(T x) 返回2的x次冪 2x
T log2(T x) 返回2為底的對(duì)數(shù) log2
T sqrt(T x) 開(kāi)根號(hào) √x
T inversesqrt(T x) 先開(kāi)根號(hào),在取倒數(shù),就是 1/√x

幾何函數(shù):

下文中的 類型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法 說(shuō)明
float length(T x) 返回矢量x的長(zhǎng)度
float distance(T p0, T p1) 返回p0 p1兩點(diǎn)的距離
float dot(T x, T y) 返回x y的點(diǎn)積
vec3 cross(vec3 x, vec3 y) 返回x y的叉積
T normalize(T x) 對(duì)x進(jìn)行歸一化,保持向量方向不變但長(zhǎng)度變?yōu)?
T faceforward(T N, T I, T Nref) 根據(jù) 矢量 N 與Nref 調(diào)整法向量
T reflect(T I, T N) 返回 I - 2 * dot(N,I) * N, 結(jié)果是入射矢量 I 關(guān)于法向量N的 鏡面反射矢量
T refract(T I, T N, float eta) 返回入射矢量I關(guān)于法向量N的折射矢量,折射率為eta

矩陣函數(shù):

mat可以為任意類型矩陣.

方法 說(shuō)明
mat matrixCompMult(mat x, mat y) 將矩陣 x 和 y的元素逐分量相乘

向量函數(shù):

下文中的 類型 T可以是 vec2, vec3, vec4, 且可以逐分量操作.

bvec指的是由bool類型組成的一個(gè)向量:

vec3 v3= vec3(0.,0.,0.);
vec3 v3_1= vec3(1.,1.,1.);
bvec3 aa= lessThan(v3,v3_1); //bvec3(true,true,true)

方法 說(shuō)明
bvec lessThan(T x, T y) 逐分量比較x < y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bvec lessThanEqual(T x, T y) 逐分量比較 x <= y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bvec greaterThan(T x, T y) 逐分量比較 x > y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bvec greaterThanEqual(T x, T y) 逐分量比較 x >= y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bvec equal(T x, T y)
bvec equal(bvec x, bvec y)
逐分量比較 x == y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bvec notEqual(T x, T y)
bvec notEqual(bvec x, bvec y)
逐分量比較 x!= y,將結(jié)果寫(xiě)入bvec對(duì)應(yīng)位置
bool any(bvec x) 如果x的任意一個(gè)分量是true,則結(jié)果為true
bool all(bvec x) 如果x的所有分量是true,則結(jié)果為true
bvec not(bvec x) bool矢量的逐分量取反

紋理查詢函數(shù):

圖像紋理有兩種 一種是平面2d紋理,另一種是盒紋理,針對(duì)不同的紋理類型有不同訪問(wèn)方法.

紋理查詢的最終目的是從sampler中提取指定坐標(biāo)的顏色信息. 函數(shù)中帶有Cube字樣的是指 需要傳入盒狀紋理. 帶有Proj字樣的是指帶投影的版本.

以下函數(shù)只在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);

以下函數(shù)只在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如果你可以一眼看懂,說(shuō)明你已經(jīng)對(duì)glsl語(yǔ)言基本掌握了.

Vertex Shader:

uniform mat4 mvp_matrix; //透視矩陣 * 視圖矩陣 * 模型變換矩陣
uniform mat3 normal_matrix; //法線變換矩陣(用于物體變換后法線跟著變換)
uniform vec3 ec_light_dir; //光照方向
attribute vec4 a_vertex; // 頂點(diǎn)坐標(biāo)
attribute vec3 a_normal; //頂點(diǎn)法線
attribute vec2 a_texcoord; //紋理坐標(biāo)
varying float v_diffuse; //法線與入射光的夾角
varying vec2 v_texcoord; //2d紋理坐標(biāo)
void main(void)
{
 //歸一化法線
 vec3 ec_normal = normalize(normal_matrix * a_normal);
 //v_diffuse 是法線與光照的夾角.根據(jù)向量點(diǎn)乘法則,當(dāng)兩向量長(zhǎng)度為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);
 //這里分解開(kāi)來(lái)是 color*vec3(1,1,1)*v_diffuse + color*i_ambient
 //色*光*夾角cos + 色*環(huán)境光
 gl_FragColor = color*(vec4(v_diffuse) + i_ambient);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末送讲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惋啃,更是在濱河造成了極大的恐慌哼鬓,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件边灭,死亡現(xiàn)場(chǎng)離奇詭異异希,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绒瘦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門称簿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)扣癣,“玉大人,你說(shuō)我怎么就攤上這事憨降「嘎牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵授药,是天一觀的道長(zhǎng)频轿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)烁焙,這世上最難降的妖魔是什么航邢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮骄蝇,結(jié)果婚禮上膳殷,老公的妹妹穿的比我還像新娘。我一直安慰自己九火,他們只是感情好赚窃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著岔激,像睡著了一般勒极。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虑鼎,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天辱匿,我揣著相機(jī)與錄音,去河邊找鬼炫彩。 笑死匾七,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的江兢。 我是一名探鬼主播昨忆,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼杉允!你這毒婦竟也來(lái)了邑贴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叔磷,失蹤者是張志新(化名)和其女友劉穎拢驾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體世澜,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡独旷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌洼。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡案疲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出麻养,到底是詐尸還是另有隱情褐啡,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布鳖昌,位于F島的核電站备畦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏许昨。R本人自食惡果不足惜懂盐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糕档。 院中可真熱鬧莉恼,春花似錦、人聲如沸速那。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)端仰。三九已至捶惜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荔烧,已是汗流浹背吱七。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茴晋,地道東北人陪捷。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诺擅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啡直,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容