OpenGLES2.0着色器語言glsl


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

 

 

在聲明數組時,也可以不指定數組的大小,但是必須符合下列兩種情況之一。

引用數組之前,要再次使用第一種聲明方式來生命該數組:

 

[代碼]xml代碼:

//聲明了一個大小不定的vec3數組
vec3 position[];
//再次聲明該數組,並且指定大小。
vec3 position[5];

 

 

代碼中訪問數組的下標都是編譯時常量,這時編譯器會自動創建適當大小的數組,使得數組尺寸足夠存儲編譯器看到的最大索引值對應的元素。

 

[代碼]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_Positiongl_PointSize等。在頂點着色器中應該根據需要給這些內建變量賦值,以便由渲染管線中的圖元裝配與光柵化等后續固定功能階段進行進一步的操作。

gl_Position:頂點着色器從應用程序中獲得原始的頂點位置的數據,這些原始的頂點數據在頂點着色器中經過平移、旋轉、縮放等數學變換后,生成新的頂點位置。

gl_PointSize:頂點着色器中可以計算一個點的大小(單位為像素),並將其賦值給gl_PointSize(標量,float類型)以傳遞給渲染管線,如果沒有明確賦值的話,就是采用默認值1gl_PointSize的值一般只有在采用了點繪制方式之后才有意義。

 

2. 片元着色器中的內建變量

片元着色器中的內疚按輸入變量主要有gl_FragCoord以及gl_FrontFacing,這兩個內建變量都是只讀的,由渲染管線中片元着色器之前的階段生成。其具體含義如下:

gl_FragCoordvec4類型,其中含有當前片元相對於窗口位置的坐標值X,Y,Z。如下圖所示:

 

 

gl_FrontFacing:布爾型內建變量,通過讀取內建變量的值可以判斷正在處理的片元是否屬於在光柵化階段生成此片元的對應圖元的正面。如果屬於正面,那么該值為true,否則為false

 

 

 

 

 

 

OpenGL ES 2.0有兩種重要的着色器: 頂點着色器片元着色器

 

頂點着色器是一個可編程的處理單元,功能是執行頂點的變換、光照、材質的應用與計算等頂點的相關操作,每頂點執行一次。其工作過程為首先將原始的頂點幾何信息以及其他屬性傳送到頂點着色器中,經過自己開發的着色器處理之后產生紋理坐標、顏色、點位置等后繼流程需要的各項頂點屬性信息。

 

片元着色器適用於處理片元值及其相關數據的可編程單元,其可以執行紋理的采樣、顏色的匯總、計算霧顏色等操作,每個片元執行一次。

 

 

 

介紹完着色器再給大家簡單說一說着色器和渲染管線的概念。
OpenGL ES 1.X的渲染管線
學習Open GL ES 2.0的渲染管線之前,應該先了解一下Open GL ES 1.X的渲染管線,這對於進一步了解Open GL ES 2.0的渲染管線也是很有好處的。
渲染管線有時也稱之為渲染流水線,一般是由顯示芯片(GPU)內部處理圖形信號的並行處理單元組成。這些並行處理單元兩兩之間是相互獨立的,在不同型號的硬件上獨立處理硬件單元的數量也有很大的差異,一般越高端的硬件,其中獨立處理單元的數量也就越多。
從另一個角度看,Open GL ES 中的渲染管線實質上指的是一些列繪制的過程。這些過程輸入的待渲染的3D物體的相關描述信息數據,經過渲染的管線,輸出的是一幀想要的圖像。具體過程如下:
1. 基本處理
該階段設定3D空間中物體的頂點坐標、頂點對應的顏色、頂點的紋理坐標等屬性,並且指定繪制方式,如:點繪制、線段繪制或者三角形繪制。
2. 頂點緩沖對象
這部分功能在應用中是可選的,對於某些在整個場景中頂點的基本上數據不變的情況。可以在初始化階段將頂點數據經過基本處理后送入頂點緩沖對象,再繪制每一幀想要的圖像時就省去了頂點數據IO的麻煩。
3. 變換和光照
該階段的主要工作是進行頂點變換以及根據程序中設置的光照屬性對頂點進行光照計算。
4. 圖元裝配
這個階段主要有兩個任務,一個是圖元組裝,另一個是圖元處理。
5. 光柵化
雖然虛擬3D世界中的幾何信息是三維的,但由於目前用於顯示的設備都是二維的。因此在真正執行光柵化工作之前,首先需要將虛擬3D世界中的物體投影到視平面上。
6. 紋理環境和顏色求和
紋理采樣:主要是根據當前需要處理片元的紋理坐標以及采用的紋理ID對相應的紋理圖進行紋理采樣,獲取采樣值。
顏色求和:執行顏色的變化,起根據紋理采樣以及光照計算的結果綜合生成需要處理片元的顏色。
7. 霧
根據程序中設置的霧的相關參數,如:顏色、濃度、范圍等來計算當前處理的片元受霧影響后的顏色。
8. Alpha測試
如果程序中啟用了Alpha測試,Open GL ES會檢查每個片元的Alpha值,只有Alpha值符合測試條件的片元才會送入到下一個階段。
9. 剪裁測試
如果程序中啟用了剪裁測試,Open GL ES 會檢查每個片元在幀緩沖中對應的位置,若對應位置在剪裁窗口中,則將此片元送到下一個階段。
10. 深度測試和模板測試
深度測試是指將輸入片元的深度值與幀緩沖區中儲存的對應位置片元的深度值進行比較。
模板測試的主要功能為將繪制區域限定在一定的范圍內,一般用在湖面倒影、鏡像等場合。
11. 顏色緩沖混合
若程序中開啟了Alpha混合,則根據混合因子將上一階段送來的片元與幀緩沖中對應位置的片元進行Alpha混合。
12. 抖動
自己理解吧,打字太累了。
13. 幀緩沖
Open GL ES 中的物體繪制並不是直接在屏幕上進行,而是預先在幀緩沖區中進行繪制,每繪制完一幀再將繪制的結果交換到屏幕上。因此每次繪制新的一幀時都需要清楚緩沖區中的相關數據,否則可能產生不正確的繪制效果。
 
Open GL ES 2.0的渲染管線
Open GL ES 1.X只是對開發人員開放了其中的一部分API接口,但在整個渲染管線的運行過程中開發人員是不能直接干預的。因此,雖然Open GL ES 1.x的渲染管線功能已經很強大,但是其留給開發人員的發揮空間並不大,很多特效難以開發,而Open GL ES 2.0為開發人員提供了更多的發揮空間。
Open GL ES 2.0中“頂點着色器”取代了Open GL ES 1.x渲染管線中的“變換和光照”這使得開發3D場景時對頂點的變換、法向量的計算、紋理坐標的變換、光照材質的應用等均由開發者使用着色器代碼完成,靈活性大大提高。
Open GL ES 2.0中“片元着色器”取代了Open GL ES 1.x渲染管線中的“紋理環境和顏色求和”、“霧”以及“Alpha測試”等階段,這使得紋理處理、顏色求和以及霧效果均由開發者自己開發,大大增強了程序對片元的處理能力。

 


免責聲明!

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



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