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

著色器(Shader)是運行在GPU上的小程序。這些小程序為圖形渲染管線的某個特定部分而運行。從基本意義上來說,著色器只是一種把輸入轉化為輸出的程序。著色器也是一種非常獨立的程序,因為它們之間不能相互通信;它們之間唯一的溝通只有通過輸入和輸出。

前面的教程里我們簡要地觸及了一點著色器的皮毛,并了解了如何恰當地使用它們。現在我們會用一種更加廣泛的形式詳細解釋著色器,特別是OpenGL著色器語言(GLSL)。

GLSL

著色器是使用一種叫GLSL的類C語言寫成的。GLSL是為圖形計算量身定制的,它包含一些針對向量和矩陣操作的有用特性。

著色器的開頭總是要聲明版本,接著是輸入和輸出變量、uniform和main函數。每個著色器的入口點都是main函數,在這個函數中我們處理所有的輸入變量,并將結果輸出到輸出變量中。如果你不知道什么是uniform也不用擔心,我們后面會進行講解。

一個典型的著色器有下面的結構:

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

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

當我們特別談論到頂點著色器的時候,每個輸入變量也叫頂點屬性(Vertex Attribute)。我們能聲明的頂點屬性是有上限的,它一般由硬件來決定。OpenGL確保至少有16個包含4分量的頂點屬性可用,但是有些硬件或許允許更多的頂點屬性,你可以查詢GL_MAX_VERTEX_ATTRIBS來獲取具體的上限:

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

通常情況下它至少會返回16個,大部分情況下是夠用了。

數據類型

和其他編程語言一樣,GLSL有數據類型可以來指定變量的種類。GLSL中包含C等其它語言大部分的默認基礎數據類型:int、float、double、uint和bool。GLSL也有兩種容器類型,它們會在這個教程中使用很多,分別是向量(Vector)和矩陣(Matrix),其中矩陣我們會在之后的教程里再討論。

向量

GLSL中的向量是一個可以包含有1、2、3或者4個分量的容器,分量的類型可以是前面默認基礎類型的任意一個。它們可以是下面的形式(n代表分量的數量):

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

大多數時候我們使用vecn,因為float足夠滿足大多數要求了。

一個向量的分量可以通過vec.x這種方式獲取,這里x是指這個向量的第一個分量。你可以分別使用.x、.y、.z和.w來獲取它們的第1、2、3、4個分量。GLSL也允許你對顏色使用rgba,或是對紋理坐標使用stpq訪問相同的分量。

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

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

你可以使用上面4個字母任意組合來創建一個和原來向量一樣長的(同類型)新向量,只要原來向量有那些分量即可;然而,你不允許在一個vec2向量中去獲取.z元素。我們也可以把一個向量作為一個參數傳給不同的向量構造函數,以減少需求參數的數量:

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

關于OpenGLES渲染管線,請參考博客 [OpenGL ES 02]OpenGL ES渲染管線與著色器。著色器是可編程管線中的術語,其語法類似C語言,分為頂點著色器(Vertex Shader)和片元著色器(Fragment Shader)

頂點著色器

Vertex shader – 在你的場景中,每個頂點都需要調用的程序,稱為“頂點著色器”。假如你在渲染一個簡單的場景:一個長方形,每個角只有一個頂點。于是vertex shader 會被調用四次。它負責執行:諸如燈光、幾何變換等等的計算。得出最終的頂點位置后,為下面的片段著色器提供必須的數據。

vertex shader可通過可編程的方式實現對頂點的操作,如坐標空間轉換,顏色及紋理坐標。最簡單的Vertex shader如下

attribute vec4 Position;

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

1、attribute聲明vertex shader接收的變量,針對每一個頂點的數據。屬性可理解為針對每一個頂點的輸入數據,只有在vertex shader中才有,在fragment shader中沒有。vec4表示由4部分組成的矢量。這里的Position用來傳入頂點vertex的位置數據。
2、main是shader腳本的入口。
3、gl_Position是vertex shader內建的輸出變量,傳遞給fragment shader,必須設置。這里將Position直接傳遞給fragment shader。

片元著色器

Fragment shader – 在你的場景中,大概每個像素都會調用的程序,稱為“片段著色器”。在一個簡單的場景,也是剛剛說到的長方形。這個長方形所覆蓋到的每一個像素,都會調用一次fragment shader。片段著色器的責任是計算燈光,以及更重要的是計算出每個像素的最終顏色

Fragment是可以被渲染到屏幕上的像素點,fragment shader即用于計算每個像素的顏色等屬性。最簡單的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設置float的精度為mediump,還可設置為lowp和highp,主要是出于性能考慮。
2、gl_FragColor是fragment shader唯一的內建輸出變量,設置像素的顏色。這里設置所有像素均為紅色。

Vertex shader接收多個參數

上邊的vertex shader僅接收頂點的位置信息,因此像素顏色都是在fragment shader中寫固定的(紅色)。而在下邊的vertex shader中,通過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表示依據兩個頂點的顏色,平滑地計算出頂點之間每個像素的顏色。

對應的fragment shader為:

varying lowp vec4 DestinationColor;

void main(void) {
    gl_FragColor = DestinationColor;
}

這里,fragment shader接收來自vertex shader的變量DestinationColor,賦值給gl_FragColor,再輸出至OpenGLES。即每個像素的顏色由DestinationColor決定,這樣可在代碼中精確控制每個像素的顏色。

Vertex shader與Fragment shader的差異

1、shader腳本中有三種級別的精度:lowp,mediump,highp。如precision highp float; 。在vertex shader中,int和float都默認為highp級別。而fragment shader中沒有默認精度,必須設置精度描述符,一般設為mediump即可。
2、attribute只作用于vertex shader中,表示接收的變量。在vertex shader中,若沒有attribute則為輸出變量(輸出至fragment shader)。
3、vertex shader的默認輸出變量至少應該有gl_Position,另外有兩個可選的gl_FrontFacing和gl_PointSize。而fragment shader只有唯一的varying輸出變量gl_FragColor。
4、Uniform是全局變量,可用于vertex shader和fragment shader。在vertex shader中通常是變換矩陣、光照參數、顏色等,。在fragment shader中通常是霧化參數、紋理參數等。OpenGLES 2.0規定所有實現應該支持的最大vertex shader的uniform變量個數不能少于128個,而最大fragment shader的uniform變量個數不能少于16個。
5、simpler是一種特殊的uniform,用于呈現紋理,可用于vertex shader和fragment shader.

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容

  • 目錄結構: 第一步,明確要干嘛 第二步,怎么去畫(純理論) 第三步,怎么去畫(實戰) 第四步,練練手 第一步,明確...
    半紙淵閱讀 8,100評論 18 57
  • 你好,三角形 圖形渲染管線(Pipeline) 3D坐標轉為2D坐標的處理過程是由OpenGL的圖形渲染管線(Pi...
    IceMJ閱讀 7,469評論 2 13
  • 1 前言 一直想沿著圖像處理這條線建立一套完整的理論知識體系,同時積累實際應用經驗。因此有了從使用AVFounda...
    RichardJieChen閱讀 5,720評論 5 12
  • 著色器(Shader) 著色器是運行在GPU上的小程序。這些小程序為圖形渲染管線的一個特定部分而運行。從基本意義上...
    IceMJ閱讀 1,692評論 0 6
  • (馬齒莧) 嶺南草藥五行草 五行草 別名 瓜子菜、蜆肉菜、老鼠耳 拉丁名:Portulaca oleracea L...
    遠水生方閱讀 1,099評論 0 2