OpengGL ES基礎(chǔ)入門----(3)著色器的介紹

著色器(Shader)是運(yùn)行在GPU上的小程序粪摘。這些小程序?yàn)閳D形渲染管線的某個(gè)特定部分而運(yùn)行响驴。從基本意義上來(lái)說(shuō)擅笔,著色器只是一種把輸入轉(zhuǎn)化為輸出的程序舆乔。著色器也是一種非常獨(dú)立的程序磨德,因?yàn)樗鼈冎g不能相互通信缘回;它們之間唯一的溝通只有通過(guò)輸入和輸出。

前面的教程里我們簡(jiǎn)要地觸及了一點(diǎn)著色器的皮毛典挑,并了解了如何恰當(dāng)?shù)厥褂盟鼈儭酥宴,F(xiàn)在我們會(huì)用一種更加廣泛的形式詳細(xì)解釋著色器,特別是OpenGL著色器語(yǔ)言(GLSL)您觉。

GLSL

著色器是使用一種叫GLSL的類C語(yǔ)言寫(xiě)成的拙寡。GLSL是為圖形計(jì)算量身定制的,它包含一些針對(duì)向量和矩陣操作的有用特性琳水。

著色器的開(kāi)頭總是要聲明版本肆糕,接著是輸入和輸出變量、uniform和main函數(shù)在孝。每個(gè)著色器的入口點(diǎn)都是main函數(shù)诚啃,在這個(gè)函數(shù)中我們處理所有的輸入變量,并將結(jié)果輸出到輸出變量中私沮。如果你不知道什么是uniform也不用擔(dān)心始赎,我們后面會(huì)進(jìn)行講解。

一個(gè)典型的著色器有下面的結(jié)構(gòu):

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
  // 處理輸入并進(jìn)行一些圖形操作
  ...
  // 輸出處理過(guò)的結(jié)果到輸出變量
  out_variable_name = weird_stuff_we_processed;
}

當(dāng)我們特別談?wù)摰巾旤c(diǎn)著色器的時(shí)候仔燕,每個(gè)輸入變量也叫頂點(diǎn)屬性(Vertex Attribute)造垛。我們能聲明的頂點(diǎn)屬性是有上限的,它一般由硬件來(lái)決定晰搀。OpenGL確保至少有16個(gè)包含4分量的頂點(diǎn)屬性可用五辽,但是有些硬件或許允許更多的頂點(diǎn)屬性,你可以查詢GL_MAX_VERTEX_ATTRIBS來(lái)獲取具體的上限:

GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

通常情況下它至少會(huì)返回16個(gè)厕隧,大部分情況下是夠用了奔脐。

數(shù)據(jù)類型

和其他編程語(yǔ)言一樣,GLSL有數(shù)據(jù)類型可以來(lái)指定變量的種類吁讨。GLSL中包含C等其它語(yǔ)言大部分的默認(rèn)基礎(chǔ)數(shù)據(jù)類型:int、float峦朗、double建丧、uint和bool。GLSL也有兩種容器類型波势,它們會(huì)在這個(gè)教程中使用很多翎朱,分別是向量(Vector)和矩陣(Matrix)橄维,其中矩陣我們會(huì)在之后的教程里再討論。

向量

GLSL中的向量是一個(gè)可以包含有1拴曲、2争舞、3或者4個(gè)分量的容器,分量的類型可以是前面默認(rèn)基礎(chǔ)類型的任意一個(gè)澈灼。它們可以是下面的形式(n代表分量的數(shù)量):

類型    含義
vecn     包含n個(gè)float分量的默認(rèn)向量
bvecn   包含n個(gè)bool分量的向量
ivecn   包含n個(gè)int分量的向量
uvecn   包含n個(gè)unsigned int分量的向量
dvecn   包含n個(gè)double分量的向量

大多數(shù)時(shí)候我們使用vecn竞川,因?yàn)閒loat足夠滿足大多數(shù)要求了。

一個(gè)向量的分量可以通過(guò)vec.x這種方式獲取叁熔,這里x是指這個(gè)向量的第一個(gè)分量委乌。你可以分別使用.x、.y荣回、.z和.w來(lái)獲取它們的第1遭贸、2、3心软、4個(gè)分量壕吹。GLSL也允許你對(duì)顏色使用rgba,或是對(duì)紋理坐標(biāo)使用stpq訪問(wèn)相同的分量删铃。

向量這一數(shù)據(jù)類型也允許一些有趣而靈活的分量選擇方式算利,叫做重組(Swizzling)。重組允許這樣的語(yǔ)法:

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

你可以使用上面4個(gè)字母任意組合來(lái)創(chuàng)建一個(gè)和原來(lái)向量一樣長(zhǎng)的(同類型)新向量泳姐,只要原來(lái)向量有那些分量即可效拭;然而,你不允許在一個(gè)vec2向量中去獲取.z元素胖秒。我們也可以把一個(gè)向量作為一個(gè)參數(shù)傳給不同的向量構(gòu)造函數(shù)缎患,以減少需求參數(shù)的數(shù)量:

vec2 vect = vec2(0.5f, 0.7f);
vec4 result = vec4(vect, 0.0f, 0.0f);
vec4 otherResult = vec4(result.xyz, 1.0f);

關(guān)于OpenGLES渲染管線,請(qǐng)參考博客 [OpenGL ES 02]OpenGL ES渲染管線與著色器阎肝。著色器是可編程管線中的術(shù)語(yǔ)挤渔,其語(yǔ)法類似C語(yǔ)言,分為頂點(diǎn)著色器(Vertex Shader)和片元著色器(Fragment Shader)

頂點(diǎn)著色器

Vertex shader – 在你的場(chǎng)景中风题,每個(gè)頂點(diǎn)都需要調(diào)用的程序判导,稱為“頂點(diǎn)著色器”。假如你在渲染一個(gè)簡(jiǎn)單的場(chǎng)景:一個(gè)長(zhǎng)方形沛硅,每個(gè)角只有一個(gè)頂點(diǎn)眼刃。于是vertex shader 會(huì)被調(diào)用四次。它負(fù)責(zé)執(zhí)行:諸如燈光摇肌、幾何變換等等的計(jì)算擂红。得出最終的頂點(diǎn)位置后,為下面的片段著色器提供必須的數(shù)據(jù)围小。

vertex shader可通過(guò)可編程的方式實(shí)現(xiàn)對(duì)頂點(diǎn)的操作昵骤,如坐標(biāo)空間轉(zhuǎn)換树碱,顏色及紋理坐標(biāo)。最簡(jiǎn)單的Vertex shader如下

attribute vec4 Position;

void main(Void) {
    gl_Position = Position; // must set gl_Position for vertex shader
}

1变秦、attribute聲明vertex shader接收的變量成榜,針對(duì)每一個(gè)頂點(diǎn)的數(shù)據(jù)。屬性可理解為針對(duì)每一個(gè)頂點(diǎn)的輸入數(shù)據(jù)蹦玫,只有在vertex shader中才有赎婚,在fragment shader中沒(méi)有。vec4表示由4部分組成的矢量钳垮。這里的Position用來(lái)傳入頂點(diǎn)vertex的位置數(shù)據(jù)惑淳。
2、main是shader腳本的入口饺窿。
3歧焦、gl_Position是vertex shader內(nèi)建的輸出變量,傳遞給fragment shader肚医,必須設(shè)置绢馍。這里將Position直接傳遞給fragment shader。

片元著色器

Fragment shader – 在你的場(chǎng)景中肠套,大概每個(gè)像素都會(huì)調(diào)用的程序舰涌,稱為“片段著色器”。在一個(gè)簡(jiǎn)單的場(chǎng)景你稚,也是剛剛說(shuō)到的長(zhǎng)方形瓷耙。這個(gè)長(zhǎng)方形所覆蓋到的每一個(gè)像素,都會(huì)調(diào)用一次fragment shader刁赖。片段著色器的責(zé)任是計(jì)算燈光搁痛,以及更重要的是計(jì)算出每個(gè)像素的最終顏色

Fragment是可以被渲染到屏幕上的像素點(diǎn),fragment shader即用于計(jì)算每個(gè)像素的顏色等屬性宇弛。最簡(jiǎn)單的Fragment shader如下

precision mediump float;

void main(void) {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // must set gl_FragColor for fragment shader
}

1鸡典、precision mediump float設(shè)置float的精度為mediump,還可設(shè)置為lowp和highp枪芒,主要是出于性能考慮彻况。
2、gl_FragColor是fragment shader唯一的內(nèi)建輸出變量舅踪,設(shè)置像素的顏色纽甘。這里設(shè)置所有像素均為紅色。

Vertex shader接收多個(gè)參數(shù)

上邊的vertex shader僅接收頂點(diǎn)的位置信息硫朦,因此像素顏色都是在fragment shader中寫(xiě)固定的(紅色)贷腕。而在下邊的vertex shader中,通過(guò)SourceColor傳遞像素顏色咬展。

attribute vec4 Position;    // position of vertex
attribute vec4 SourceColor; // color of vertex

varying vec4 DestinationColor; // will pass out to fragment shader

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Position;
}

1泽裳、未聲明為attribute的變量即為輸出變量(如DestinationColor),將傳遞給fragment shader破婆。
2涮总、varying表示依據(jù)兩個(gè)頂點(diǎn)的顏色,平滑地計(jì)算出頂點(diǎn)之間每個(gè)像素的顏色祷舀。

對(duì)應(yīng)的fragment shader為:

varying lowp vec4 DestinationColor;

void main(void) {
    gl_FragColor = DestinationColor;
}

這里瀑梗,fragment shader接收來(lái)自vertex shader的變量DestinationColor,賦值給gl_FragColor裳扯,再輸出至OpenGLES抛丽。即每個(gè)像素的顏色由DestinationColor決定,這樣可在代碼中精確控制每個(gè)像素的顏色饰豺。

Vertex shader與Fragment shader的差異

1亿鲜、shader腳本中有三種級(jí)別的精度:lowp,mediump冤吨,highp蒿柳。如precision highp float; 。在vertex shader中漩蟆,int和float都默認(rèn)為highp級(jí)別垒探。而fragment shader中沒(méi)有默認(rèn)精度,必須設(shè)置精度描述符怠李,一般設(shè)為mediump即可圾叼。
2、attribute只作用于vertex shader中捺癞,表示接收的變量夷蚊。在vertex shader中,若沒(méi)有attribute則為輸出變量(輸出至fragment shader)翘簇。
3撬码、vertex shader的默認(rèn)輸出變量至少應(yīng)該有g(shù)l_Position,另外有兩個(gè)可選的gl_FrontFacing和gl_PointSize版保。而fragment shader只有唯一的varying輸出變量gl_FragColor呜笑。
4、Uniform是全局變量彻犁,可用于vertex shader和fragment shader叫胁。在vertex shader中通常是變換矩陣、光照參數(shù)汞幢、顏色等驼鹅,。在fragment shader中通常是霧化參數(shù)、紋理參數(shù)等输钩。OpenGLES 2.0規(guī)定所有實(shí)現(xiàn)應(yīng)該支持的最大vertex shader的uniform變量個(gè)數(shù)不能少于128個(gè)豺型,而最大fragment shader的uniform變量個(gè)數(shù)不能少于16個(gè)。
5买乃、simpler是一種特殊的uniform姻氨,用于呈現(xiàn)紋理,可用于vertex shader和fragment shader.

本文主要參考:http://learnopengl-cn.readthedocs.io/zh/latest/
http://blog.csdn.net/icetime17/article/details/50436927

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末剪验,一起剝皮案震驚了整個(gè)濱河市肴焊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌功戚,老刑警劉巖娶眷,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異啸臀,居然都是意外死亡届宠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門壳咕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)席揽,“玉大人,你說(shuō)我怎么就攤上這事谓厘』闲撸” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵竟稳,是天一觀的道長(zhǎng)属桦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)他爸,這世上最難降的妖魔是什么聂宾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮诊笤,結(jié)果婚禮上系谐,老公的妹妹穿的比我還像新娘。我一直安慰自己讨跟,他們只是感情好纪他,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著晾匠,像睡著了一般茶袒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凉馆,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天薪寓,我揣著相機(jī)與錄音亡资,去河邊找鬼。 笑死向叉,一個(gè)胖子當(dāng)著我的面吹牛锥腻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播植康,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旷太,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼展懈!你這毒婦竟也來(lái)了销睁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤存崖,失蹤者是張志新(化名)和其女友劉穎冻记,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體来惧,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冗栗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了供搀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隅居。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖葛虐,靈堂內(nèi)的尸體忽然破棺而出胎源,到底是詐尸還是另有隱情,我是刑警寧澤屿脐,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布涕蚤,位于F島的核電站,受9級(jí)特大地震影響的诵,放射性物質(zhì)發(fā)生泄漏万栅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一西疤、第九天 我趴在偏房一處隱蔽的房頂上張望烦粒。 院中可真熱鬧,春花似錦代赁、人聲如沸扰她。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)义黎。三九已至,卻和暖如春豁跑,著一層夾襖步出監(jiān)牢的瞬間廉涕,已是汗流浹背泻云。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狐蜕,地道東北人宠纯。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像层释,于是被迫代替她去往敵國(guó)和親婆瓜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 目錄結(jié)構(gòu): 第一步贡羔,明確要干嘛 第二步廉白,怎么去畫(huà)(純理論) 第三步,怎么去畫(huà)(實(shí)戰(zhàn)) 第四步乖寒,練練手 第一步猴蹂,明確...
    半紙淵閱讀 8,065評(píng)論 18 57
  • 你好,三角形 圖形渲染管線(Pipeline) 3D坐標(biāo)轉(zhuǎn)為2D坐標(biāo)的處理過(guò)程是由OpenGL的圖形渲染管線(Pi...
    IceMJ閱讀 7,411評(píng)論 2 13
  • 1 前言 一直想沿著圖像處理這條線建立一套完整的理論知識(shí)體系楣嘁,同時(shí)積累實(shí)際應(yīng)用經(jīng)驗(yàn)磅轻。因此有了從使用AVFounda...
    RichardJieChen閱讀 5,644評(píng)論 5 12
  • 著色器(Shader) 著色器是運(yùn)行在GPU上的小程序。這些小程序?yàn)閳D形渲染管線的一個(gè)特定部分而運(yùn)行逐虚。從基本意義上...
    IceMJ閱讀 1,662評(píng)論 0 6
  • (馬齒莧) 嶺南草藥五行草 五行草 別名 瓜子菜聋溜、蜆肉菜、老鼠耳 拉丁名:Portulaca oleracea L...
    遠(yuǎn)水生方閱讀 1,059評(píng)論 0 2