OpenGL ES 入門之旅--OpenGL ES頂點(diǎn)著色器和片元著色器

這次我們來(lái)從OpenGL ES的角度來(lái)學(xué)習(xí)一下頂點(diǎn)著色器和片元著色器。在這之前我們先來(lái)看一下在OpenGL ES 3.0下的圖形管線:

圖形管線.png
這里展示的只是一個(gè)簡(jiǎn)圖晨横,具體流程圖請(qǐng)參見(jiàn)OpenGL 下的渲染流程和存儲(chǔ)著色器.

頂點(diǎn)著色器 Vertex Shader

頂點(diǎn)著色器,實(shí)現(xiàn)了一種通用的可編程方法操作頂點(diǎn)忘瓦。
頂點(diǎn)著色器可用于傳統(tǒng)的基于頂點(diǎn)操作榄鉴,例如通過(guò)矩陣變換位置编检、計(jì)算照明方程式以生成逐頂點(diǎn)的顏色以及生成或者變換紋理坐標(biāo)。

在編程中仙辟,頂點(diǎn)著色器的輸入主要有:
1.著色器程序 ShaderProgram---描述頂點(diǎn)上執(zhí)行操作的頂點(diǎn)著色器程序編程源代碼或者可執(zhí)行文件檀轨。
2.頂點(diǎn)著色器輸入屬性Attributes---用于頂點(diǎn)數(shù)組提供每個(gè)頂點(diǎn)的數(shù)據(jù)。
3.統(tǒng)一變量Uniforms---頂點(diǎn)著色器和片元著色器使用的常量數(shù)據(jù)欺嗤。
4.采樣器Samplers---代表頂點(diǎn)著色器使用的紋理的特殊統(tǒng)一變量類型参萄,被Uniforms使用的特殊類型,在頂點(diǎn)著色器的貼圖中使用煎饼,且是可選的讹挎。

相應(yīng)的,頂點(diǎn)著色器的輸出叫做varying變量吆玖。
在最初的光柵化階段筒溃,這些變量被計(jì)算,作為片段著色器的輸入沾乘,從頂點(diǎn)著色器的矩陣使用插補(bǔ)的方法產(chǎn)生片段著色器的變量怜奖,輸入和輸出如下圖所示:

頂點(diǎn)著色器輸入輸出.png

gl_Position:浮點(diǎn)型輸出變量,用于輸出頂點(diǎn)位置的裁剪坐標(biāo)翅阵,該值在裁剪和視口階段用于執(zhí)行相應(yīng)的圖元裁剪以及從裁剪坐標(biāo)到屏幕坐標(biāo)的頂點(diǎn)位置變換歪玲,頂點(diǎn)著色器沒(méi)有寫入gl_Position時(shí)其值是未定義的。
glPointSize:浮點(diǎn)輸出變量掷匠,用于寫入以像素表示的點(diǎn)尺寸滥崩,在渲染點(diǎn)時(shí)使用,頂點(diǎn)著色器輸出的這個(gè)變量值被限定在OpenGL ES 3.0實(shí)現(xiàn)支持的非平滑點(diǎn)大小范圍之內(nèi)讹语。

頂點(diǎn)著色器的業(yè)務(wù):
1.矩陣變換位置
2.計(jì)算光照公式生成逐頂點(diǎn)顏色
3.生成或者變換紋理坐標(biāo)
下面來(lái)看一下頂點(diǎn)著色器的代碼片段:

attribute vec4 position;  //四維向量
attribute vec2 textCoordinate;  // 紋理坐標(biāo)
uniform mat4 rotateMatrix; //旋轉(zhuǎn)4X4矩陣
varying lowp vec2 varyTextCoord; 
void main()
{
varyTextCoord = textCoordinate; 
vec4 vPos = position;
vPos = vPos * rotateMatrix; 
gl_Position = vPos;
}
頂點(diǎn)著色器中的內(nèi)建變量

頂點(diǎn)著色器的內(nèi)建變量可以分為:特殊變量(頂點(diǎn)著色器的輸入/輸出)钙皮,統(tǒng)一狀態(tài)(深度范圍)以及規(guī)定的最大值(屬性數(shù)量,頂點(diǎn)著色器變量數(shù)量和統(tǒng)一變量數(shù)量)的常量。
內(nèi)建特殊變量

gl_VertexID,是一個(gè)輸入變量短条,用于保存頂點(diǎn)的整數(shù)索引导匣,這個(gè)整數(shù)型變量,用highp精度限定符聲明茸时。

gl_InstanceID,是一個(gè)輸入變量逐抑,用于保存實(shí)例化繪圖調(diào)用中圖元的實(shí)例編號(hào),對(duì)于常規(guī)調(diào)用的繪圖調(diào)用屹蚊,該值為0; gl_InstanceID是一個(gè)整數(shù)型變量,用highp精度限定符聲明进每。

gl_Position, 用于輸出頂點(diǎn)位置的裁剪坐標(biāo)汹粤,該值在裁剪和視口變換用于執(zhí)行相應(yīng)的圖元裁剪,以及從裁剪坐標(biāo)到屏幕坐標(biāo)的頂點(diǎn)位置變換田晚。如果頂點(diǎn)著色器未寫入gl_Position嘱兼,則gl_Position的值未定義,gl_Position是浮點(diǎn)型變量贤徒,用highp精度限定符聲明芹壕。

gl_PointSize,可以寫入像素表示點(diǎn)精靈的尺寸,在渲染點(diǎn)精靈時(shí)使用接奈,頂點(diǎn)著色器輸出的gl_PointSize值被限定在OPenGL ES 3.0實(shí)現(xiàn)支持的非平滑點(diǎn)大小范圍之內(nèi)踢涌,gl_PointSize是一個(gè)浮點(diǎn)型變量,用highp精度限定符聲明序宦。

gl_FrontFacing,是一個(gè)特殊變量睁壁,但是不是由頂點(diǎn)著色器直接寫入的,而是根據(jù)頂點(diǎn)著色器生成的位置值和渲染圖元的類型生成的互捌,它是一個(gè)布爾值潘明。

內(nèi)建統(tǒng)一變量
在頂點(diǎn)著色器內(nèi)可用的唯一內(nèi)建Uniform狀態(tài)是窗口坐標(biāo)中的深度范圍,這些由內(nèi)建統(tǒng)一變量名gl_DepthRange給出秕噪。

struct gl_DepthRangeParameters
{
highp float near; //near z 
highp float far; //near far 
highp float diff; //far - near
}
uniform gl_DepthRangeParameters gl_DepthRange;

內(nèi)建常量
·

const mediump int gl_MaxVertexAttribs = 16;
const mediump int gl_MaxVertexUniformVectors = 256; 
const mediump int gl_MaxVertexOutputVectors = 16;
const mediump int gl_MaxVertexTextureImageUnits = 16; 
const mediump int gl_MaxCombinedTextureImageUnits = 32;

gl_MaxVertexAttribs: 可以指定的頂點(diǎn)數(shù)據(jù)最大的數(shù)量钳降。
gl_MaxVertexUniformVectors:頂點(diǎn)著色器可以使用的vect4 Uniform 變量最大數(shù)量。
gl_MaxVertexOutputVectors:表示輸出向量的最大數(shù)量腌巾。
gl_MaxVertexTextureImageUnits:頂點(diǎn)著色器可用紋理單元的最大數(shù)量遂填。
gl_MaxCombinedTextureImageUnits:頂點(diǎn)/片元著色器中的可用紋理單元的最大數(shù)量的總和。

頂點(diǎn)著色器中的矩陣變換
MVP矩陣(模型--視圖--投影矩陣)頂點(diǎn)著色器的位置輸入保存的是物體坐標(biāo)澈蝙,而輸出的坐標(biāo)保存為裁剪坐標(biāo)城菊,MVP矩陣是3D圖形中進(jìn)行這種變換的3個(gè)非常重要的變換矩陣的乘積:模型矩陣,視圖矩陣碉克,投影矩陣凌唬。
模型矩陣:---將物體坐標(biāo)變換為世界坐標(biāo)
視圖矩陣:---將世界坐標(biāo)變換為眼睛坐標(biāo)(觀察坐標(biāo))
投影矩陣:---將眼睛坐標(biāo)(觀察坐標(biāo))變換為裁剪坐標(biāo)

在頂點(diǎn)著色器之后進(jìn)入圖元裝配(Primitive Assembly)階段和光柵化(Rasterization)階段,此過(guò)程開發(fā)者無(wú)法干預(yù),(有關(guān)圖元裝配和光柵化的內(nèi)容請(qǐng)參見(jiàn):OpenGL 下的坐標(biāo)系和著色器渲染流程

片元著色器Fragment Shader

片元著色器是用于處理片元值及相關(guān)數(shù)據(jù)的可編程單元客税,其可以執(zhí)行紋理的采樣况褪,顏色的匯總等操作。
片元著色器主要功能為通過(guò)重復(fù)執(zhí)行(每片元一次)將3D物體中的圖元光柵化后產(chǎn)生的每個(gè)片元的顏色等屬性計(jì)算出來(lái)送入后繼階段更耻;

片元著色器對(duì)光柵化階段產(chǎn)生的每個(gè)片元進(jìn)行操作测垛,需要的輸入數(shù)據(jù)如下:
1.著色器程序Shader program:片元著色器的源碼或可執(zhí)行文件,描述了將對(duì)片元執(zhí)行的操作秧均。
2.輸入變量Varying variables:頂點(diǎn)著色器輸出varying變量經(jīng)過(guò)光柵化插值計(jì)算后產(chǎn)生的作用于每個(gè)片元的值食侮。
3.統(tǒng)一變量Uniforms:片元著色器使用的常量數(shù)據(jù)
4.采樣器Samplers:一種特殊的uniforms,表示片元著色器使用的紋理目胡。

片元著色器的輸入和輸出如下圖所示:
片元.png

gl_FragColor值的是計(jì)算后此片元的顏色锯七。一般在片元著色器的最后都需要對(duì)gl_FragColor進(jìn)行賦值。

片元著色器的業(yè)務(wù):
1.計(jì)算顏色
2.獲取紋理值
3.往像素點(diǎn)中填充顏色值(顏色值或者紋理值)
下面來(lái)看一下片元著色器的代碼片段:

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap; //采樣器
void main()
{
//texture2D方法有兩個(gè)參數(shù):(紋理采樣器,紋理坐標(biāo)),取得紋素(紋理的像素值)俩块。
gl_FragColor = texture2D(colorMap, varyTextCoord); 
}
片元著色器中的內(nèi)建變量

內(nèi)建特殊變量

gl_FragCoord:片元著色器中的一個(gè)只讀變量裆操,這個(gè)變量保存片元的窗口相對(duì)坐標(biāo)。

gl_FrontFacing:片元著色器中的一個(gè)只讀變量,這個(gè)布爾變量是正面圖元時(shí)為true,否則為false。

gl_PointCoord:只讀變量袱蜡,可以在渲染點(diǎn)精靈的時(shí)候使用,保存了點(diǎn)精靈的紋理坐標(biāo)慢宗,這個(gè)坐標(biāo)在點(diǎn)精靈光柵化期間自動(dòng)生成戒劫,處于(0,1)區(qū)間婆廊。

gl_FragDepth:一個(gè)只寫輸出變量迅细,在片元著色器寫入時(shí),覆蓋片元的固定功能深度值淘邻,盡量減少手動(dòng)實(shí)現(xiàn)深度值寫入茵典,這個(gè)功能需要謹(jǐn)慎使用,因?yàn)樗赡芙迷S多GPU的深度優(yōu)化宾舅,例如:許多GPU都有“Early-z”的功能统阿,在執(zhí)行片元著色器之前進(jìn)行深度測(cè)試,使用“Early-z”的好處就是不能通過(guò)深度測(cè)試的片元就不會(huì)被著色(從而降低了著色器的調(diào)用次數(shù)筹我,提高了性能)但是使用gl_FragDepth,就必須禁用該功能扶平,因?yàn)镚PU在執(zhí)行著色器之前不知道深度值。

內(nèi)建常量

const mediump int gl_MaxFragmentInputVectors = 15;
const mediump int gl_MaxTextureImageUnits = 16;
const mediump int gl_MaxFragmentUniformVectors = 224;
const mediump int gl_MaxDrawBuffers = 4;
const mediump int gl_MinProgramTexelOffset = -8; 
const mediump int gl_MaxProgramTexelOffset = 7;

gl_MaxFragmentInputVectors: 片元著色器輸入的最大數(shù)量蔬蕊。
gl_MaxFragmentUniformVectors:可用紋理圖像單元的最大數(shù)量
gl_MaxFragmentUniformVectors:片元著色器可用vec4 Uniform變量最大數(shù)量
gl_MaxDrawBuffers:多重渲染目標(biāo)最大支持?jǐn)?shù)量

多重紋理混合

//?片元著?色器器代碼
attribute vec2 v_texCoord;
uniform sampler2D s_baseMap;
uniform sampler2D s_SecondMap;
void main()
{
  vec4 baseColor;
  vec4 secondColor;
  baseColor = texture(s_baseMap ,v_texCoord);
  secondColor = texture(s_SecondMap ,v_texCoord);
  gl_FragColor = baseColor * secondColor;
}
//客戶端代碼: 將各個(gè)紋理理對(duì)象綁定到紋理理單元0和1,為采樣器器設(shè)置數(shù) 值,將采集器器綁定到對(duì)應(yīng)的紋理理單元
glActiveTexutre(GL_TEXTURE0);
glBindTeture(GL_TEXTURE_2D ,baseMapTexId);
glUniformli(baseMapTexId,0);
glActiveTexutre(GL_TEXTURE1);
glBindTeture(GL_TEXTURE_2D ,secondMapTexId);
glUniformli(secondMapTexId,1);
逐片段操作Per-Fragment Operations

先來(lái)看一下逐片段操作的流程:
流程.png

像素歸屬測(cè)試:確定幀緩存區(qū)中位置[Xw,Yw]的像素目前是不是歸屬于OpenGL ES所有结澄。例如:如果一個(gè)顯示OpenGL ES幀緩存區(qū)View被另一個(gè)View所遮蔽,則窗口系統(tǒng)可以確定被遮蔽的像素不屬于OpenGL ES上下文,從而不全部顯示這些像素麻献。而像素歸屬測(cè)試是OpenGL ES的一部分们妥,它不由開發(fā)者人為控制而是由OpenGL ES內(nèi)部進(jìn)行。

裁剪測(cè)試:裁剪測(cè)試確定[Xw,Yw]是否位于作為OpenGL ES狀態(tài)的一部分裁剪矩形范圍內(nèi)勉吻,如果該片段位于裁剪區(qū)域之外监婶,則被拋棄。

深度測(cè)試:輸入片段的深度值進(jìn)行比較齿桃,確定片段是否拒絕測(cè)試惑惶。

混合:混合將新生成的片段顏色與保存在幀緩存區(qū)的位置的顏色值組合起來(lái)。(這里的混合與片元著色器的混合要區(qū)別開來(lái)短纵。)

抖動(dòng):抖動(dòng)可用于最小化因?yàn)槭褂糜邢蘧仍趲彺鎱^(qū)中保存顏色值而產(chǎn)生的偽像带污。

EGL(作為了解)

OpenGL ES 命令需要渲染上下文和繪制表面才能完成圖形圖像的繪制。
渲染上下文:存儲(chǔ)的是相關(guān)OpenGL ES 狀態(tài)
繪制表面: 是用于繪制圖元的表面,它指定渲染所需要的緩存區(qū)類型,例如顏?緩存區(qū),深度緩沖區(qū)和模板緩存區(qū).

OpenGL ES API 并沒(méi)有提供如何創(chuàng)建渲染上下文或者上下文如何連接到原生窗口系統(tǒng). EGL 是Khronos 渲染API(如OpenGL ES) 和原生窗口系統(tǒng)之間的接口.唯一?持 OpenGL ES 卻不支持EGL 的平臺(tái)是iOS. Apple 提供?自?的EGL API的iOS實(shí)現(xiàn),稱為EAGL.
因?yàn)槊總€(gè)窗口系統(tǒng)都有不同的定義,所以EGL提供基本的不透明類型—EGLDisplay, 這個(gè)類型封裝了所有系統(tǒng)相關(guān)性,?于和原生窗?系統(tǒng)接口.
由于OpenGL ES是基于C的API踩娘,因此它非常便攜且受到?泛支持。作為C API喉祭,它與
Objective-C Cocoa Touch應(yīng)?程序?縫集成养渴。OpenGL ES規(guī)范沒(méi)有定義窗口層; 相
反,托管操作系統(tǒng)必須提供函數(shù)來(lái)創(chuàng)建一個(gè)接受命令的OpenGL ES 渲染上下文和一個(gè)幀緩沖區(qū)泛烙,其中寫入任何繪圖命令的結(jié)果理卑。在iOS上使?用OpenGL ES需要使?iOS類來(lái)設(shè)置和呈現(xiàn)繪圖表面,并使?平臺(tái)中立的API來(lái)呈現(xiàn)其內(nèi)容蔽氨。

EGL的主要功能如下:

  1. 和本地窗?系統(tǒng)(native windowing system)通訊;
  2. 查詢可用的配置;
  3. 創(chuàng)建OpenGL ES可用的“繪圖表面”(drawing surface);
  4. 同步不同類別的API之間的渲染藐唠,?如在OpenGL ES和OpenVG之間同步,或者在
    OpenGL和本地窗口的繪圖命令之間;
  5. 管理“渲染資源”鹉究,?比如紋理映射(rendering map)宇立。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市自赔,隨后出現(xiàn)的幾起案子妈嘹,更是在濱河造成了極大的恐慌,老刑警劉巖绍妨,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件润脸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡他去,警方通過(guò)查閱死者的電腦和手機(jī)毙驯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)灾测,“玉大人爆价,你說(shuō)我怎么就攤上這事。” “怎么了允坚?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵魂那,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我稠项,道長(zhǎng)涯雅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任展运,我火速辦了婚禮活逆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拗胜。我一直安慰自己蔗候,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布埂软。 她就那樣靜靜地躺著锈遥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勘畔。 梳的紋絲不亂的頭發(fā)上所灸,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音炫七,去河邊找鬼爬立。 笑死,一個(gè)胖子當(dāng)著我的面吹牛万哪,可吹牛的內(nèi)容都是我干的侠驯。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼奕巍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吟策!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起的止,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤踊挠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后冲杀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體效床,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年权谁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了剩檀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旺芽,死狀恐怖沪猴,靈堂內(nèi)的尸體忽然破棺而出辐啄,到底是詐尸還是另有隱情,我是刑警寧澤运嗜,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布壶辜,位于F島的核電站,受9級(jí)特大地震影響担租,放射性物質(zhì)發(fā)生泄漏砸民。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一奋救、第九天 我趴在偏房一處隱蔽的房頂上張望岭参。 院中可真熱鬧,春花似錦尝艘、人聲如沸演侯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秒际。三九已至,卻和暖如春狡汉,著一層夾襖步出監(jiān)牢的瞬間娄徊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工轴猎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嵌莉,地道東北人进萄。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓捻脖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親中鼠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子可婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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