在OpenGL ES中著色器分為頂點著色器和片元著色器幼苛。頂點著色器是針對每個頂點執(zhí)行一次绿饵,用于確定頂點的位置。片元著色器是針對每個片元俯逾,片元我們可以理解為每個像素程腹,用于確定每個片元(像素)的顏色匣吊。
一、GLSL 簡介
GLSL又叫OpenGL著色語言(OpenGL Shading Language),是用來在OpenGL中著色編程的語言色鸳,是一種面向過程的語言社痛,基本的語法和C/C++基本相同,他們是在圖形卡的GPU (Graphic Processor Unit圖形處理單元)上執(zhí)行的命雀,代替了固定的渲染管線的一部分蒜哀,使渲染管線中不同層次具有可編程性。比如:視圖轉換吏砂、投影轉換等撵儿。GLSL(GL Shading Language)的著色器代碼分成2個部分:Vertex Shader(頂點著色器)和Fragment(片斷著色器)。
二狐血、GLSL 基礎
GLSL 雖然很類似于C/C++淀歇,但是它和C/C++還是有很大的不同的,比如氛雪,沒有double,long等類型耸成,沒有union报亩、enum、unsigned以及位運算等特性井氢。
基本數(shù)據(jù)類型
GLSL中的數(shù)據(jù)類型主要分為標量弦追、向量、矩陣花竞、采樣器劲件、結構體、數(shù)組约急、空類型七種類型:
- 標量
標量表示的是只有大小沒有方向的量零远,在GLSL中標量只有bool、int和float三種厌蔽。對于int牵辣,和C一樣,可以寫為十進制(16)奴饮、八進制(020)或者十六進制(0x10)纬向。對于標量的運算,我們最需要注意的是精度戴卜,防止溢出問題逾条。
- 向量
向量我們可以看做是數(shù)組,在GLSL通常用于儲存顏色投剥、坐標等數(shù)據(jù)师脂,針對維數(shù),可分為二維、三維和四位向量危彩。針對存儲的標量類型攒磨,可以分為bool、int和float汤徽。共有vec2娩缰、vec3、vec4谒府,ivec2拼坎、ivec3、ivec4完疫、bvec2泰鸡、bvec3和bvec4九種類型,數(shù)組代表維數(shù)壳鹤、i表示int類型盛龄、b表示bool類型。需要注意的是芳誓,GLSL中的向量表示豎向量余舶,所以與矩陣相乘進行變換時,矩陣在前锹淌,向量在后(與DirectX正好相反)匿值。向量在GPU中由硬件支持運算,比CPU快的多赂摆。
- 作為顏色向量時挟憔,用rgba表示分量,就如同取數(shù)組的中具體數(shù)據(jù)的索引值烟号。三維顏色向量就用rgb表示分量绊谭。比如對于顏色向量vec4 color,color[0]和color.r都表示color向量的第一個值汪拥,也就是紅色的分量龙誊。其他相同。
- 作為位置向量時喷楣,用xyzw表示分量趟大,xyz分別表示xyz坐標,w表示向量的模铣焊。三維坐標向量為xyz表示分量逊朽,二維向量為xy表示分量。
- 作為紋理向量時曲伊,用stpq表示分量叽讳,三維用stp表示分量追他,二維用st表示分量。
- 矩陣
在GLSL中矩陣擁有22岛蚤、33邑狸、4*4三種類型的矩陣,分別用mat2涤妒、mat3单雾、mat4表示。我們可以把矩陣看做是一個二維數(shù)組她紫,也可以用二維數(shù)組下表的方式取里面具體位置的值硅堆。
4.采樣器
采樣器是專門用來對紋理進行采樣工作的,在GLSL中一般來說贿讹,一個采樣器變量表示一副或者一套紋理貼圖渐逃。所謂的紋理貼圖可以理解為我們看到的物體上的皮膚。
5.結構體
和C語言中的結構體相同民褂,用struct來定義結構體茄菊,關于結構體參考C語言中的結構體。
6.數(shù)組
數(shù)組知識也和C中相同赊堪,不同的是數(shù)組聲明時可以不指定大小面殖,但是建議在不必要的情況下,還是指定大小的好雹食。
7.空類型
空類型用void表示畜普,僅用來聲明不返回任何值得函數(shù)期丰。
數(shù)據(jù)聲明示例:
float a=1.0;
int b=1;
bool c=true;
vec2 d=vec2(1.0,2.0);
vec3 e=vec3(1.0,2.0,3.0)
vec4 f=vec4(vec3,1.2);
vec4 g=vec4(0.2); //相當于vec(0.2,0.2,0.2,0.2)
vec4 h=vec4(a,a,1.3,a);
mat2 i=mat2(0.1,0.5,1.2,2.4);
mat2 j=mat2(0.8); //相當于mat2(0.8,0.8,0.8,0.8)
mat3 k=mat3(e,e,1.2,1.6,1.8);
運算符
GLSL中的運算符有(越靠前群叶,運算優(yōu)先級越高):
- 索引:[]
- 前綴自加和自減:++,–
- 一元非和邏輯非:~钝荡,街立!
- 加法和減法:+,-
- 等于和不等于:==埠通,赎离!=
- 邏輯異或:^^
- 三元運算符號,選擇:端辱?:
- 成員選擇與混合:.
- 后綴自加和自減:++梁剔,–
- 乘法和除法:*,/
- 關系運算符:>舞蔽,<荣病,=,>=渗柿,<=个盆,<>
- 邏輯與:&&
- 邏輯或:||
- 賦值預算:=,+=,-=颊亮,*=柴梆,/=
類型轉換
GLSL的類型轉換與C不同。在GLSL中類型不可以自動提升终惑,比如float a=1;就是一種錯誤的寫法绍在,必須嚴格的寫成float a=1.0,也不可以強制轉換狠鸳,即float a=(float)1;也是錯誤的寫法揣苏,但是可以用內置函數(shù)來進行轉換,如float a=float(1);還有float a=float(true);(true為1.0件舵,false為0.0)等卸察,值得注意的是,低精度的int不能轉換為低精度的float铅祸。
限定符
GLSL中的限定符號主要有:
- attritude:一般用于各個頂點各不相同的量坑质。如頂點顏色、坐標等临梗。
- uniform:一般用于對于3D物體中所有頂點都相同的量涡扼。比如光源位置,統(tǒng)一變換矩陣等盟庞。
- varying:表示易變量吃沪,一般用于頂點著色器傳遞到片元著色器的量。
- const:常量什猖。
限定符與java限定符類似票彪,放在變量類型之前,并且只能用于全局變量不狮。在GLSL中降铸,沒有默認限定符一說。
流程控制
GLSL中的流程控制與C中基本相同摇零,主要有:
- if(){}推掸、if(){}else{}、if(){}else if(){}else{}
- while(){}和do{}while()
- for(;;){}
- break和continue
函數(shù)
GLSL中也可以定義函數(shù)驻仅,定義函數(shù)的方式也與C語言基本相同谅畅。函數(shù)的返回值可以是GLSL中的除了采樣器的任意類型。對于GLSL中函數(shù)的參數(shù)噪服,可以用參數(shù)用途修飾符來進行修飾毡泻,常用修飾符如下:
- in:輸入?yún)?shù),無修飾符時默認為此修飾符芯咧。
- out:輸出參數(shù)牙捉。
- inout:既可以作為輸入?yún)?shù)竹揍,又可以作為輸出參數(shù)。
浮點精度
與頂點著色器不同的是邪铲,在片元著色器中使用浮點型時芬位,必須指定浮點類型的精度,否則編譯會報錯带到。精度有三種昧碉,分別為:
- lowp:低精度。8位揽惹。
- mediump:中精度被饿。10位。
- highp:高精度搪搏。16位狭握。
不僅僅是float可以制定精度,其他(除了bool相關)類型也同樣可以疯溺,但是int论颅、采樣器類型并不一定要求指定精度。加精度的定義如下:
uniform lowp float a=1.0;
varying mediump vec4 c;
當然囱嫩,也可以在片元著色器中設置默認精度恃疯,只需要在片元著色器最上面加上precision <精度> <類型>即可制定某種類型的默認精度。其他情況相同的話墨闲,精度越高今妄,畫質越好,使用的資源也越多鸳碧。
程序結構
GLSL程序的結構和C語言差不多盾鳞,main()方法表示入口函數(shù),可以在其上定義函數(shù)和變量杆兵,在main中可以引用這些變量和函數(shù)雁仲。定義在函數(shù)體以外的叫做全局變量仔夺,定義在函數(shù)體內的叫做局部變量琐脏。與高級語言不通的是,變量和函數(shù)在使用前必須聲明缸兔,不能再使用的后面聲明變量或者函數(shù)日裙。
GLSL 內建變量
在著色器中我們一般都會聲明變量來在程序中使用,但是著色器中還有一些特殊的變量惰蜜,不聲明也可以使用昂拂。這些變量叫做內建變量。內建變量抛猖,相當于著色器硬件的輸入和輸出點格侯,使用者利用這些輸入點輸入之后鼻听,就會看到屏幕上的輸出。通過輸出點可以知道輸出的某些數(shù)據(jù)內容联四。當然撑碴,實際上肯定不會這樣簡單,這么說只是為了幫助理解朝墩。在頂點著色器中的內建變量和片元著色器的內建變量是不相同的醉拓。著色器中的內建變量有很多,在此收苏,我們只列出最常用的集中內建變量亿卤。
頂點著色器的內建變量
輸入變量:
- gl_Position:頂點坐標
- gl_PointSize:點的大小,沒有賦值則為默認值1鹿霸,通常設置繪圖為點繪制才有意義排吴。
片元著色器的內建變量
輸入變量:
- gl_FragCoord:當前片元相對窗口位置所處的坐標。
- gl_FragFacing:bool型懦鼠,表示是否為屬于光柵化生成此片元的對應圖元的正面傍念。
輸出變量:
- gl_FragColor:當前片元顏色
- gl_FragData:vec4類型的數(shù)組。向其寫入的信息葛闷,供渲染管線的后繼過程使用憋槐。
常用內置函數(shù)
常見函數(shù)
- radians(x):角度轉弧度
- degrees(x):弧度轉角度
- sin(x):正弦函數(shù),傳入值為弧度淑趾。相同的還有cos余弦函數(shù)阳仔、tan正切函數(shù)、asin反正弦扣泊、acos反余弦近范、atan反正切
- pow(x,y):xy
- exp(x):
- exp2(x):
- log(x):
- log2(x):
- sqrt(x):
- inversesqr(x):
- abs(x):取x的絕對值
- sign(x):x>0返回1.0,x<0返回-1.0延蟹,否則返回0.0
- ceil(x):返回大于或者等于x的整數(shù)
- floor(x):返回小于或者等于x的整數(shù)
- fract(x):返回x-floor(x)的值
- mod(x,y):取模(求余)
- min(x,y):獲取xy中小的那個
- max(x,y):獲取xy中大的那個
- mix(x,y,a):返回x?(1?a)+y?a
- step(x,a):x< a返回0.0评矩,否則返回1.0
- smoothstep(x,y,a):a < x返回0.0,a>y返回1.0阱飘,否則返回0.0-1.0之間平滑的Hermite插值斥杜。
- dFdx(p):p在x方向上的偏導數(shù)
- dFdy(p):p在y方向上的偏導數(shù)
- fwidth(p):p在x和y方向上的偏導數(shù)的絕對值之和
幾何函數(shù)
- length(x):計算向量x的長度
- distance(x,y):返回向量xy之間的距離
- dot(x,y):返回向量xy的點積
- cross(x,y):返回向量xy的差積
- normalize(x):返回與x向量方向相同,長度為1的向量
矩陣函數(shù)
- matrixCompMult(x,y):將矩陣相乘
- lessThan(x,y):返回向量xy的各個分量執(zhí)行x< y的結果沥匈,類似的有greaterThan,equal,notEqual
- lessThanEqual(x,y):返回向量xy的各個分量執(zhí)行x<= y的結果蔗喂,類似的有類似的有greaterThanEqual
- any(bvec x):x有一個元素為true,則為true
- all(bvec x):x所有元素為true高帖,則返回true缰儿,否則返回false
- not(bvec x):x所有分量執(zhí)行邏輯非運算
紋理采樣函數(shù)
紋理采樣函數(shù)有texture2D、texture2DProj散址、texture2DLod乖阵、texture2DProjLod宣赔、textureCube、textureCubeLod及texture3D瞪浸、texture3DProj拉背、texture3DLod、texture3DProjLod等默终。
- texture表示紋理采樣椅棺,2D表示對2D紋理采樣,3D表示對3D紋理采樣
- Lod后綴齐蔽,只適用于頂點著色器采樣
- Proj表示紋理坐標st會除以q
紋理采樣函數(shù)中两疚,3D在OpenGLES2.0并不是絕對支持。我們再次暫時不管3D紋理采樣函數(shù)含滴。重點只對texture2D函數(shù)進行說明诱渤。texture2D擁有三個參數(shù),第一個參數(shù)表示紋理采樣器谈况。第二個參數(shù)表示紋理坐標勺美,可以是二維、三維碑韵、或者四維赡茸。第三個參數(shù)加入后只能在片元著色器中調用,且只對采樣器為mipmap類型紋理時有效祝闻。