前言
該篇文章是繼camera2 的基礎(chǔ)上 添加的 Opengles,實(shí)現(xiàn)濾鏡或者黑白灰等效果,由于Opengles 需要設(shè)置 GLSL 語(yǔ)言的 shader,這里單獨(dú)加一張 GLSL 的學(xué)習(xí)筆記。閱讀時(shí)間20分鐘+
1. 關(guān)于GLSL
著色器是用來(lái)實(shí)現(xiàn)圖像渲染的,用來(lái)替代固定渲染管線的可編程程序。著色器替代了傳統(tǒng)的固定渲染管線,可以實(shí)現(xiàn)3D圖形學(xué)計(jì)算中的相關(guān)計(jì)算,由于其可編程性,可以實(shí)現(xiàn)各種各樣的圖像效果而不用受顯卡的固定渲染管線限制。這極大的提高了圖像的畫(huà)質(zhì)。
在Opengloes 中著色器分為頂點(diǎn)著色器和片元著色器,我們可以理解為:頂點(diǎn)著色器是針對(duì)每個(gè)頂點(diǎn)執(zhí)行一次,用于確定頂點(diǎn)的位置;片元著色器是針對(duì)每個(gè)片元(可以理解為每個(gè)像素)執(zhí)行一次,用于確認(rèn)渲染每個(gè)片元(像素)的顏色。
2. GLSL 簡(jiǎn)要說(shuō)明
OpenGLES的著色器語(yǔ)言GLSL是一種高級(jí)的圖形化編程語(yǔ)言,其源自應(yīng)用廣泛的C語(yǔ)言。與傳統(tǒng)的C語(yǔ)言不同的是,它提供了更加豐富的針對(duì)于圖像處理的原生類(lèi)型,諸如向量、矩陣之類(lèi)。OpenGLES 主要包含以下特性:
1.GLSL是一種面向過(guò)程的語(yǔ)言,和Java的面向?qū)ο笫遣煌摹?br> 2.它完美的支持向量和矩陣操作。
3.它是通過(guò)限定符操作來(lái)管理輸入輸出類(lèi)型的。
4.GLSL提供了大量的內(nèi)置函數(shù)來(lái)提供豐富的擴(kuò)展功能。
3.1 基本類(lèi)型
| 類(lèi)型 | 描述 |
|---|---|
| void | 同 java,表示空類(lèi)型。作為函數(shù)的返回類(lèi)型,表示這個(gè)函數(shù)不返回值。 |
| bool | 布爾類(lèi)型 rue 和false,可以產(chǎn)生布爾型的表達(dá)式。 |
| int | 整型 代表至少包含16位的有符號(hào)的整數(shù)。十進(jìn)制,十六進(jìn)制 八進(jìn)制 |
| float | 浮點(diǎn)型 |
| bvec2 /3 /4 | 包含2 / 3 / 4個(gè)布爾成分的向量 |
| ivec2 / 3 / 4 | 包含2 / 3 / 4個(gè)整型成分的向量 |
| mat2 或者 mat2x2 | 2x2的浮點(diǎn)數(shù)矩陣類(lèi)型 |
| mat3 或者 mat3x3 | 3x3的浮點(diǎn)數(shù)矩陣類(lèi)型 |
| mat4 或者 mat4x4 | 4x4的浮點(diǎn)矩陣 |
| mat2x3 | 2列3行的浮點(diǎn)矩陣(OpenGL的矩陣是列主順序的) 還有 很多種類(lèi)型 2× 4 2列 4行 不一一列舉了 |
| sampler1D / 2D / 3D | 用于內(nèi)建的紋理函數(shù)中引用指定的1D /2D / 3D 紋理的句柄。只可以作為一致變量或者函數(shù)參數(shù)使用 |
| samplerCube | cube map紋理句柄 |
| sampler1DShadow / sampler2DShadow | 一維 / 二維深度紋理句柄 |
代碼舉例 :
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.0);
vec4 g=vec4(0.2); //相當(dāng)于vec(0.2,0.2,0.2,0.2)
mat2 i=mat2(0.1,0.5,1.2,2.4);
mat2 j=mat2(0.8); //相當(dāng)于mat2(0.8,0.8,0.8,0.8)
3.2 運(yùn)算符
GLSL語(yǔ)言的操作符與Java 語(yǔ)言相似。如下表(操作符的優(yōu)先級(jí)從高到低排列)
| 操作符 | 描述 |
|---|---|
| () | 用于表達(dá)式組合,函數(shù)調(diào)用,構(gòu)造 |
| [ ] | 數(shù)組下標(biāo),向量或矩陣的選擇器 |
| . | 結(jié)構(gòu)體和向量的成員選擇 |
| ++ -- | 前綴或后綴的自增自減操作符 |
| + – ! | 一元操作符,表示正 負(fù) 邏輯非 |
| * / | 乘 除操作符 |
| + - | 二元操作符 表示加 減操作 |
| <> <= >= == != | 小于,大于,小于等于, 大于等于,等于,不等于 判斷符 |
| && ^^ | 邏輯與 ,或, 異或 |
| ?: | 條件判斷符 |
| = += –= *= /= | 賦值操作符 |
3.3 結(jié)構(gòu)體
結(jié)構(gòu)體可以組合基本類(lèi)型和數(shù)組來(lái)形成用戶(hù)自定義的類(lèi)型。在定義一個(gè)結(jié)構(gòu)體的同時(shí),你可以定義一個(gè)結(jié)構(gòu)體實(shí)例?;蛘吆竺嬖俣x。
struct surface {float indexOfRefraction;
vec3 color;float turbulence;
} mySurface;
surface secondeSurface;
可以通過(guò)=為結(jié)構(gòu)體賦值,或者使用 ==,!=來(lái)判斷兩個(gè)結(jié)構(gòu)體是否相等
只有結(jié)構(gòu)體中的每個(gè)成分都相等,那么這兩個(gè)結(jié)構(gòu)體才是相等的。訪問(wèn)結(jié)構(gòu)體的內(nèi)部成員使用. 來(lái)訪問(wèn)(和 java 相同)。
結(jié)構(gòu)體至少包含一個(gè)成員。固定大小的數(shù)組也可以被包含在結(jié)構(gòu)體中。GLSL的結(jié)構(gòu)體不支持嵌套定義。只有預(yù)先聲明的結(jié)構(gòu)體可以嵌套其中。
struct myStruct {
vec3 points[3]; //固定大小的數(shù)組是合法的
surface surf; //可以,之前已經(jīng)定義了
struct velocity { //不合法float speed;
vec3 direction;
} velo;
subSurface sub;
//不合法,沒(méi)有預(yù)先聲明;
struct subSurface {
int id;
};
};
3.4 數(shù)組
GLSL中只可以使用一維的數(shù)組。數(shù)組的類(lèi)型可以是一切基本類(lèi)型或者結(jié)構(gòu)體。下面的幾種數(shù)組聲明是合法的:
surface mySurfaces[];
vec4 lightPositions[8];
vec4 lightPos[] = lightPositions;const int numSurfaces = 5;
surface myFiveSurfaces[numSurfaces];float[5] values;
指定顯示大小的數(shù)組可以作為函數(shù)的參數(shù)或者使返回值,也可以作為結(jié)構(gòu)體的成員.數(shù)組類(lèi)型內(nèi)建了一個(gè)length()函數(shù),可以返回?cái)?shù)組的長(zhǎng)度。
vec4 myColor, ambient, diffuse[6], specular[6];
myColor = ambient + diffuse[4] + specular[4];
3.5 修飾符
| 修飾符 | 描述 |
|---|---|
| const | 常量值必須在聲明是初始化。它是只讀的不可修改的。 |
| attribute | 表示只讀的頂點(diǎn)數(shù)據(jù),只用在頂點(diǎn)著色器中。數(shù)據(jù)來(lái)自當(dāng)前的頂點(diǎn)狀態(tài)或者頂點(diǎn)數(shù)組。它必須是全局范圍聲明的,不能再函數(shù)內(nèi)部。一個(gè)attribute可以是浮點(diǎn)數(shù)類(lèi)型的標(biāo)量,向量,或者矩陣。不可以是數(shù)組或則結(jié)構(gòu)體 |
| uniform | 一致變量。在著色器執(zhí)行期間一致變量的值是不變的。與const常量不同的是,這個(gè)值在編譯時(shí)期是未知的是由著色器外部初始化的。一致變量在頂點(diǎn)著色器和片段著色器之間是共享的。它也只能在全局范圍進(jìn)行聲明。 |
| varying | 頂點(diǎn)著色器的輸出。例如顏色或者紋理坐標(biāo),(插值后的數(shù)據(jù))作為片段著色器的只讀輸入數(shù)據(jù)。必須是全局范圍聲明的全局變量。可以是浮點(diǎn)數(shù)類(lèi)型的標(biāo)量,向量,矩陣。不能是數(shù)組或者結(jié)構(gòu)體。 |
| centorid varying | 在沒(méi)有多重采樣的情況下,與varying是一樣的意思。在多重采樣時(shí),centorid varying在光柵化的圖形內(nèi)部進(jìn)行求值而不是在片段中心的固定位置求值。 |
| invariant | (不變量)用于表示頂點(diǎn)著色器的輸出和任何匹配片段著色器的輸入,在不同的著色器中計(jì)算產(chǎn)生的值必須是一致的。所有的數(shù)據(jù)流和控制流,寫(xiě)入invariant變量的是一致的。編譯器為了保證結(jié)果是完全一致的,需要放棄那些可能會(huì)導(dǎo)致不一致值的潛在的優(yōu)化。除非必要,不要使用這個(gè)修飾符。在多通道渲染中避免z-fighting可能會(huì)使用到。 |
| in | 用在函數(shù)的參數(shù)中,表示這個(gè)參數(shù)是輸入的,在函數(shù)中改變這個(gè)值,并不會(huì)影響對(duì)調(diào)用的函數(shù)產(chǎn)生副作用。(相當(dāng)于C語(yǔ)言的傳值),這個(gè)是函數(shù)參數(shù)默認(rèn)的修飾符 |
| out | 用在函數(shù)的參數(shù)中,表示該參數(shù)是輸出參數(shù),值是會(huì)改變的。 |
| inout | 用在函數(shù)的參數(shù),表示這個(gè)參數(shù)即是輸入?yún)?shù)也是輸出參數(shù)。 |
3.6 內(nèi)置變量
內(nèi)置變量可以與固定函數(shù)功能進(jìn)行交互。在使用前不需要聲明。頂點(diǎn)著色器可用的內(nèi)置變量如下表:
| 名稱(chēng) | 類(lèi)型 | 描述 |
|---|---|---|
| gl_Color | vec4 | 輸入屬性-表示頂點(diǎn)的主顏色 |
| gl_SecondaryColor | vec4 | 輸入屬性-表示頂點(diǎn)的輔助顏色 |
| gl_Normal | vec3 | 輸入屬性-表示頂點(diǎn)的法線值 |
| gl_Vertex | vec4 | 輸入屬性-表示物體空間的頂點(diǎn)位置 |
| gl_MultiTexCoordn | vec4 | 輸入屬性-表示頂點(diǎn)的第n個(gè)紋理的坐標(biāo) |
| gl_FogCoord | float | 輸入屬性-表示頂點(diǎn)的霧坐標(biāo) |
| gl_Position | vec4 | 輸出屬性-變換后的頂點(diǎn)的位置,用于后面的固定的裁剪等操作。所有的頂點(diǎn)著色器都必須寫(xiě)這個(gè)值。 |
| gl_ClipVertex | vec4 | 輸出坐標(biāo),用于用戶(hù)裁剪平面的裁剪 |
| gl_PointSize | float | 點(diǎn)的大小 |
| gl_FrontColor | vec4 | 正面的主顏色的varying輸出 |
| gl_BackColor | vec4 | 背面主顏色的varying輸出 |
| gl_FrontSecondaryColor | vec4 | 正面的輔助顏色的varying輸出 |
| gl_BackSecondaryColor | vec4 | 背面的輔助顏色的varying輸出 |
| gl_TexCoord [] | vec4 | 紋理坐標(biāo)的數(shù)組varying輸出 |
| gl_FogFragCoord | float | 霧坐標(biāo)的varying輸出 |
片段著色器 的內(nèi)置變量如下表:
| 名稱(chēng) | 類(lèi)型 | 描述 |
|---|---|---|
| gl_Color | vec4 | 包含主顏色的插值只讀輸入 |
| gl_SecondaryColor | vec4 | 包含輔助顏色的插值只讀輸入 |
| gl_TexCoord[] | vec4 | 包含紋理坐標(biāo)數(shù)組的插值只讀輸入 |
| gl_FogFragCoord | float | 包含霧坐標(biāo)的插值只讀輸入 |
| gl_FragCoord | vec4 | 只讀輸入,窗口的x,y,z和1/w |
| gl_FrontFacing | bool | 只讀輸入,如果是窗口正面圖元的一部分,則這個(gè)值為true |
| gl_PointCoord | vec2 | 點(diǎn)精靈的二維空間坐標(biāo)范圍在(0.0, 0.0)到(1.0, 1.0)之間,僅用于點(diǎn)圖元和點(diǎn)精靈開(kāi)啟的情況下。 |
| gl_FragData[] | vec4 | 使用glDrawBuffers輸出的數(shù)據(jù)數(shù)組。不能與gl_FragColor結(jié)合使用。 |
| gl_FragColor | vec4 | 輸出的顏色用于隨后的像素操作 |
| gl_FragDepth | float | 輸出的深度用于隨后的像素操作,如果這個(gè)值沒(méi)有被寫(xiě),則使用固定功能管線的深度值代替 |
3.7 構(gòu)造函數(shù)
構(gòu)造函數(shù)可以用于初始化包含多個(gè)成員的變量,包括數(shù)組和結(jié)構(gòu)體。構(gòu)造函數(shù)也可以用在表達(dá)式中。調(diào)用方式如下:
vec3 myNormal = vec3(1.0, 1.0, 1.0);
greenTint = myColor + vec3(0.0, 1.0, 0.0);
ivec4 myColor = ivec4(255);
還可以使用混合標(biāo)量和向量的方式來(lái)構(gòu)造,只要你的元素足以填滿(mǎn)該向量。
vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);
vec3 v = vec3(1.0, 10.0, 1.0);
vec3 v1 = vec3(v);
vec2 fv = vec2(5.0, 6.0);
對(duì)于矩陣,OpenGL中矩陣是列主順序的。如果只傳了一個(gè)值,則會(huì)構(gòu)造成對(duì)角矩陣,其余的元素為0.
mat3 m3 = mat3(1.0);
構(gòu)造出來(lái)的矩陣式:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
mat2 matrix1 = mat2(1.0, 0.0, 0.0, 1.0);
mat2 matrix2 = mat2(vec2(1.0, 0.0), vec2(0.0, 1.0));
mat2 matrix3 = mat2(1.0);
mat2 matrix4 = mat2(mat4(2.0)); //會(huì)取 4x4矩陣左上角的2x2矩陣。
構(gòu)造函數(shù)可以用于標(biāo)量數(shù)據(jù)類(lèi)型的轉(zhuǎn)換。GLSL不支持隱式或顯示的轉(zhuǎn)換,只能通過(guò)構(gòu)造函數(shù)來(lái)轉(zhuǎn)。其中int轉(zhuǎn)為float值是一樣的。float轉(zhuǎn)為int則小數(shù)部分被丟棄。int或float轉(zhuǎn)為bool,0和0.0轉(zhuǎn)為false,其余的值轉(zhuǎn)為true. bool轉(zhuǎn)為int或float,false值轉(zhuǎn)為0和0.0,true轉(zhuǎn)為1和1.0.
float f = 1.7;
int I = int(f); // I = 1
數(shù)組的初始化,可以在構(gòu)造函數(shù)中傳入值來(lái)初始化數(shù)組中對(duì)應(yīng)的每一個(gè)值。
ivec2 position[3] = ivec2[3]((0,0), (1,1), (2,2));
ivec2 pos2[3] = ivec2[]((3,3), (2,1), (3,1));
構(gòu)造函數(shù)也可以對(duì)結(jié)構(gòu)體進(jìn)行初始化。其中順序和類(lèi)型要一一對(duì)應(yīng)。
struct surface {
int index;
vec3 color;
float rotate;
};
surface mySurface = surface(3, vec3(red, green, blue), 0.5);
3.8 控制流
GLSL中的流程控制與 java 中基本相同,主要有:
- if(){}、if(){}else{}、if(){}else if(){}else{}
- while(){}和do{}while()
- for(;;){}
- break和continue
3.9 函數(shù)
在每個(gè)shader中必須有一個(gè)main函數(shù)。main函數(shù)中的void參數(shù)是可選的,但返回值是void時(shí)必須的。
GLSL中的函數(shù),必須是在全局范圍定義和聲明的。不能在函數(shù)定義中聲明或定義函數(shù)。函數(shù)必須有返回類(lèi)型,參數(shù)是可選的。參數(shù)的修飾符(in, out, inout, const等)是可選的
void main(void)
{
...
}
3.9.1 常見(jiàn)函數(shù)
- radians(x):角度轉(zhuǎn)弧度
- degrees(x):弧度轉(zhuǎn)角度
- sin(x):正弦函數(shù),傳入值為弧度。相同的還有cos余弦函數(shù)、tan正切函數(shù)、asin反正弦、acos反余弦、atan反正切
- pow(x,y):xyxy
- exp(x):exex
- exp2(x):2x2x
- log(x):logexlogex
- log2(x):log2xlog2x
- sqrt(x):x??√x
- inversesqr(x):1x??√1x
- abs(x):取x的絕對(duì)值
- 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中小的那個(gè)
- max(x,y):獲取xy中大的那個(gè)
- mix(x,y,a):返回x?(1?a)+y?ax?(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方向上的偏導(dǎo)數(shù)
- dFdy(p):p在y方向上的偏導(dǎo)數(shù)
- fwidth(p):p在x和y方向上的偏導(dǎo)數(shù)的絕對(duì)值之和
3.9.2 幾何函數(shù)
- length(x):計(jì)算向量x的長(zhǎng)度
- distance(x,y):返回向量xy之間的距離
- dot(x,y):返回向量xy的點(diǎn)積
- cross(x,y):返回向量xy的差積
- normalize(x):返回與x向量方向相同,長(zhǎng)度為1的向量
3.9.3 矩陣函數(shù)
- matrixCompMult(x,y):將矩陣相乘
- lessThan(x,y):返回向量xy的各個(gè)分量執(zhí)行x< y的結(jié)果,類(lèi)似的有g(shù)reaterThan,equal,notEqual
- lessThanEqual(x,y):返回向量xy的各個(gè)分量執(zhí)行x<= y的結(jié)果,類(lèi)似的有類(lèi)似的有g(shù)reaterThanEqual
- any(bvec x):x有一個(gè)元素為true,則為true
- all(bvec x):x所有元素為true,則返回true,否則返回false
- not(bvec x):x所有分量執(zhí)行邏輯非運(yùn)算
3.9.4 紋理采樣函數(shù)
紋理采樣函數(shù)有texture2D、texture2DProj、texture2DLod、texture2DProjLod、textureCube、textureCubeLod及texture3D、texture3DProj、texture3DLod、texture3DProjLod等。
- texture表示紋理采樣,2D表示對(duì)2D紋理采樣,3D表示對(duì)3D紋理采樣
- Lod后綴,只適用于頂點(diǎn)著色器采樣
- Proj表示紋理坐標(biāo)st會(huì)除以q
后記
該篇文章知識(shí)點(diǎn) 多為文章頭部參考文章原文,這里比較多的是 記錄和歸納。