OpenGL學(xué)習(xí)之著色器與渲染管線
看此篇之前請(qǐng)看http://www.lxweimin.com/p/68ee05d6106a
著色器與渲染管線
渲染管線一般是有顯示芯片(GPU)內(nèi)部處理圖形信號(hào)的并行處理單元組成。這些并行處理單元兩兩之間是相互獨(dú)立的,在不同型號(hào)的硬件上獨(dú)立處理單元的數(shù)量也有很大的差異。
圖中陰影部分是可編程的部分
基本處理
該階段設(shè)定3D空間中物體的頂點(diǎn)坐標(biāo),頂點(diǎn)對(duì)應(yīng)的顏色,頂點(diǎn)的紋理坐標(biāo)等屬性,并且指定繪制方式。頂點(diǎn)著色器
頂點(diǎn)著色器是一個(gè)可編程的處理單元,功能為執(zhí)行頂點(diǎn)的變換,光照,材質(zhì)的應(yīng)用于計(jì)算等頂點(diǎn)的相關(guān)操作。工作過(guò)程為首先將原始的頂點(diǎn)幾何信息及其他屬性傳送到頂點(diǎn)著色器中,經(jīng)過(guò)自己開(kāi)發(fā)的頂點(diǎn)著色器處理后產(chǎn)生紋理坐標(biāo),顏色,點(diǎn)位置等后繼流程需要的各項(xiàng)頂點(diǎn)屬性信息,然后將其傳遞給圖元裝配階段。
頂點(diǎn)著色器的輸入主要為待處理頂點(diǎn)相應(yīng)的attribute變量,uniform變量,采樣器以及臨時(shí)變量;輸出主要為經(jīng)過(guò)頂點(diǎn)著色器生成的varying變量及一些內(nèi)建輸出變量。
頂點(diǎn)著色器的輸入數(shù)據(jù)由下面組成:
Attributes:使用頂點(diǎn)數(shù)組封裝每個(gè)頂點(diǎn)的數(shù)據(jù),一般用于每個(gè)頂點(diǎn)都各不相同的變量,如頂點(diǎn)位置、顏色等。
Uniforms:頂點(diǎn)著色器使用的常量數(shù)據(jù),不能被著色器修改,一般用于對(duì)同一組頂點(diǎn)組成的單個(gè)3D物體中所有頂點(diǎn)都相同的變量,如當(dāng)前光源的位置。
Samplers:這個(gè)是可選的,一種特殊的uniforms,表示頂點(diǎn)著色器使用的紋理。
Shader program:頂點(diǎn)著色器的源碼或可執(zhí)行文件,描述了將對(duì)頂點(diǎn)執(zhí)行的操作。
輸出變量-易變比那里在頂點(diǎn)著色器賦值后并不是將賦的值送入后后繼的片元著色器中,而是在光柵化階段由管線根據(jù)片元所屬頂點(diǎn)對(duì)應(yīng)的頂點(diǎn)著色器對(duì)此易變變量的賦值情況及片元與各項(xiàng)頂點(diǎn)的位置插值產(chǎn)生。
下面是一個(gè)用opengl es著色器語(yǔ)言編寫的頂點(diǎn)著色器源碼,這個(gè)頂點(diǎn)著色器使用一個(gè)position和跟它相關(guān)聯(lián)的color數(shù)據(jù)作為輸入數(shù)據(jù),通過(guò)一個(gè)4×4矩陣變換位置,然后輸出變換后的位置和顏色數(shù)據(jù)。
// uniforms used by the vertex shader
uniform mat4 u_mvpMatrix; // matrix to convert P from model
// space to normalized device space.
// attributes input to the vertex shader
attribute vec4 a_position; // position value
attribute vec4 a_color; // input vertex color
// varying variables – input to the fragment shader
varying vec4 v_color; // output vertex color
void main() {
v_color = a_color;
gl_Position = u_mvpMatrix * a_position;
}
圖元裝配(primitive assembly)
頂點(diǎn)著色器之后,渲染管線的下一個(gè)階段是圖元裝配,圖元是一個(gè)能用OpenGL ES繪圖命令繪制的幾何體,繪圖命令指定了一組頂點(diǎn)屬性,描述了圖元的集合形狀和圖元類型。頂點(diǎn)著色器使用這些頂點(diǎn)屬性計(jì)算頂點(diǎn)的位置,顏色以及紋理坐標(biāo),這樣才能傳到片元著色器。
這個(gè)階段主要有兩個(gè)任務(wù),一個(gè)是圖元組裝,另一個(gè)是圖元處理。
圖元組裝是指頂點(diǎn)數(shù)據(jù)根據(jù)設(shè)置的繪制方式被結(jié)合成完整的圖元,例如,點(diǎn)繪制方式下僅需要一個(gè)單獨(dú)的頂點(diǎn),每個(gè)頂點(diǎn)為一個(gè)圖元;線段繪制方式則需要兩個(gè)頂點(diǎn),每?jī)蓚€(gè)頂點(diǎn)構(gòu)成一個(gè)圖元。
圖元處理最重要的工作是剪裁,對(duì)于每個(gè)圖元,必須確定它是否位于視椎體內(nèi)(3維空間顯示在屏幕上的可見(jiàn)區(qū)域),如果圖元部分在視椎體中,需要進(jìn)行裁剪,如果圖元全部在視椎體外,則直接丟棄圖元。裁剪之后,頂點(diǎn)位置轉(zhuǎn)換成了屏幕坐標(biāo)。背面剔除操作也會(huì)執(zhí)行,它根據(jù)圖元是正面還是背面,如果是背面則丟棄該圖元。經(jīng)過(guò)裁剪和背面剔除操作后,就進(jìn)入渲染流水線的下一個(gè)階段:光柵化。光柵化(Rasterization)
光柵化階段把圖元轉(zhuǎn)換成片元集合,之后會(huì)提交給片元著色器處理,這些片元集合表示可以被繪制到屏幕的像素。如下圖所示:
- 片元著色器
片元著色器是用于處理片元值及相關(guān)數(shù)據(jù)的可編程單元,其可以執(zhí)行紋理的采樣,顏色的匯總,計(jì)算霧顏色等操作。片元著色器主要功能為通過(guò)重復(fù)執(zhí)行(每片元一次)將3D物體中的圖元光柵化后產(chǎn)生的每個(gè)片元的顏色等屬性計(jì)算出來(lái)送入后繼階段;
片元著色器對(duì)光柵化階段產(chǎn)生的每個(gè)片元進(jìn)行操作,需要的輸入數(shù)據(jù)如下:- Varying variables:頂點(diǎn)著色器輸出的varying變量經(jīng)過(guò)光柵化插值計(jì)算后產(chǎn)生的作用于每個(gè)片元的值。
- Uniforms:片元著色器使用的常量數(shù)據(jù)
- Samplers:一種特殊的uniforms,表示片元著色器使用的紋理。
- Shader program:片元著色器的源碼或可執(zhí)行文件,描述了將對(duì)片元執(zhí)行的操作。
片元著色器也可以丟棄片元或者為片元生成一個(gè)顏色值,保存到內(nèi)置變量gl_FragColor。光柵化階段產(chǎn)生的顏色、深度、模板和屏幕坐標(biāo)(Xw, Yw)成為流水線中pre-fragment階段(FragmentShader之后)的輸入。如下圖:
Varting0~n值的是從頂點(diǎn)著色器傳遞到片元活色器的易變數(shù)據(jù)變量,它是由系統(tǒng)在頂點(diǎn)著色器后的光柵化階段自動(dòng)插值產(chǎn)生,其個(gè)數(shù)不一定。
-
gl_FragColor值的是計(jì)算后此片元的顏色。一般在片元著色器的最后都需要對(duì)gl_FragColor進(jìn)行賦值。
下面是一個(gè)簡(jiǎn)單的片元著色器源碼,可以跟上面的頂點(diǎn)著色器源碼結(jié)合繪制一個(gè)高洛德著色的三角形。
precision mediump float;
varying vec4 v_color; // input vertex color from vertex shader
void main(void) {
gl_FragColor = v_color;
}
- 追個(gè)片元操作階段(Per-Fragment Operations)
片元著色器之后就是追個(gè)片元操作階段,包括一系列的測(cè)試階段。一個(gè)光柵化階段產(chǎn)生的具有屏幕坐標(biāo)(x,y)的片元,只能修改framebuffer(幀緩沖)中位置在(x,y)的像素。下圖是Opengl es 2.0逐片元操作的過(guò)程:
Pixel ownership test:像素所有權(quán)測(cè)試,決定framebuffer中某一個(gè)(Xw, Yw)位置的像素是否屬于當(dāng)前Opengl ES的context,比如:如果一個(gè)Opengl ES幀緩沖窗口被其他窗口遮住了,窗口系統(tǒng)將決定被遮住的像素不屬于當(dāng)前Opengl ES的context,因此也就不會(huì)被顯示。
Scissor test:裁剪測(cè)試,決定位置為(Xw, Yw)的片元是否位于裁剪矩形內(nèi),如果不在,則被丟棄。
Stencil and depth tests:模板和深度測(cè)試,傳入片元的模板和深度值,決定是否丟棄片元。
Blending:將新產(chǎn)生的片元顏色值和framebuffer中某個(gè)(Xw, Yw)位置存儲(chǔ)的顏色值進(jìn)行混合。
Dithering:抖動(dòng),可以用來(lái)最大限度的減少使用有限精度存儲(chǔ)顏色值到framebuffer的工件。
逐片元操作之后,片元要么被丟棄,要么一個(gè)片元的顏色,深度或者模板值被寫入到framebuffer的(Xw, Yw)位置,不過(guò)是否真的會(huì)寫入還得依賴于write masks啟用與否。write masks能更好的控制顏色、深度和模板值寫入到合適的緩沖區(qū)。例如:顏色緩沖區(qū)中的write mask可以被設(shè)置成沒(méi)有紅色值寫入到顏色緩沖區(qū)。另外,Opengl ES 2.0提供從framebuffer中獲取像素的接口,不過(guò)需要記住的是像素只能從顏色緩沖區(qū)讀回,深度和模板值不能讀回。
注意:Opengl ES 2.0 的Per-Fragment Operations已經(jīng)不再支持Alpha test 和 LogicOp了,這兩個(gè)步驟在 OpenGL 2.0 和 OpenGL ES 1.x中是存在的。Alpha test 階段不再需要的原因是片元著色器可以丟棄片元,所以可以在片元著色器中執(zhí)行Alpha test。 LogicOp因?yàn)楹苌偈褂茫圆辉僦С至恕?/p>
- 幀緩沖
OpeGL ES中的物體繪制并不是直接在屏幕上進(jìn)行的,而是預(yù)先在幀緩沖區(qū)中進(jìn)行繪制,每繪制玩一幀再將繪制的結(jié)果交換到屏幕上。因此,在每次繪制新的一幀時(shí)都需要清除緩沖區(qū)中的相關(guān)數(shù)據(jù),否則有可能產(chǎn)生不正確的繪制效果。
同時(shí),微課應(yīng)對(duì)不同方面的需要,幀緩沖是由一套組件組成的,主要包括顏色緩沖,深度緩沖以及模板緩沖- 顏色緩沖用于存儲(chǔ)每個(gè)片元的顏色值,每個(gè)顏色值包括RGBA 4個(gè)色彩通道,應(yīng)用程序運(yùn)行時(shí)在屏幕上看到的就是顏色緩沖中的內(nèi)容。
- 深度緩沖用來(lái)存儲(chǔ)每個(gè)片元的深度值,所謂深度值是指以特定的內(nèi)部格式表示的從片元處到觀察點(diǎn)(攝像機(jī))的距離。在啟用深度測(cè)試的情況下,新片元想進(jìn)入幀緩沖時(shí)需要將自己的深度值與幀緩沖中對(duì)應(yīng)位置的片元的深度值進(jìn)行比較,若結(jié)果小于才可能進(jìn)行緩沖,否則丟棄。
- 模板緩沖用來(lái)存儲(chǔ)每個(gè)片元的模板值,供模板測(cè)試使用。