OpenGLES2.0中是強制使用可編程的渲染管線的,使用的是glsl着色器語言,因為着色器語言是使用的GPU,即圖形處理單元,而不是CPU,這樣可以使CPU從繁重的幾何計算和像素的處理中解脫出來了。這就加大了處理的速度。
下面的這篇教程是轉載的。原文地址如下,感謝作者manyou
http://www.apkbus.com/blog-99192-39382.html
一、着色語言基礎
數據類型概述
1. 標量
標量也被稱為“無向量”其值只有大小,並不具有方向。標量之間的運算遵循簡單的代數法則,如質量、密度、體積、時間以及溫度等都屬於標量。OpenGL ES着色語言支持的標量類型有布爾型(bool)、整形(int)和浮點型(float)。
2. 向量
OpenGL ES着色語言中,向量可以看做是用同樣類型的標量組成,其基本類型也分為bool、int和float三種。每個向量可以由2個、3個、4個相同的標量組成,具體情況如下:
向量類型 |
說明 |
向量類型 |
說明 |
vec2 |
包含了2個浮點數的向量 |
ivec4 |
包含了4個整數的向量 |
vec3 |
包含了3個浮點數的向量 |
bvec2 |
包含了2個布爾數的向量 |
vec4 |
包含了4個浮點數的向量 |
bvec3 |
包含了3個布爾數的向量 |
ivec2 |
包含了2個整數的向量 |
bvec4 |
包含了4個布爾數的向量 |
ivec3 |
包含了3個整數的向量 |
向量在着色器代碼的開發中有着十分重要的作用,可以很方面的存儲以及存儲顏色、位置、紋理坐標等不僅包含一個組成部分的量。開發中,有時可能需奧單獨訪問向量中的某個分量,基本的語法為“<向量名>.<分量名>”,根據目的的不同,主要有以下幾種用法:
將一個向量看做顏色時,可以使用r,g,b,a四個分量名,分別代表紅、綠、藍、透明度4個色彩通道。具體用法如下:
[代碼]xml代碼:
//給向量aColor的紅色通道賦值 aColor.r = 0.6;
將一個向量看做位置時,可以使用x,y,z,w等4個分量名,分別代表X軸,Y軸,Z軸和向量的模四個分量,具體用法和顏色類似。
將一個向量看做紋理坐標時,可以使用s,t,p,q四個分量名,期分別代表紋理坐標的不同分量,具體用法同顏色。(對紋理坐標中的s,t等分量巴友可能不是很明白,不用擔心,在后面介紹紋理貼圖的教程會進行詳細的介紹)
訪問向量中的各個不同的分量不但可以采用“.”加上不同的分量名,還可以將向量看做一個數組,用下標來進行訪問,具體用法如下:
[代碼]xml代碼:
//給向量aColor的紅色通道賦值 aColor[0] = 0.6;
3. 矩陣
有一些基礎的開發人員都知道,3D場景中的移位、旋轉、縮放等變換都是由矩陣的運算來實現的。因此3D場景的開發中會非常多的使用矩陣,矩陣按尺寸分為2x2矩陣、3x3矩陣、4x4矩陣,具體情況如下表所示:
矩陣類型 |
說明 |
mat2 |
2x2浮點數矩陣 |
mat3 |
3x3浮點數矩陣 |
mat4 |
4x4浮點數矩陣 |
對於矩陣的訪問,可以講矩陣作為列向量的數組來訪問。如matrix為一個mat4,可以使用matrix[2]取到該矩陣的第三列,其為一個vec4;也可以使用matix[2][2]取得第三列向量的第3個分量。
4. 采樣器
采樣器是着色語言中不同於C語言的一種特殊的基本數據類型,其專門用來進行紋理采樣的相關操作。一般情況下,一個采樣器變量代表一幅或一套紋理貼圖,其具體情況如下:
采樣器 |
說明 |
sampler2D |
用於訪問二維紋理 |
smapler3D |
用於訪問三維紋理 |
samplerCube |
用於訪問立方貼圖紋理 |
需要注意的是,與前面介紹的幾種變量不同,采樣器變量不能再着色器中初始化。一般情況下采樣器變量都用uniform限定符來修飾,從宿主語言(如java)接受傳遞進着色器的值。
5. 結構體
OpenGL ES着色語言還提供了類似C語言中的用戶自定義結構體,同樣也是使用struct關鍵字進行聲明。其基本用法如下:
[代碼]xml代碼:
struct info{ vec3 color; vec3 position; vec2 textureCoor; }
6. 數組
聲明數組的方式主要有兩種,
在聲明數組的同時,指定數組的大小:
[代碼]xml代碼:
vec3 position[20];
在聲明數組時,也可以不指定數組的大小,但是必須符合下列兩種情況之一。
u 引用數組之前,要再次使用第一種聲明方式來生命該數組:
[代碼]xml代碼:
//聲明了一個大小不定的vec3數組 vec3 position[]; //再次聲明該數組,並且指定大小。 vec3 position[5];
u 代碼中訪問數組的下標都是編譯時常量,這時編譯器會自動創建適當大小的數組,使得數組尺寸足夠存儲編譯器看到的最大索引值對應的元素。
[代碼]xml代碼:
//聲明了一個大小不定的vec3數組 vec3 position[]; //position需要一個大小為4的數組 position[3] = vec3(3.0); //position需要一個大小為21的數組 position[20] = vec3(6.0);
7. 空類型使用void表示,僅用來聲明不返回任何值得函數。例如在頂點着色器以及片元着色器中必須存在的main函數就是一個返回值為空的函數,代碼如下:
[代碼]xml代碼:
void main() { }
數據類型的基本使用
1. 聲明、作用域及初始化
變量的聲明以及作用域與Java/C++語法類似,可以再任何需要的位置聲明變量,同時期作用域也同樣分為局部變量和全局變量:
[代碼]xml代碼:
//聲明了全局變量a和b int a,b; //聲明了全局變量aPosition並賦值 vec3 aPosition = vec3(1.0, 2.2, 3.3); void myFunction() { //聲明了局部變量c並賦值 int c = 14; //給全局變量a賦值 a = 4; //給全局變量b賦值 b = a * c; }
向量的初始化還有一些很靈活的技巧,巴友們體會一下下面的代碼:
[代碼]xml代碼:
//聲明浮點變量a並賦值 float a = 12.3; //聲明浮點變量b並賦值 float b = 11.4; //聲明2維向量va並賦值 vec2 va = vec2(2.3, 2.5); //聲明2維向量vb並賦值 vec2 vb = vec2(a, b); //聲明3維向量vc並賦值 vec3 vc = vec3(vb, 12.5); //聲明4維向量vd並賦值 vec4 vd = vec4(va, vb); //聲明4維向量ve並賦值, 相當於vec4(0.2 , 0.2 , 0.2, 0.2); vec4 ve = vec4(0.2);
2. 運算符
與大多數編程語言類似,常見的運算符都可以在該語言中使用。下面按照優先級順序列出了OpenGL ES着色語言中可以使用的運算符:
運算符 |
說明 |
運算符 |
說明 |
[] |
用於索引 |
. |
成員選擇與混合 |
++ -- |
自加1與自減1后綴 |
++ -- |
自加1與自減1前綴 |
- ! |
一元非與邏輯非 |
* / |
乘法與除法 |
+ - |
加法與減法 |
< > <= >= |
關系運算符 |
== != |
等於和不等於 |
&& |
邏輯與 |
^^ |
邏輯異或 |
|| |
邏輯或 |
?: |
選擇 |
= += -= *= /= |
賦值運算符 |
3. 限定符
與其他的編程語言一樣,着色器中對變量也有很多可選的限定符,主要如下:
限定符 |
說明 |
attribute |
一般用於每個頂點都各不相同的量,如頂點位置、顏色等。 |
uniform |
一般用於對同一組頂點組成的單個3D物體中所有頂點都相同的量,如當前光源的位置。 |
varying |
用於從頂點着色器傳遞到片元着色器的量 |
const |
用於聲明常量 |
attribute限定符
顧名思義為屬性限定符,其修飾的變量用來接收渲染管線傳遞進頂點着色器的當前待處理頂點的各種屬性值。這些屬性值每個頂點各自擁有獨立的副本,用於描述頂點的各項特征,如頂點坐標、法向量、顏色、紋理坐標等。
用attribute限定符修士的變量其值是由宿主程序批量出入渲染管線的,管線進行基本處理后再傳遞給頂點着色器。數據中有多少個頂點,管線就調用多少次頂點着色器,每次講一個頂點的各種屬性數據傳遞給頂點着色器中對應atribute變量。因此,頂點着色器每次執行將完成對一個頂點各項屬性數據的處理。
從上面的介紹中可以看出,atribute限定符只能用於頂點着色器中,不能再片元着色器中使用,且attribute限定符只能用來修飾浮點數標量、浮點向量以及矩陣變量,不能用來修飾其他類型的變量。下面的代碼片段給出了在頂點着色器中正確使用attribute限定符的情況:
[代碼]xml代碼:
//頂點位置 attribute vec3 aPosition; //頂點法向量 attribute vec3 aNormal;
前面已經提到,對於用attribute限定符修飾的變量的值是由宿主程序批量傳入渲染管線的,相關代碼如下:
[代碼]java代碼:
// 聲明頂點位置屬性引用 int maPositionHandle; // 獲取頂點位置屬性引用的值, // mProgram為着色器程序ID, // aPosition為着色器中對應屬性的變量名稱。 maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); // 將頂點位置數據傳入渲染管線 // maPositionHandle:頂點位置屬性引用 // 3:每頂點一組的數據個數(這里是X,Y,Z坐標,因此為3) // GLES20.GL_FLOAT:數據類型 // false:是否格式化 // 3 * 4:每組數據的尺寸,這個魅族3個浮點數值(X,Y,Z坐標),每個浮點數4個字節 // mVertexBuffer:存放了數據的緩沖 GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
具體代碼可以參考第一個教程中的Triangle類。
http://www.apkbus.com/blog-99192-39498.html
uniform限定符
uniform為一致變量限定符,一致變量指的是對於同一組頂點組成的單個3D物體中所有頂點都相同的量。Uniform變量可以用在頂點着色器或片元着色器中,其支持用來修飾所有的基本數據類型。與屬性限定符類似,一致變量的值也是從宿主程序傳入的。
下面的代碼片給出了在頂點或片元着色器中正確使用uniform限定符的情況:
[代碼]xml代碼:
//總變換矩陣 uniform mat4 uMVPMatrix; //變換矩陣 uniform mat4 uMMatrix; //光源位置 uniform vec3 uLightLocation; //攝像機位置 uniform vec3 uCamera;
將一致變量的值由宿主程序傳入渲染管線的代碼如下:
[代碼]java代碼:
//總變換矩陣一致變量引用 int muMVPMatrixHandle; //獲取着色器程序中總變換矩陣一致變量的引用 muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); //通過一致變量引用將一致變量值傳入渲染管線 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFianlMatrix(mMMatrix), 0);
需要注意的是,隨一致性變量類型不同將值傳入渲染管線的方法也有所不同,這些方法的名稱都以glUniform開頭,常用的如下所列:
glUniformNf/glUniformNfv方法,將N個浮點數傳入管線,以備管線傳遞給由N個浮點數組成的一致變量,N的取值為1,2,3,4。
glUniformNi/glUniformNiv方法,將N個整數傳入管線,以備管線傳遞給由N個整數組成的一致變量,N的取值為1,2,3,4。
glUniformMatrixNfv方法,將N * N的矩陣傳入管線,以備管線傳遞給N * N矩陣類型的一致變量,N的取值為2,3,4。
verying限定符
想要將頂點着色器中的信息傳入到片元着色器中,必須使用varying限定符。歐諾個varying限定符修飾的全局變量又稱為易變變量,易變變量可以看成是頂點着色器和片元着色器之間的動態接口,方便頂點着色器與片元着色器之間信息的傳遞。下圖給出了易變變量的工作原理:
從上圖可以看出,首先頂點着色器再每個頂點中都對一邊變量vPosition進行了賦值。接着在片元着色器中接受易變變量vPosition的值時得到的並不是某個頂點賦的特定值,而是根據片元所在的位置以及圖元中各個頂點的位置進行差值計算產生的值。
如圖中頂點1、2、3的vPosition值分別為vec3(0,7,0)、vec3(5,0,0)、vec3(-5,0,0),則插值后片元a的vPosition值為vec3(1.45, 2.06, 0)。
從上述介紹中可以看到,光柵化后產生了多少個片元,就會插值計算出多少套易變變量。同時渲染管線就會調用多少次片元着色器。可以看出,3D物體的渲染中,片元着色器執行的次數會大大超過頂點着色器。因此GPU硬件中配置的片元着色器硬件數量往往多於頂點着色器硬件數量以提高渲染速度。
const限定符
用const限定符修飾的變量其值是不可以變的,也就是常量,又稱為編譯時常量。編譯時常量在聲明的時候必須進行初始化。例如:
[代碼]xml代碼:
const int tempx = 1;
內建變量
着色器代碼的開發中會用到很多變量,其中大部分可能是由開發人員根據需求自定義的,但着色器中也提供了一些用來滿足特定需求的內建變量。這些內建變量不需要聲明就可以使用,一般用來實現渲染管線固定功能部分與自定義頂點或片元着色器之間的信息交互。
1. 頂點着色器中的內建變量
頂點着色器中的內建變量主要是輸出變量,包括gl_Position、gl_PointSize等。在頂點着色器中應該根據需要給這些內建變量賦值,以便由渲染管線中的圖元裝配與光柵化等后續固定功能階段進行進一步的操作。
gl_Position:頂點着色器從應用程序中獲得原始的頂點位置的數據,這些原始的頂點數據在頂點着色器中經過平移、旋轉、縮放等數學變換后,生成新的頂點位置。
gl_PointSize:頂點着色器中可以計算一個點的大小(單位為像素),並將其賦值給gl_PointSize(標量,float類型)以傳遞給渲染管線,如果沒有明確賦值的話,就是采用默認值1,gl_PointSize的值一般只有在采用了點繪制方式之后才有意義。
2. 片元着色器中的內建變量
片元着色器中的內疚按輸入變量主要有gl_FragCoord以及gl_FrontFacing,這兩個內建變量都是只讀的,由渲染管線中片元着色器之前的階段生成。其具體含義如下:
gl_FragCoord:vec4類型,其中含有當前片元相對於窗口位置的坐標值X,Y,Z。如下圖所示:
gl_FrontFacing:布爾型內建變量,通過讀取內建變量的值可以判斷正在處理的片元是否屬於在光柵化階段生成此片元的對應圖元的正面。如果屬於正面,那么該值為true,否則為false。