1, OpenGL 編程模型
2, 管線流程(重點(diǎn),每一個(gè)細(xì)節(jié)都要講清楚)
渲染流水線微姊,就是一系列有序的處理階段的序列酸茴,用于把我們應(yīng)用中的數(shù)據(jù)轉(zhuǎn)化到OpenGL生成一個(gè)最終的圖像。下圖是OpenGL4.3使用的流水線兢交。
上圖中薪捍,藍(lán)色的方塊表示是可編程的shader階段。
OpenGL從我們提供的幾何數(shù)據(jù)(頂點(diǎn)和幾何圖元)出發(fā)配喳,首先使用了一系列shader階段來(lái)處理它:vertex shading酪穿,tessellation shading(它本身就包含了兩種shaders),接著是geometry shading晴裹,然后再傳遞給光柵化程序(rasterizer)被济;光柵化程序?qū)?huì)為每個(gè)在裁剪區(qū)域(clipping region)內(nèi)部的圖元生成fragments,然后再為每個(gè)fragment執(zhí)行一個(gè)fragment shader涧团。
如你所見(jiàn)只磷,shaders真是無(wú)處不在熬酢!不是所有的階段都是需要的钮追。如上面所說(shuō)预厌,只有vertex和fragment shaders是我們必須實(shí)現(xiàn)的。Tessellation和geometry shaders都是可選的元媚。
下面轧叽,我們對(duì)每個(gè)階段進(jìn)行更深入地解釋。下面的內(nèi)容難度系數(shù)五顆星(對(duì)新手惠毁。)犹芹!但是,請(qǐng)堅(jiān)持看下去鞠绰!它們很重要腰埂!
- Vertex Specification
準(zhǔn)備頂點(diǎn)數(shù)組數(shù)據(jù)(vertex array data)
即進(jìn)行頂點(diǎn)規(guī)格定義。應(yīng)用將會(huì)建立一個(gè)有序的頂點(diǎn)列表蜈膨,然后發(fā)送給OpenGL屿笼。這些頂點(diǎn)定義了圖元的邊界。圖元是基本的繪制形狀翁巍,如點(diǎn)驴一、線、三角形灶壶。這些頂點(diǎn)列表是如何被組織成一個(gè)個(gè)圖元的會(huì)在后面的階段里進(jìn)行處理肝断。
這個(gè)階段會(huì)處理一些頂點(diǎn)數(shù)組對(duì)象(Vertex Array Objects)和頂點(diǎn)緩存對(duì)象(Vertex Buffer Objects)。VAO定義了每個(gè)頂點(diǎn)包含的信息驰凛,而VBO則是頂點(diǎn)本身的數(shù)據(jù)所在胸懈。
一個(gè)頂點(diǎn)的數(shù)據(jù)就是一系列頂點(diǎn)屬性(vertex attributes)。每一個(gè)attribute都是一個(gè)數(shù)據(jù)的集合恰响,用于后面的階段進(jìn)行處理趣钱。雖然這些attributes定義了一個(gè)頂點(diǎn),但沒(méi)有要求說(shuō)一個(gè)頂點(diǎn)的attributes集合中必須包含了位置和法線信息胚宦。實(shí)際上首有,attribute數(shù)據(jù)是完全任意的,它們僅僅是“數(shù)據(jù)”枢劝,在這個(gè)準(zhǔn)備階段不會(huì)有人在意你傳遞的到底是什么attribute井联,它們的真正含義會(huì)在頂點(diǎn)處理階段進(jìn)行解讀。
OpenGL要求所有的數(shù)據(jù)都必須存儲(chǔ)在緩存對(duì)象中(buffer objects)您旁。緩存對(duì)象是OpenGL管理的一些內(nèi)存空間烙常。“想要讓我辦事被冒,請(qǐng)先把你的東西放到我的地盤(pán)军掂!”把數(shù)據(jù)放到這些緩存里有很多方法,但最常見(jiàn)的是使用glBufferData()來(lái)實(shí)現(xiàn)昨悼。當(dāng)然這里面還有一些其他步驟蝗锥,我們后面會(huì)講到。
- 向OpenGL發(fā)送數(shù)據(jù)
在我們定義了頂點(diǎn)相關(guān)信息后率触,我們可以通過(guò)調(diào)用OpenGL的繪圖操作來(lái)要求按一個(gè)個(gè)幾何圖元繪制到屏幕上终议。這些操作例如有g(shù)lDrawArrays()。我們后面會(huì)講到葱蝗。這個(gè)繪制的過(guò)程意味著我們把頂點(diǎn)數(shù)據(jù)傳遞給OpenGL服務(wù)器穴张。
- Vertex Processing
對(duì)于通過(guò)繪制命令繪制的每一個(gè)頂點(diǎn),OpenGL將調(diào)用一個(gè)vertex shader來(lái)處理關(guān)于這個(gè)頂點(diǎn)的相關(guān)信息两曼。Vertex shader接受從上個(gè)階段傳遞來(lái)的attribute作為輸入皂甘,然后把每一個(gè)輸入頂點(diǎn)轉(zhuǎn)換成一個(gè)輸出頂點(diǎn)(這個(gè)關(guān)系是1對(duì)1的,不會(huì)多也不會(huì)少)悼凑。和輸入的頂點(diǎn)信息不同偿枕,輸出的頂點(diǎn)數(shù)據(jù)有一些必需的要求——vertex shader必須填充一個(gè)位置信息。
Vertex shaders的復(fù)雜性可以變化非常大户辫,有的很簡(jiǎn)單渐夸,就是僅僅復(fù)制數(shù)據(jù)然后傳遞給下一個(gè)流水線階段,我們稱這種為pass-through shader渔欢;有的很復(fù)雜墓塌,會(huì)執(zhí)行很多操作來(lái)計(jì)算頂點(diǎn)的屏幕位置(通常使用變換矩陣來(lái)完成,后面會(huì)講到)奥额,還可能會(huì)進(jìn)行光照計(jì)算來(lái)計(jì)算頂點(diǎn)的顏色苫幢,或者其他技術(shù)。
通常披坏,一個(gè)應(yīng)用會(huì)包含多個(gè)vertex shader态坦,但同一時(shí)間只有一個(gè)會(huì)被激活(active)。
- Primitive Assembly
Primitive assembly就是把vertex shader輸出的頂點(diǎn)數(shù)據(jù)集合在一起棒拂,并把它組合成一個(gè)圖元的過(guò)程伞梯。用戶渲染的圖元的類(lèi)型決定了這個(gè)過(guò)程是如何工作的。
這個(gè)過(guò)程的輸出是一個(gè)有序的簡(jiǎn)單圖元(點(diǎn)帚屉、線或者三角形)序列谜诫。
- Tessellation Shading
Tessellation,讀 泰斯類(lèi)什攻旦,可以翻譯成曲面細(xì)分喻旷。在vertex shader處理了每一個(gè)頂點(diǎn)的相關(guān)信息后,如果tessellation shader階段被激活的話牢屋,它就會(huì)繼續(xù)處理這些數(shù)據(jù)且预。在后面我們會(huì)看到tessellation使用patchs來(lái)描述一個(gè)對(duì)象的形狀槽袄,并且允許細(xì)化(tessellate)相對(duì)簡(jiǎn)單的patch集合,來(lái)增加幾何圖元的數(shù)量锋谐,提高模型的平滑度和真實(shí)度遍尺。Tessellation Shading階段可以使用兩個(gè)shaders來(lái)控制patch數(shù)據(jù),以及中間一個(gè)固定函數(shù)的tessellator來(lái)生成最終的形狀涮拗。
更多內(nèi)容可以參見(jiàn)這篇文章(雖然是DirectX的乾戏。。三热。)
- Geometry Shading
這一階段允許在光柵化之前處理單獨(dú)的幾何圖元鼓择,包括創(chuàng)建新的圖元。這一階段同樣是可選的就漾,但是會(huì)很有用呐能!后面會(huì)講到。
Geometry shader會(huì)處理每一個(gè)輸入的圖元抑堡,然后返回0個(gè)或更多的輸出圖元催跪。它的輸入是primitive assembly的輸出圖元。因此如果我們按triangle strip看待一個(gè)圖元夷野,那么geometry shader看到的就會(huì)使一系列三角形懊蒸。
然而也有一些輸入的圖元類(lèi)型是專門(mén)為geometry shaders定義的。這些相鄰的圖元可以讓GS了解關(guān)于相鄰頂點(diǎn)的信息悯搔。
GS的輸出可以是0個(gè)多更多的簡(jiǎn)單圖元骑丸。GS可以移除圖元,或者根據(jù)一個(gè)輸入圖元來(lái)輸出更多的圖元來(lái)細(xì)分(tessellate)它們妒貌。GS甚至可以改變圖元的類(lèi)型通危,比如把點(diǎn)圖元編程三角形,把線圖元變成點(diǎn)灌曙。
- Transform Feedback
Geometry shader或者primitive assembly的輸出會(huì)被寫(xiě)入一系列的緩存對(duì)象菊碟。這被稱為transform feedback模式。它允許我們通過(guò)vertex和geometry shaders來(lái)變換數(shù)據(jù)在刺,然后再等待后續(xù)使用逆害。
通過(guò)舍棄光柵化的結(jié)果,流水線可以在這步就停止了蚣驼。這允許transform feedback成為渲染的唯一輸出魄幕。
- 裁剪(Clipping)和剔除(Culling)
然后就進(jìn)入圖元裁剪和適當(dāng)?shù)奶蕹A段了。
裁剪以為著颖杏,如果有圖元處于視野的邊界上纯陨,即一部分在內(nèi)部一部分在外部,那么它就會(huì)被裁剪成一些小的圖元。而且翼抠,vertex shader可以在空間內(nèi)定義一些裁剪平面咙轩,這些裁剪平面又會(huì)引起額外的裁剪。
三角面的剔除同樣在這一階段完成阴颖。處于視野范圍以外臭墨,或者在裁剪平面的邊界內(nèi)部的圖元,都會(huì)被提出膘盖。
- 光柵化(Rasterization)
在裁剪完成后,更新后的圖元就會(huì)被發(fā)送給光柵化程序去生成fragments尤误。那么什么是fragment呢侠畔?一個(gè)fragment可以看成是一個(gè)“候選像素”。這類(lèi)像素在幀緩存中的一塊區(qū)域中损晤。一個(gè)fragment仍可以被拒絕(reject)软棺,并且永遠(yuǎn)不會(huì)更新它的相關(guān)像素位置。
Wiki上把fragment成為是一個(gè)狀態(tài)的集合尤勋,用于計(jì)算一個(gè)像素的最終數(shù)據(jù)喘落。一個(gè)fragment的狀態(tài)包含了它在屏幕空間的位置信息,樣本覆蓋(sample coverage最冰,如果開(kāi)啟了multisampling的話)瘦棋,以及一些其他由vertex或者geometry shader輸出的數(shù)據(jù)。這些數(shù)據(jù)集合是通過(guò)該fragment對(duì)應(yīng)的頂點(diǎn)數(shù)據(jù)進(jìn)行插值計(jì)算而得的暖哨。這個(gè)插值計(jì)算是由輸出這些數(shù)據(jù)的shader定義的赌朋。
處理fragments是后面兩個(gè)階段的任務(wù)——fragment shading和per-fragment操作。
- Fragment Processing
最后一個(gè)我們可以編程控制顏色的階段就是fragment shading篇裁。在這個(gè)階段沛慢,我們使用一個(gè)shader來(lái)決定該fragment的最終顏色(其實(shí)下個(gè)階段,per-fragment操作仍可以進(jìn)行最后的顏色修改)和它的深度值(depth value)达布。在fragment shaders里我們可以進(jìn)行非常強(qiáng)大的紋理映射的工作团甲。如果一個(gè)fragment shader認(rèn)為某個(gè)fragment不應(yīng)該繪制出來(lái),它還可以終結(jié)一個(gè)fragment的處理過(guò)程黍聂。這個(gè)過(guò)程稱為fragment discard躺苦。
一個(gè)fragment shader會(huì)輸出一個(gè)顏色列表、一個(gè)深度值和一個(gè)stencil值产还。Fragment shaders不可以為一個(gè)fragment設(shè)置stencil圾另,但是它們可以控制顏色和深度值。
我們可以想來(lái)區(qū)分vertex shading(包括tessellation和geometry shading)和fragment shading:vertex shading決定了一個(gè)圖元在屏幕上的位置雕沉,而fragment shading使用這些信息來(lái)決定該fragment的顏色集乔。
- Per-Fragment操作
從fragment處理器輸出的fragment數(shù)據(jù)會(huì)再通過(guò)一系列的步驟。
第一個(gè)步驟就是各種剔除檢驗(yàn)(culling tests)。如果開(kāi)啟了stencil test扰路,如果一個(gè)fragment沒(méi)有通過(guò)檢驗(yàn)它就會(huì)被剔除尤溜,而不會(huì)寫(xiě)入到幀緩存中;如果開(kāi)啟了depth test汗唱,如果一個(gè)fragment沒(méi)有通過(guò)檢驗(yàn)它就會(huì)被剔除宫莱,而不會(huì)寫(xiě)入到幀緩存中。只要沒(méi)有通過(guò)任何一個(gè)檢驗(yàn)哩罪,fragments都會(huì)被剔除授霸,不會(huì)添加到幀緩存中。
如果一個(gè)fragment成功通過(guò)了所有的檢測(cè)际插,它就會(huì)直接寫(xiě)入幀緩存中碘耳,更新它的像素顏色(也可能是深度值)。如果blending被開(kāi)啟了框弛,該fragment的顏色會(huì)和當(dāng)前的像素顏色進(jìn)行混合去產(chǎn)生一個(gè)新的顏色辛辨,再寫(xiě)入幀緩存中。
最后瑟枫,fragment數(shù)據(jù)被寫(xiě)入幀緩存中斗搞。Masking operation允許用戶避免寫(xiě)入特定的值。寫(xiě)顏色慷妙、深度和stencil都可以被mask成on或者off僻焚;單獨(dú)的顏色通道也可以。
3, 著色器編程
3, 光照
4, FBO/PBO/VBO/RBO
5, 基礎(chǔ)概念
光柵化:
通俗點(diǎn)說(shuō)膝擂,你告訴GL我要畫(huà)條線溅呢,然后告訴他線兩個(gè)端點(diǎn)的坐標(biāo)是(0,0)和(0猿挚,10)咐旧,那么GL自動(dòng)腦補(bǔ)出中間10個(gè)點(diǎn)的坐標(biāo),這個(gè)過(guò)程就叫光冊(cè)化绩蜻,腦補(bǔ)的方法叫線性差值.復(fù)雜點(diǎn)铣墨,現(xiàn)在我要畫(huà)個(gè)三角形,給他三個(gè)頂點(diǎn)的坐標(biāo)办绝,它會(huì)計(jì)算出里面所有像素的坐標(biāo).再?gòu)?fù)雜點(diǎn)伊约,我不只給頂點(diǎn)坐標(biāo)了,我告訴他(0孕蝉,0)點(diǎn)是白色屡律,(0,10)點(diǎn)是黑色降淮,那么光冊(cè)化就自動(dòng)計(jì)算出中間10個(gè)點(diǎn)每個(gè)點(diǎn)的顏色超埋,自動(dòng)做過(guò)渡的效果.這個(gè)計(jì)算方法還是線性差值.繼續(xù)通俗佑笋,線性差值也沒(méi)啥坯临,小學(xué)算數(shù)罷了秀又,誰(shuí)都會(huì). 不懂就自己計(jì)算如上10個(gè)點(diǎn)的坐標(biāo)帝簇,計(jì)算過(guò)程就是線性差值. 沒(méi)錯(cuò),就這么簡(jiǎn)單.著色器分兩個(gè)部分来庭,一個(gè)頂點(diǎn)妒蔚,一個(gè)片斷,中間就是光冊(cè)化.也就是先頂點(diǎn)處理月弛,計(jì)算出每個(gè)頂點(diǎn)的坐標(biāo),顏色,紋理坐標(biāo)等等肴盏,也可以是任何其它千奇百怪的東西(壽命,溫度,身高,婚否,飯量………). 然后經(jīng)過(guò)光冊(cè)化,給他們差值.最后片斷階段帽衙,你會(huì)獲得每個(gè)像素的坐標(biāo),顏色,紋理,壽命,溫度…… 初學(xué)階段菜皂,你可以把片斷(fragment)理解成像素,其實(shí)意思差別不大佛寿,等你GL入門(mén)了,自然就理解這倆詞有啥區(qū)別了-
光柵化(Rasterize/rasteriztion)
這個(gè)詞兒Adobe官方翻譯成柵格化或者像素化但壮。沒(méi)錯(cuò)冀泻,就是把矢量圖形轉(zhuǎn)化成像素點(diǎn)兒的過(guò)程。我們屏幕上顯示的畫(huà)面都是由像素組成蜡饵,而三維物體都是點(diǎn)線面構(gòu)成的弹渔。要讓點(diǎn)線面,變成能在屏幕上顯示的像素溯祸,就需要Rasterize這個(gè)過(guò)程肢专。就是從矢量的點(diǎn)線面的描述,變成像素的描述焦辅。如下圖博杖,這是一個(gè)放大了1200%的屏幕,前面是告訴計(jì)算機(jī)我有一個(gè)圓形筷登,后面就是計(jì)算機(jī)把圓形轉(zhuǎn)換成可以顯示的像素點(diǎn)剃根。這個(gè)過(guò)程就是Rasterize。
渲染管線(Pipeline)
這個(gè)翻譯尤其不接地氣前方,簡(jiǎn)直就是直譯(pipe管子line線路)狈醉。Pipeline是輸送管道的意思。其實(shí)是指三維渲染的過(guò)程中*顯卡執(zhí)行的惠险、從幾何體到最終渲染圖像的苗傅、數(shù)據(jù)傳輸處理計(jì)算的過(guò)程。著色器(Shader)
這個(gè)翻譯的挺好班巩。畫(huà)畫(huà)的時(shí)候我們經(jīng)常有這么一個(gè)過(guò)程:先打線稿渣慕,再上色。著色器就是用來(lái)做這個(gè)工作的。通常著色器分兩種:1頂點(diǎn)著色器(vertex shader)這個(gè)是告訴電腦如何打線稿的——如何處理頂點(diǎn)摇庙、法線等的數(shù)據(jù)的小程序旱物。2片面著色器(fragment shader)這個(gè)是告訴電腦如何上色的——如何處理光、陰影卫袒、遮擋宵呛、環(huán)境等等對(duì)物體表面的影響,最終生成一副圖像的小程序夕凝。采用了這兩種著色器小程序 的** 數(shù)據(jù)傳輸處理計(jì)算的渲染過(guò)程宝穗,稱之為 可編程管線。世界矩陣/視圖矩陣/投影矩陣
世界矩陣(World Matrix)码秉、視圖矩陣(View Matrix)以及投影矩陣(Projection Matirx);
世界矩陣確定一個(gè)統(tǒng)一的世界坐標(biāo)逮矛,用于組織獨(dú)立的物體形成一個(gè)完整的場(chǎng)景;
視圖矩陣就是我們能看到的那部分場(chǎng)景,由虛擬攝像機(jī)負(fù)責(zé)拍攝转砖;
投影矩陣就是3維物體的平面影射.把三維場(chǎng)景在一個(gè)二維的平面上顯示.
- glfinish() / glflush() 的區(qū)別
OpenGL里會(huì)要用到的兩個(gè)重要函數(shù)须鼎。glFlush和glFinish。
glFlush:將GL命令隊(duì)列中的命令發(fā)送給顯卡并清空命令隊(duì)列府蔗,發(fā)送完立即返回晋控;
glFinish:將GL命令隊(duì)列中的命令發(fā)送給顯卡并清空命令隊(duì)列,顯卡完成這些命令(也就是畫(huà)完了)后返回姓赤。
- 四元素/歐拉角
- 紋理參數(shù)設(shè)置
- 數(shù)據(jù)類(lèi)型/傳遞
- 紋理混合
- 光柵化處理的理解/渲染管線中的各個(gè)階段的處理對(duì)應(yīng)的opengl函數(shù)
- 著色器/程序 使用流程
- 裁剪/剔除
- 深度測(cè)試等各種測(cè)試
- 模板緩沖區(qū)
- 各個(gè)版本的新特性
- 紋理壓縮
- 世界坐標(biāo)系/相機(jī)坐標(biāo)系/物體坐標(biāo)系
世界坐標(biāo)系是一個(gè)特殊的坐標(biāo)系, 他建立了描述其他坐標(biāo)系需要的參考框架,也就是說(shuō)能夠用世界坐標(biāo)系描述其他坐標(biāo)系的位置,而不能用更大的,外部的坐標(biāo)系來(lái)描述世界坐標(biāo)系
物體坐標(biāo)系是和特定物體相關(guān)的坐標(biāo)系, 每個(gè)物體都有他們獨(dú)特的坐標(biāo)系.
相機(jī)坐標(biāo)系和觀察者密切相關(guān).
- mipmap
Mipmap是多級(jí)漸遠(yuǎn)紋理,也是目前應(yīng)用最為廣泛的紋理映射(map)技術(shù)之一赡译。簡(jiǎn)單來(lái)說(shuō),就是實(shí)現(xiàn) “實(shí)物(圖片)看起來(lái)近大遠(yuǎn)小不铆,近處清晰遠(yuǎn)處模糊”的效果蝌焚。它簡(jiǎn)單來(lái)說(shuō)就是一系列的紋理圖像,后一個(gè)紋理圖像是前一個(gè)的二分之一誓斥。多級(jí)漸遠(yuǎn)紋理背后的理念很簡(jiǎn)單:距觀察者的距離超過(guò)一定的閾值只洒,OpenGL會(huì)使用不同的多級(jí)漸遠(yuǎn)紋理,即最適合物體的距離的那個(gè)劳坑。由于距離遠(yuǎn)红碑,解析度不高也不會(huì)被用戶注意到。同時(shí)泡垃,多級(jí)漸遠(yuǎn)紋理另一加分之處是它的性能非常好
-
glDrawElements/ glDrawArrays 區(qū)別
比如畫(huà)一個(gè)由2個(gè)3角形組成的正方形析珊,左上角坐標(biāo)是l,t,右下角坐標(biāo)是r,b
使用glDrawArrays繪制時(shí),畫(huà)2個(gè)三角形蔑穴,需要這樣傳:
(l,t),(r,t),(l,b)
(r,t),(r,b),(l,b)
而用glDrawElements畫(huà)的話可以這樣
float coord[4][2]={{l,t},{r,t},{r,b},{l,b}};
繪制時(shí):
0,1,3
1,2,3
glDrawArrays傳輸或指定的數(shù)據(jù)是最終的真實(shí)數(shù)據(jù),在繪制時(shí)效能更好
而glDrawElements指定的是真實(shí)數(shù)據(jù)的調(diào)用索引,在內(nèi)存/顯存占用上更節(jié)省 OpenGL 優(yōu)化
參考:http://blog.csdn.net/chenchao868/article/details/4768716
http://www.360doc.com/content/15/1205/14/16593919_518090882.shtml
- OpenGL ES 調(diào)試