關(guān)于OpenGL繪制流程可查看计雌,之前寫(xiě)的一篇文章昧谊,詳細(xì)解讀了各個(gè)繪制步驟
本文主要說(shuō)明在繪制過(guò)程中的正背面剔除以及深度測(cè)試效果;
下載示例代碼運(yùn)行凤价,運(yùn)行效果如下圖鸽斟,能夠正常繪制出甜甜圈的效果,可以偷偷的笑開(kāi)心下料仗;
當(dāng)旋轉(zhuǎn)甜甜圈的時(shí)候湾盗,發(fā)現(xiàn)如下圖所示問(wèn)題,在旋轉(zhuǎn)的過(guò)程中立轧,出現(xiàn)了黑色的部分格粪,這個(gè)看起來(lái)可不太友好;面對(duì)如此問(wèn)題該如何解決呢氛改?
在繪制3D場(chǎng)景的時(shí)候,我們需要決定哪些部分是對(duì)觀察者可?的,或者哪些部分是對(duì)觀察者不可見(jiàn)的.對(duì)于不可見(jiàn)的部分,應(yīng)該及早丟棄.例如在一個(gè)不透明的墻壁后,就不應(yīng)該 渲染.這種情況叫做”隱藏?面消除”(Hidden surface elimination).
解決方案:
油畫(huà)算法
先繪制場(chǎng)景中的離觀察者較遠(yuǎn)的物體,再繪制較近的物體(具體步驟見(jiàn)上圖帐萎,先繪制紅色方塊,接著是黃色圓形胜卤,接著是灰色長(zhǎng)方形)疆导,即可解決隱藏面消除的問(wèn)題;
油畫(huà)畫(huà)法弊端
使?油畫(huà)算法,只要將場(chǎng)景按照物理距離觀察者的距離遠(yuǎn)近排序,由遠(yuǎn)及近的繪制即可.那么會(huì)出現(xiàn)什么問(wèn)題??如果個(gè)三?形是疊加的情況,油畫(huà)算法將?法處理
OpenGL提供的解決方案:
正背面剔除(Face Culling)
可以想像下葛躏,當(dāng)我們看到一個(gè)3D圖形時(shí)澈段,無(wú)論從哪個(gè)方向去觀察,最多可以看到幾個(gè)面舰攒?~~~答案是3個(gè)败富;基于此,那么就沒(méi)有必要繪制根本看不到的3個(gè)面摩窃,將看不到的3個(gè)面以某種方式丟棄兽叮,OpenGL的渲染性能即可提高50%
OpenGL?可以做到檢查所有正面朝向觀察者的面,并渲染它們.從而丟棄背?朝向的面.?這樣可以節(jié)約片元著?器的性能
glEnable(GL_CULL_FACE);//開(kāi)啟正面剔除
glDisable(GL_CULL_FACE);//關(guān)閉正面剔除
當(dāng)開(kāi)啟正面剔除后,運(yùn)行demo會(huì)看到如下效果猾愿,prefect~
上面提到了正面鹦聪、背面兩個(gè)概念,那么OpenGL是如何識(shí)別正面背面蒂秘,以及是否可以自定義哪個(gè)方向是正面哪個(gè)方向是背面呢泽本?
通過(guò)分析頂點(diǎn)數(shù)據(jù)的順序可知
背面:?按照順時(shí)針頂點(diǎn)連接順序的三?形面
正?:?按照逆時(shí)針頂點(diǎn)連接順序的三?形?
1、左側(cè)三角形頂點(diǎn)順序?yàn)? 1—> 2—> 3 ;?右側(cè)三角形的頂點(diǎn)順序?yàn)? 1—> 2—> 3 .
2姻僧、當(dāng)觀察者在右側(cè)時(shí),則右邊的三?形?向?yàn)槟鏁r(shí)針?向則為正面,而左側(cè)的三?形為順時(shí)針則為背面?
3观挎、當(dāng)觀察者在左側(cè)時(shí),則左邊的三?形為逆時(shí)針?向判定為正面,而右側(cè)的三?角形為順時(shí)針判定為背面.
正面和背面是有三角形的頂點(diǎn)定義順序和觀察者?向共同決定的.隨著觀察者的?度方向的改變,正面背面也會(huì)跟著改變
?戶選擇剔除哪個(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)
glCullFace(GL_BACK);
glFrontFace(GL_CW);?
使用正背面剔除效果后,在旋轉(zhuǎn)的過(guò)程中沒(méi)有黑色陰影出現(xiàn)段化,但是當(dāng)旋轉(zhuǎn)到前后重疊的時(shí)候,會(huì)發(fā)現(xiàn)造成,出現(xiàn)了如下圖所示效果(出現(xiàn)了一個(gè)缺口)显熏?是什么原因?qū)е履兀?/p>
在甜甜圈旋轉(zhuǎn)過(guò)程中喘蟆,當(dāng)旋轉(zhuǎn)到前后兩部分重疊時(shí)缓升,正常情況下應(yīng)該顯示的是離我們近的位置即前面部分,后面部分是隱藏面蕴轨,但是OpenGL中并不能清除的區(qū)分港谊,兩個(gè)圖層誰(shuí)顯示在前,誰(shuí)顯示在后橙弱,由此導(dǎo)致甜甜圈產(chǎn)生了缺口
那么如何解決此問(wèn)題呢歧寺?OpenGL給我們提供了哪些方案呢?
在解決問(wèn)題之前需要了解OpenGL坐標(biāo)體系中的兩個(gè)概念棘脐,深度斜筐、深度緩存區(qū)
深度
深度其實(shí)就是該像素點(diǎn)在3D世界中距離攝像機(jī)的距離,Z值
深度值一般由16位,24位或者32位值表示蛀缝,通常是24位顷链。位數(shù)越高的話,深度的精確度越 好屈梁。深度值的范圍在[0,1]之間
值越?表示越靠近觀察者
值越大表示遠(yuǎn)離觀察者
深度緩存區(qū)?
深度緩存區(qū),就是一塊內(nèi)存區(qū)域,專(zhuān)門(mén)存儲(chǔ)著每個(gè)像素點(diǎn)(繪制在屏幕上的)深度值.存儲(chǔ)在顯存中
深度值(Z值)越?,?則離攝像機(jī)就越遠(yuǎn).
深度值(Z值)越小,?則離攝像機(jī)就越近.
為什么需要深度緩沖區(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ě)?.
還記得在渲染的代碼中有一行就是用來(lái)專(zhuān)門(mén)清除緩存的嗤练,包括顏色緩存、深度緩存在讶;因?yàn)槿绻彺鎱^(qū)不清空煞抬,之前的數(shù)據(jù)會(huì)有殘留,會(huì)對(duì)目前圖形的繪制造成影響真朗;在不清楚清除哪部分?jǐn)?shù)據(jù)的時(shí)候此疹,可以選擇全部清除,如下
//清空顏色遮婶、深度緩存區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
在了解了深度以及深度緩存區(qū)之后蝗碎,在面臨上面缺口問(wèn)題的時(shí)候,OpenGL提供的解決方案就正式出場(chǎng)啦---深度測(cè)試
深度測(cè)試
glEnable(GL_DEPTH_TEST);//開(kāi)啟深度測(cè)試
glDisable(GL_DEPTH_TEST);//關(guān)閉深度測(cè)試
開(kāi)啟深度測(cè)試后旗扑,在繪制過(guò)程中蹦骑,像素點(diǎn)新的深度值需要與深度緩存中已經(jīng)存在的深度值作比較,如果新值 > 舊值臀防,則丟棄這部分不繪制眠菇,反之,將新的深度值更新至深度緩存區(qū)袱衷,由于深度緩存區(qū)與顏色緩存區(qū)是一一對(duì)應(yīng)的捎废,同時(shí)也需要更新該像素點(diǎn)的顏色值到顏色緩存區(qū),這個(gè)過(guò)程就是深度測(cè)試
開(kāi)啟深度測(cè)試后致燥,看看效果登疗,在旋轉(zhuǎn)過(guò)程中,即使前后重疊,也不會(huì)出現(xiàn)缺口的現(xiàn)象辐益,如下圖
深度測(cè)試解決的問(wèn)題:
1断傲、當(dāng)類(lèi)似甜甜圈旋轉(zhuǎn)時(shí),前后2個(gè)部分重疊智政,此時(shí)OpenGL不能清除分辨哪個(gè)圖層在前面认罩,哪個(gè)圖層在后面,則會(huì)出現(xiàn)缺口
2续捂、隱藏面消除垦垂,除了使用正背面剔除外,還可使用深度測(cè)試來(lái)解決