【OpenGL ES系列教程】著色語言 Shading Language(一)

由于Android平臺下的可編程圖形硬件支持是 OpenGL ES 2.0標(biāo)準(zhǔn)灌曙,因此本教程向巴友們介紹 OpenGL ES著色語言示绊。 OpenGL ES 著色語言是一種高級的圖形編程語言。其源自于應(yīng)用廣泛的C語言宛官,同時具有RendeMan以及其他著色語言的一些優(yōu)良特性扶檐,易于被開發(fā)人員掌握凶杖。 OpenGL ES 的著色語言主要包括以下特性:
OpenGL ES 2.0著色語言是一種高級的過程語言(注意,不是面向?qū)ο蟮模?br> 對頂點著色器款筑、片元著色器使用的是同樣的語言智蝠。
基于C/C++的語法及流程控制腾么。
完美支持向量與矩陣的各種操作。
通過類型限定符來管理輸入與輸出杈湾。
擁有大量的內(nèi)置函數(shù)來提供豐富的功能解虱。
一、著色語言基礎(chǔ)
數(shù)據(jù)類型概述

  1. 標(biāo)量
    標(biāo)量也被稱為“無向量”其值只有大小漆撞,并不具有方向殴泰。標(biāo)量之間的運算遵循簡單的代數(shù)法則,如質(zhì)量浮驳、密度悍汛、體積、時間以及溫度等都屬于標(biāo)量至会。OpenGL ES著色語言支持的標(biāo)量類型有布爾型(bool)离咐、整形(int)和浮點型(float)。
  2. 向量
    OpenGL ES著色語言中奉件,向量可以看做是用同樣類型的標(biāo)量組成宵蛀,其基本類型也分為bool、int和float三種县貌。每個向量可以由2個术陶、3個、4個相同的標(biāo)量組成煤痕,具體情況如下:
    向量類型
    說明
    向量類型
    說明
    vec2
    包含了2個浮點數(shù)的向量
    ivec4
    包含了4個整數(shù)的向量
    vec3
    包含了3個浮點數(shù)的向量
    bvec2
    包含了2個布爾數(shù)的向量
    vec4
    包含了4個浮點數(shù)的向量
    bvec3
    包含了3個布爾數(shù)的向量
    ivec2
    包含了2個整數(shù)的向量
    bvec4
    包含了4個布爾數(shù)的向量
    ivec3
    包含了3個整數(shù)的向量
    向量在著色器代碼的開發(fā)中有著十分重要的作用梧宫,可以很方面的存儲以及存儲顏色、位置杭攻、紋理坐標(biāo)等不僅包含一個組成部分的量祟敛。開發(fā)中,有時可能需奧單獨訪問向量中的某個分量兆解,基本的語法為“<向量名>.<分量名>”,根據(jù)目的的不同跑揉,主要有以下幾種用法:
    將一個向量看做顏色時锅睛,可以使用r,g,b,a四個分量名,分別代表紅历谍、綠现拒、藍(lán)、透明度4個色彩通道望侈。具體用法如下:
    [代碼]xml代碼:
//給向量aColor的紅色通道賦值
aColor.r = 0.6;

將一個向量看做位置時印蔬,可以使用x,y,z,w等4個分量名,分別代表X軸脱衙,Y軸侥猬,Z軸和向量的模四個分量例驹,具體用法和顏色類似。
將一個向量看做紋理坐標(biāo)時退唠,可以使用s,t,p,q四個分量名鹃锈,期分別代表紋理坐標(biāo)的不同分量,具體用法同顏色瞧预。(對紋理坐標(biāo)中的s,t等分量巴友可能不是很明白屎债,不用擔(dān)心,在后面介紹紋理貼圖的教程會進(jìn)行詳細(xì)的介紹)
訪問向量中的各個不同的分量不但可以采用“.”加上不同的分量名垢油,還可以將向量看做一個數(shù)組盆驹,用下標(biāo)來進(jìn)行訪問,具體用法如下:
[代碼]xml代碼:

//給向量aColor的紅色通道賦值
aColor[0] = 0.6;
  1. 矩陣
    有一些基礎(chǔ)的開發(fā)人員都知道滩愁,3D場景中的移位躯喇、旋轉(zhuǎn)、縮放等變換都是由矩陣的運算來實現(xiàn)的惊楼。因此3D場景的開發(fā)中會非常多的使用矩陣玖瘸,矩陣按尺寸分為2x2矩陣、3x3矩陣檀咙、4x4矩陣雅倒,具體情況如下表所示:
    矩陣類型
    說明
    mat2
    2x2浮點數(shù)矩陣
    mat3
    3x3浮點數(shù)矩陣
    mat4
    4x4浮點數(shù)矩陣
    對于矩陣的訪問,可以講矩陣作為列向量的數(shù)組來訪問弧可。如matrix為一個mat4蔑匣,可以使用matrix[2]取到該矩陣的第三列,其為一個vec4棕诵;也可以使用matix[2][2]取得第三列向量的第3個分量裁良。
  2. 采樣器
    采樣器是著色語言中不同于C語言的一種特殊的基本數(shù)據(jù)類型,其專門用來進(jìn)行紋理采樣的相關(guān)操作校套。一般情況下价脾,一個采樣器變量代表一幅或一套紋理貼圖,其具體情況如下:
    采樣器
    說明
    sampler2D
    用于訪問二維紋理
    smapler3D
    用于訪問三維紋理
    samplerCube
    用于訪問立方貼圖紋理
    需要注意的是笛匙,與前面介紹的幾種變量不同侨把,采樣器變量不能再著色器中初始化。一般情況下采樣器變量都用uniform限定符來修飾妹孙,從宿主語言(如java)接受傳遞進(jìn)著色器的值秋柄。
  3. 結(jié)構(gòu)體
    OpenGL ES著色語言還提供了類似C語言中的用戶自定義結(jié)構(gòu)體,同樣也是使用struct關(guān)鍵字進(jìn)行聲明蠢正。其基本用法如下:
    [代碼]xml代碼:
struct info{
vec3 color;
vec3 position;
vec2 textureCoor;
}
  1. 數(shù)組
    聲明數(shù)組的方式主要有兩種骇笔,
    在聲明數(shù)組的同時,指定數(shù)組的大小:
    [代碼]xml代碼:
vec3 position[20];

在聲明數(shù)組時笨触,也可以不指定數(shù)組的大小懦傍,但是必須符合下列兩種情況之一。
u 引用數(shù)組之前旭旭,要再次使用第一種聲明方式來生命該數(shù)組:
[代碼]xml代碼:

//聲明了一個大小不定的vec3數(shù)組
vec3 position[];
//再次聲明該數(shù)組谎脯,并且指定大小。
vec3 position[5];

u 代碼中訪問數(shù)組的下標(biāo)都是編譯時常量持寄,這時編譯器會自動創(chuàng)建適當(dāng)大小的數(shù)組源梭,使得數(shù)組尺寸足夠存儲編譯器看到的最大索引值對應(yīng)的元素。
[代碼]xml代碼:

//聲明了一個大小不定的vec3數(shù)組
vec3 position[];
//position需要一個大小為4的數(shù)組
position[3] = vec3(3.0);
//position需要一個大小為21的數(shù)組
position[20] = vec3(6.0);
  1. 空類型使用void表示稍味,僅用來聲明不返回任何值得函數(shù)废麻。例如在頂點著色器以及片元著色器中必須存在的main函數(shù)就是一個返回值為空的函數(shù),代碼如下:
    [代碼]xml代碼:
void main() {
}

數(shù)據(jù)類型的基本使用

  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并賦值, 相當(dāng)于vec4(0.2 , 0.2 , 0.2, 0.2);
vec4 ve = vec4(0.2);
  1. 運算符
    與大多數(shù)編程語言類似怜姿,常見的運算符都可以在該語言中使用。下面按照優(yōu)先級順序列出了OpenGL ES著色語言中可以使用的運算符:
    運算符
    說明
    運算符
    說明
    []
    用于索引
    .
    成員選擇與混合
    ++ --
    自加1與自減1后綴
    ++ --
    自加1與自減1前綴
  • !
    一元非與邏輯非
  • /
    乘法與除法

加法與減法
< > <= >=
關(guān)系運算符
== !=
等于和不等于
&&
邏輯與
^^
邏輯異或
||
邏輯或
?:
選擇
= += -= *= /=
賦值運算符

  1. 限定符
    與其他的編程語言一樣疼燥,著色器中對變量也有很多可選的限定符,主要如下:
    限定符
    說明
    attribute
    一般用于每個頂點都各不相同的量醉者,如頂點位置、顏色等撬即。
    uniform
    一般用于對同一組頂點組成的單個3D物體中所有頂點都相同的量立磁,如當(dāng)前光源的位置唱歧。
    varying
    用于從頂點著色器傳遞到片元著色器的量
    const
    用于聲明常量
    attribute限定符
    顧名思義為屬性限定符,其修飾的變量用來接收渲染管線傳遞進(jìn)頂點著色器的當(dāng)前待處理頂點的各種屬性值粒竖。這些屬性值每個頂點各自擁有獨立的副本,用于描述頂點的各項特征温圆,如頂點坐標(biāo)、法向量孩革、顏色岁歉、紋理坐標(biāo)等。
    用attribute限定符修士的變量其值是由宿主程序批量出入渲染管線的,管線進(jìn)行基本處理后再傳遞給頂點著色器锅移。數(shù)據(jù)中有多少個頂點熔掺,管線就調(diào)用多少次頂點著色器,每次講一個頂點的各種屬性數(shù)據(jù)傳遞給頂點著色器中對應(yīng)atribute變量非剃。因此置逻,頂點著色器每次執(zhí)行將完成對一個頂點各項屬性數(shù)據(jù)的處理。
    從上面的介紹中可以看出备绽,atribute限定符只能用于頂點著色器中券坞,不能再片元著色器中使用,且attribute限定符只能用來修飾浮點數(shù)標(biāo)量肺素、浮點向量以及矩陣變量恨锚,不能用來修飾其他類型的變量。下面的代碼片段給出了在頂點著色器中正確使用attribute限定符的情況:
    [代碼]xml代碼:
//頂點位置
attribute vec3 aPosition;
//頂點法向量
attribute vec3 aNormal;

前面已經(jīng)提到倍靡,對于用attribute限定符修飾的變量的值是由宿主程序批量傳入渲染管線的猴伶,相關(guān)代碼如下:
[代碼]java代碼:

// 聲明頂點位置屬性引用
int maPositionHandle;
// 獲取頂點位置屬性引用的值,
// mProgram為著色器程序ID,
// aPosition為著色器中對應(yīng)屬性的變量名稱塌西。
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
// 將頂點位置數(shù)據(jù)傳入渲染管線
// maPositionHandle:頂點位置屬性引用
// 3:每頂點一組的數(shù)據(jù)個數(shù)(這里是X,Y,Z坐標(biāo)他挎,因此為3)
// GLES20.GL_FLOAT:數(shù)據(jù)類型
// false:是否格式化
// 3 * 4:每組數(shù)據(jù)的尺寸,這個魅族3個浮點數(shù)值(X,Y,Z坐標(biāo))捡需,每個浮點數(shù)4個字節(jié)
// mVertexBuffer:存放了數(shù)據(jù)的緩沖
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);

具體代碼可以參考第一個教程中的Triangle類办桨。
http://www.apkbus.com/blog-99192-39498.html
uniform限定符
uniform為一致變量限定符,一致變量指的是對于同一組頂點組成的單個3D物體中所有頂點都相同的量栖忠。Uniform變量可以用在頂點著色器或片元著色器中崔挖,其支持用來修飾所有的基本數(shù)據(jù)類型。與屬性限定符類似庵寞,一致變量的值也是從宿主程序傳入的狸相。
下面的代碼片給出了在頂點或片元著色器中正確使用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個浮點數(shù)傳入管線古沥,以備管線傳遞給由N個浮點數(shù)組成的一致變量瘸右,N的取值為1,2,3,4。
glUniformNi/glUniformNiv方法岩齿,將N個整數(shù)傳入管線太颤,以備管線傳遞給由N個整數(shù)組成的一致變量,N的取值為1,2,3,4龄章。
glUniformMatrixNfv方法做裙,將N * N的矩陣傳入管線,以備管線傳遞給N * N矩陣類型的一致變量仔戈,N的取值為2,3,4拧廊。
verying限定符
想要將頂點著色器中的信息傳入到片元著色器中,必須使用varying限定符卦绣。歐諾個varying限定符修飾的全局變量又稱為易變變量,易變變量可以看成是頂點著色器和片元著色器之間的動態(tài)接口廊蜒,方便頂點著色器與片元著色器之間信息的傳遞山叮。下圖給出了易變變量的工作原理:


21212.png

從上圖可以看出添履,首先頂點著色器再每個頂點中都對一邊變量vPosition進(jìn)行了賦值暮胧。接著在片元著色器中接受易變變量vPosition的值時得到的并不是某個頂點賦的特定值,而是根據(jù)片元所在的位置以及圖元中各個頂點的位置進(jìn)行差值計算產(chǎn)生的值钞翔。
如圖中頂點1席舍、2、3的vPosition值分別為vec3(0,7,0)汰扭、vec3(5,0,0)福铅、vec3(-5,0,0),則插值后片元a的vPosition值為vec3(1.45, 2.06, 0)。
從上述介紹中可以看到珊泳,光柵化后產(chǎn)生了多少個片元,就會插值計算出多少套易變變量色查。同時渲染管線就會調(diào)用多少次片元著色器秧了⊙檎保可以看出帝嗡,3D物體的渲染中,片元著色器執(zhí)行的次數(shù)會大大超過頂點著色器哟玷。因此GPU硬件中配置的片元著色器硬件數(shù)量往往多于頂點著色器硬件數(shù)量以提高渲染速度。
const限定符
用const限定符修飾的變量其值是不可以變的喉脖,也就是常量树叽,又稱為編譯時常量谦絮。編譯時常量在聲明的時候必須進(jìn)行初始化。例如:
[代碼]xml代碼:

const int tempx = 1;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末性锭,一起剝皮案震驚了整個濱河市篷店,隨后出現(xiàn)的幾起案子臭家,更是在濱河造成了極大的恐慌,老刑警劉巖蹄殃,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诅岩,死亡現(xiàn)場離奇詭異,居然都是意外死亡吩谦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門咐扭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑废,“玉大人,你說我怎么就攤上這事薛闪“陈” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵术浪,是天一觀的道長胰苏。 經(jīng)常有香客問我醇疼,道長,這世上最難降的妖魔是什么倔毙? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任陕赃,我火速辦了婚禮颁股,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诉儒。我一直安慰自己亏掀,他們只是感情好泛释,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布怜校。 她就那樣靜靜地躺著米者,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喂分,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天机蔗,我揣著相機與錄音,去河邊找鬼梆掸。 笑死牙言,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卑硫。 我是一名探鬼主播蚕断,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼亿乳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了障陶?” 一聲冷哼從身側(cè)響起桐款,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤魔眨,失蹤者是張志新(化名)和其女友劉穎酿雪,沒想到半個月后侄刽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡醋安,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年吓揪,在試婚紗的時候發(fā)現(xiàn)自己被綠了柠辞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片主胧。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖焙格,靈堂內(nèi)的尸體忽然破棺而出夷都,到底是詐尸還是另有隱情,我是刑警寧澤厢破,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布治拿,位于F島的核電站,受9級特大地震影響见坑,放射性物質(zhì)發(fā)生泄漏捏检。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一贯城、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鲫骗,春花似錦、人聲如沸执泰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽排苍。三九已至,卻和暖如春凑队,著一層夾襖步出監(jiān)牢的瞬間幔翰,已是汗流浹背遗增。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工款青, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饰及。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓燎含,卻偏偏與公主長得像腿短,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子橘忱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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