前言
期待您移步上篇:OpenGL筆記三:固定管線著色器和基本圖元
- 渲染過(guò)程中可能產(chǎn)?的問(wèn)題:
在繪制3D場(chǎng)景的時(shí)候,我們需要決定哪些部分是對(duì)觀察者 可?見(jiàn)的,或者哪些部分是對(duì)觀察者不可?見(jiàn)的.對(duì)于不可?見(jiàn)的 部分,應(yīng)該及早丟棄.例如在?個(gè)不透明的墻壁后,就不應(yīng)該 渲染.這種情況叫做”隱藏?消除”(Hidden surface elimination).
油畫(huà)算法
- 油畫(huà)算法
先繪制場(chǎng)景中的離觀察者較遠(yuǎn)的物體,再繪制較近的物體. - 油畫(huà)法弊端
使?油畫(huà)算法,只要將場(chǎng)景按照物理距離觀察者的距離遠(yuǎn)近排序,由遠(yuǎn)及近的繪制即可.那么會(huì)出現(xiàn) 什么問(wèn)題? 如果三個(gè)三?角形是疊加的情況,油畫(huà)算法將?法處理.
正背?剔除(Face Culling)
嘗試相信?個(gè)3D圖形,你從任何?個(gè)?向去觀察,最多可以看到?個(gè)?? 答案是,最多3?. 從?個(gè)??體的任意位置和?向上看,你?過(guò)不可能看到多于3個(gè)?.那么思考? 我們?yōu)楹我嘤嗟娜ダL制那根本看不到的3個(gè)?? 如果我們能以某種?式去丟棄這部分?jǐn)?shù)據(jù),OpenGL 在渲染的性能即可提?超過(guò)50%.
分析??體中的正背?
- 開(kāi)啟表?剔除(默認(rèn)背?剔除)
void glEnable(GL_CULL_FACE);
- 關(guān)閉表?剔除(默認(rèn)背?剔除)
void glDisable(GL_CULL_FACE);
- ?戶選擇剔除那個(gè)?(正?/背?)
void glCullFace(GLenum mode);
mode參數(shù)為: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默認(rèn)GL_BACK
- ?戶指定繞序那個(gè)為正?
void glFrontFace(GLenum mode);
mode參數(shù)為: GL_CW,GL_CCW,默認(rèn)值:GL_CCW
- 如,剔除正?實(shí)現(xiàn)(1)
glCullFace(GL_BACK);
glFrontFace(GL_CW);
- 如,剔除正?實(shí)現(xiàn)(2)
glCullFace(GL_FRONT);
深度、深度緩沖區(qū)
- 深度其實(shí)就是該像素點(diǎn)在3D世界中距離攝像機(jī)的距離,Z值
- 深度緩存區(qū),就是?塊內(nèi)存區(qū)域,專(zhuān)?門(mén)存儲(chǔ)著每個(gè)像素點(diǎn)(繪制在屏幕上的)深度值.深度值(Z值)越?, 則離攝像機(jī)就越遠(yuǎn).
- 為什么需要深度緩沖區(qū)?
- 在不使?深度測(cè)試的時(shí)候,如果我們先繪制?個(gè)距離?較近的物理,再繪制距離較遠(yuǎn)的物理,則距離 遠(yuǎn)的位圖因?yàn)楹罄L制,會(huì)把距離近的物體覆蓋掉. 有了深度緩沖區(qū)后,繪制物體的順序就不那么重 要的. 實(shí)際上,只要存在深度緩沖區(qū),OpenGL 都會(huì)把像素的深度值寫(xiě)?到緩沖區(qū)中. 除?調(diào)? glDepthMask(GL_FALSE).來(lái)禁?寫(xiě)?.
Z-bu?er?法(深度緩沖區(qū)Depth-bu?er)
- 深度測(cè)試:深度緩沖區(qū)(DepthBu?er)和顏?緩存區(qū)(ColorBu?er)是對(duì)應(yīng)的.顏?緩存區(qū)存儲(chǔ)像素的顏?信 息,?深度緩沖區(qū)存儲(chǔ)像素的深度信息. 在決定是否繪制?個(gè)物體表?時(shí), ?先要將表?對(duì)應(yīng)的像 素的深度值與當(dāng)前深度緩沖區(qū)中的值進(jìn)??較. 如果?于深度緩沖區(qū)中的值,則丟棄這部分.否則 利?這個(gè)像素對(duì)應(yīng)的深度值和顏?值.分別更新深度緩沖區(qū)和顏?緩存區(qū). 這個(gè)過(guò)程稱(chēng)為”深度測(cè) 試”。
使?深度測(cè)試
深度緩沖區(qū),?般由窗?管理系統(tǒng),GLFW創(chuàng)建.深度值?般由16位,24位,32位值表示. 通常是24位.位 數(shù)越?,深度精確度更好.
//開(kāi)啟深度測(cè)試
glEnable(GL_DEPTH_TEST);
//在繪制場(chǎng)景前,清除顏?緩存區(qū),深度緩沖
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
清除深度緩沖區(qū)默認(rèn)值為1.0,表示最?的深度值,深度值的范圍為(0,1)之間. 值越?表示越靠近觀察者,值越?表示 越遠(yuǎn)離觀察者.
- 深度測(cè)試判斷模式
//指定深度測(cè)試判斷模式
void glDepthFunc(GLEnum mode);

- 打開(kāi)/阻斷 深度緩存區(qū)寫(xiě)?
void glDepthMask(GLBool value);
value : GL_TURE 開(kāi)啟深度緩沖區(qū)寫(xiě)?; GL_FALSE 關(guān)閉深度緩沖區(qū)寫(xiě)?
ZFighting閃爍問(wèn)題的原因
- 原因:因?yàn)殚_(kāi)啟深度測(cè)試后,OpenGL 就不會(huì)再去繪制模型被遮擋的部分. 這樣實(shí)現(xiàn)的顯示更加真實(shí).但是 由于深度緩沖區(qū)精度的限制對(duì)于深度相差?常?的情況下.(例如在同?平?上進(jìn)?2次 制),OpenGL 就可能出現(xiàn)不能正確判斷兩者的深度值,會(huì)導(dǎo)致深度測(cè)試的結(jié)果不可預(yù)測(cè).顯示出來(lái)的 現(xiàn)象時(shí)交錯(cuò)閃爍.的前?2個(gè)畫(huà)?,交錯(cuò)出現(xiàn).
- ZFighting閃爍問(wèn)題問(wèn)題解決:
- 啟? Polygon O?set ?式解決
解決?法: 讓深度值之間產(chǎn)?間隔.如果2個(gè)圖形之間有間隔,是不是意味著就不會(huì)產(chǎn)??涉.可以理 解為在執(zhí)?深度測(cè)試前將??體的深度值做?些細(xì)微的增加.于是就能將重疊的2個(gè)圖形深度值之 前有所區(qū)分.
//啟?Polygon O?set ?式 glEnable(GL_POLYGON_OFFSET_FILL)
參數(shù)列表:
GL_POLYGON_OFFSET_POINT 對(duì)應(yīng)光柵化模式: GL_POINT GL_POLYGON_OFFSET_LINE 對(duì)應(yīng)光柵化模式: GL_LINE GL_POLYGON_OFFSET_FILL 對(duì)應(yīng)光柵化模式: GL_FILL
- 指定偏移量
通過(guò)glPolygonO?set 來(lái)指定.glPolygonO?set 需要2個(gè)參數(shù): factor , units
每個(gè)Fragment 的深度值都會(huì)增加如下所示的偏移量:
O?set = ( m * factor ) + ( r * units); m : 多邊形的深度的斜率的最?值,理解?個(gè)多邊形越是與近裁剪?平?,m 就越接近于0.
r : 能產(chǎn)?于窗?坐標(biāo)系的深度值中可分辨的差異最?值.r 是由具體是由具體OpenGL 平臺(tái)指定的 ?個(gè)常量.
?個(gè)?于0的O?set 會(huì)把模型推到離你(攝像機(jī))更遠(yuǎn)的位置,相應(yīng)的?個(gè)?于0的O?set 會(huì)把模型拉 近
?般??,只需要將-1.0 和 -1 這樣簡(jiǎn)單賦值給glPolygonO?set 基本可以滿?需求.
void glPolygonOffset(Gl?oat factor,Gl?oat units);
應(yīng)?到?段上總偏移計(jì)算?程式: Depth Offset = (DZ * factor) + (r * units);
DZ:深度值(Z值) r:使得深度緩沖區(qū)產(chǎn)?變化的最?值
負(fù)值,將使得z值距離我們更近,?正值,將使得z值距離我們更遠(yuǎn), 上次我們?cè)O(shè)置factor和units設(shè)置為-1,-1
- 關(guān)閉Polygon O?set
glDisable(GL_POLYGON_OFFSET_FILL)
ZFighting閃爍問(wèn)題預(yù)防
- 不要將兩個(gè)物體靠的太近,避免渲染時(shí)三?角形疊在?起。這種?式要求對(duì)場(chǎng)景中物體插??個(gè)少量的 偏移,那么就可能避免ZFighting現(xiàn)象。例如上?的??體和平?問(wèn)題中,將平?下移0.001f就可以解 決這個(gè)問(wèn)題。當(dāng)然?動(dòng)去插?這個(gè)?的偏移是要付出代價(jià)的。
- 盡可能將近裁剪?設(shè)置得離觀察者遠(yuǎn)?些。上?我們看到,在近裁剪平?附近,深度的精確度是很? 的,因此盡可能讓近裁剪?遠(yuǎn)?些的話,會(huì)使整個(gè)裁剪范圍內(nèi)的精確度變??些。但是這種?式會(huì)使 離觀察者較近的物體被裁減掉,因此需要調(diào)試好裁剪?參數(shù)。
- 使?更?位數(shù)的深度緩沖區(qū),通常使?的深度緩沖區(qū)是24位的,現(xiàn)在有?些硬件使?使?32位的緩沖 區(qū),使精確度得到提?。
混合
我們把OpenGL 渲染時(shí)會(huì)把顏?值存在顏?緩存區(qū)中,每個(gè)?段的深度值也是放在深度緩沖區(qū)。當(dāng)深度 緩沖區(qū)被關(guān)閉時(shí),新的顏?將簡(jiǎn)單的覆蓋原來(lái)顏?緩存區(qū)存在的顏?值,當(dāng)深度緩沖區(qū)再次打開(kāi)時(shí),新 的顏??段只是當(dāng)它們?原來(lái)的值更接近鄰近的裁剪平?才會(huì)替換原來(lái)的顏??段。
glEnable(GL_BlEND);
組合顏?
- ?標(biāo)顏?:已經(jīng)存儲(chǔ)在顏?緩存區(qū)的顏?值
- 源顏?:作為當(dāng)前渲染命令結(jié)果進(jìn)?顏?緩存區(qū)的顏?值
當(dāng)混合功能被啟動(dòng)時(shí),源顏?和?標(biāo)顏?的組合?式是混合?程式控制的。在默認(rèn)情況 下,混合?程式如下所示:
Cf = (Cs * S) + (Cd * D)
/*
Cf :最終計(jì)算參數(shù)的顏?
Cs : 源顏?
Cd :?標(biāo)顏?
S:源混合因?
D:?標(biāo)混合因?
*/
設(shè)置混合因?
設(shè)置混合因?,需要?到glBlendFun函數(shù)
glBlendFunc(GLenum S,GLenum D);
S:源混合因?
D:?標(biāo)混合因?

圖中R、G、B、A 分別代表 紅、綠、藍(lán)、alpha。
圖中下標(biāo)S、D,分別代表源、?標(biāo)
圖中C 代表常量顏?(默認(rèn)??)
實(shí)例
下?通過(guò)?個(gè)常?見(jiàn)的混合函數(shù)組合來(lái)說(shuō)明問(wèn)題:
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
如果顏?緩存區(qū)已經(jīng)有?種顏?紅?(1.0f,0.0f,0.0f,0.0f),這個(gè)?標(biāo)顏?Cd,如果在這>上??? 種alpha為0.6的藍(lán)?(0.0f,0.0f,1.0f,0.6f)
Cd (?標(biāo)顏?) = (1.0f,0.0f,0.0f,0.0f); Cs (源顏?) = (0.0f,0.0f,1.0f,0.6f); S = 源>alpha值 = 0.6f D = 1 - 源alpha值= 1-0.6f = 0.4f
?程式Cf = (Cs * S) + (Cd * D)
等價(jià)于 = (Blue * 0.6f) + (Red * 0.4f)
- 最終顏?是以原先的紅?(?標(biāo)顏?)與 后來(lái)的藍(lán)?(源顏?)進(jìn)?組合。源顏?的alpha值 越?,添加的藍(lán)?顏?成分越?,?標(biāo)顏?所保留的成分就會(huì)越少。 混合函數(shù)經(jīng)常?于實(shí)現(xiàn)在其他?些不透明的物體前?繪制?個(gè)透明物體的效果。