OpenGL的正面&背面剔除和深度測(cè)試

渲染中可能會(huì)出現(xiàn)的問(wèn)題(不希望出現(xiàn)的幾何圖形)

默認(rèn)情況下,我們所渲染的每個(gè)點(diǎn)、線或三角形都會(huì)在[圖片上傳中...(opengl1.png-b3c9f6-1625020212941-0)]
屏幕上進(jìn)行光柵化,并按照在組合圖元批次時(shí)指定的順序排列,這在某些情況下會(huì)產(chǎn)生問(wèn)題。

如果我們繪制一個(gè)由很多個(gè)三角形組成的實(shí)體對(duì)象,那么第一個(gè)繪制的三角形可能會(huì)被后面繪制的三角形覆蓋。如下圖這個(gè)像游泳圈似的模型,其中一些三角形在游泳圈的背面,另一些在正面,正常我們應(yīng)該是看不到背面的(不考慮透明幾何體的特殊情況)。這樣的話,三角形繪制的順序可能會(huì)一團(tuán)糟,就變成了下圖的樣子:


opengl1.png

解決方法

1.油畫(huà)法(painters algorithm):

對(duì)這些三角形排序,先渲染較遠(yuǎn)的三角形,再在它們上方渲染較近的三角形。但這種方法在圖形處理中效率很低,必須在任何發(fā)生重疊的地方對(duì)每個(gè)像素進(jìn)行兩次寫(xiě)操作,速度會(huì)變慢。并且對(duì)獨(dú)立的三角形排序的開(kāi)銷會(huì)過(guò)高。所以一般不推薦使用。

2. 正面&背面剔除:

對(duì)正面和背面三角形進(jìn)行區(qū)分的原因之一就是為了進(jìn)行剔除。背面剔除能極大提高性能,避免上圖出現(xiàn)的問(wèn)題。它很高效,在渲染的圖元裝配階段就整體拋棄了一些三角形。

開(kāi)啟背面剔除:

glEnable(GL_CULL_FACE);

關(guān)閉背面剔除:

glDisable(GL_CULL_FACE);

請(qǐng)注意,我們并沒(méi)有知名剔除的是正面還是背面。這是由另外一個(gè)函數(shù) glCullFace 控制的。

void glCullFace(GLenum mode);

mode 參數(shù)的可用值為 GL_FRONT、GL_BACK 或 GL_FRONT_AND_BACK。這樣要消除不透明物體的內(nèi)部幾何圖形就需要兩行代碼:

void glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);

在某些情況下,剔除實(shí)體幾何體的正面也很有必要,比如要顯示圖形內(nèi)部渲染的時(shí)候。在渲染透明對(duì)象時(shí)(下面馬上就會(huì)講到混合),我們經(jīng)常會(huì)對(duì)一個(gè)對(duì)象進(jìn)行兩次渲染,第一次會(huì)開(kāi)啟透明并剔除正面,第二次則消除背面。這樣就在渲染正面之前渲染了背面,這也是渲染透明物體的需要。

但是在開(kāi)啟背面剔除后,會(huì)發(fā)現(xiàn)上面的游泳圈模型還是顯示的有問(wèn)題,原因沒(méi)有開(kāi)啟深度測(cè)試。如圖:


opengl2.png

3. 深度測(cè)試:

  • 深度: 深度就是在openGL坐標(biāo)系中,像素點(diǎn)的 Z 坐標(biāo)距離觀察者的距離。觀察者可能放在坐標(biāo)系的任何位置,那么,就不能簡(jiǎn)單的說(shuō) Z 數(shù)值越大或越小,就是越靠近觀察者。
    如果觀察者在Z軸的正方向,Z 值大的靠近觀察者,如果是在Z軸的反方向,則 Z 值小的更靠近觀察者。
  • 深度緩沖區(qū)(DepthBuffer): 深度緩沖區(qū)原理就是把一個(gè)距離觀察平面(近裁剪面)的深度值(或距離)與窗口中的每個(gè)像素相關(guān)聯(lián)。
    首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值設(shè)置為最大值。
    如果啟用了深度緩沖區(qū),在繪制每個(gè)像素之前,OpenGL會(huì)把它的深度值和已經(jīng)存儲(chǔ)在這個(gè)像素的深度值進(jìn)行比較。如果,新像素深度值 < 原先像素深度值,則新像素值會(huì)取代原先的;反之,新像素值被遮擋,它的顏色值和深度將被丟棄。
    這個(gè)比較、丟棄的過(guò)程就叫做 深度測(cè)試,深度測(cè)試是另一種高效消除隱藏面的技術(shù)。

申請(qǐng)一個(gè)顏色緩沖區(qū)和一個(gè)深度緩沖區(qū):

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);

要啟用深度測(cè)試,只需調(diào)用

glEnable(GL_DEPTH_TEST);

關(guān)閉深度測(cè)試:

glDisable(GL_DEPTH_TEST);

如果沒(méi)有深度緩沖區(qū),那么啟動(dòng)深度測(cè)試的命令將被忽略。
在繪制場(chǎng)景前,清除顏色緩沖區(qū)和深度緩沖區(qū):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

開(kāi)啟了深度測(cè)試后,我們終于得到了一個(gè)我們想要的游泳圈模型:


opengl3.png

清除深度緩沖區(qū)的默認(rèn)值是1.0,表示最大的深度值,深度值的范圍在[0,1]之間。
用戶通過(guò)glDepthFunc(GLenum func)函數(shù)指定深度測(cè)試的規(guī)則,這個(gè)函數(shù)包括一個(gè)參數(shù),如下表:

參數(shù) 說(shuō)明
GL_ALWAYS 總是通過(guò)測(cè)試
GL_NEVER 總是不通過(guò)測(cè)試
GL_LESS 當(dāng)前深度值 < 存儲(chǔ)的深度值時(shí)通過(guò)
GL_EQUAL 當(dāng)前深度值 = 存儲(chǔ)的深度值時(shí)通過(guò)
GL_LEQUAL 當(dāng)前深度值 <= 存儲(chǔ)的深度值時(shí)通過(guò)
GL_GREATER 當(dāng)前深度值 > 存儲(chǔ)的深度值時(shí)通過(guò)
GL_NOTEQUAL 當(dāng)前深度值 != 存儲(chǔ)的深度值時(shí)通過(guò)
GL_GEQUAL 當(dāng)前深度值 >= 存儲(chǔ)的深度值時(shí)通過(guò)

z-fighting(z沖突、閃爍)問(wèn)題:

當(dāng)深度值精確度很低時(shí),容易引起ZFighting現(xiàn)象,表現(xiàn)為兩個(gè)物體靠的很近時(shí)確定誰(shuí)在前,誰(shuí)在后時(shí)出現(xiàn)了歧義。問(wèn)題表現(xiàn)如圖:

opengl4.png
  • 在第二次繪制時(shí),插入一個(gè)少量的偏移。
  • 使用 glPolygonOffset 函數(shù)調(diào)節(jié)片段的深度值,使得深度值偏移而不產(chǎn)生重疊。
  • 使用更高位數(shù)的深度緩沖區(qū),通常使用的深度緩沖區(qū)是24位的,現(xiàn)在有一些硬件使用使用32位的緩沖區(qū),使精確度得到提高。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、渲染中可能會(huì)出現(xiàn)的問(wèn)題(不希望出現(xiàn)的幾何圖形) 默認(rèn)情況下,我們所渲染的每個(gè)點(diǎn)、線或三角形都會(huì)再屏幕上進(jìn)行光柵...
    凡幾多閱讀 1,980評(píng)論 0 4
  • 正背面剔除的理解和解決方案: 在渲染過(guò)程中可能會(huì)產(chǎn)生以下這個(gè)問(wèn)題: 問(wèn)題:為什么會(huì)產(chǎn)生像圖片那樣的問(wèn)題,會(huì)出現(xiàn)一大...
    iOS_滄海一笑閱讀 397評(píng)論 0 0
  • 在繪制3D圖形時(shí),應(yīng)該判斷哪些面對(duì)于觀察者可見(jiàn),哪些面對(duì)于觀察者不可見(jiàn)。不可見(jiàn)部分應(yīng)該及時(shí)丟棄,以提高渲染效率。專...
    MrDemon_閱讀 623評(píng)論 0 0
  • 在繪制3D圖形時(shí),應(yīng)該判斷哪些面對(duì)于觀察者可見(jiàn),哪些面對(duì)于觀察者不可見(jiàn)。不可見(jiàn)部分應(yīng)該及時(shí)丟棄,以提高渲染效率。專...
    ugpass閱讀 340評(píng)論 0 0
  • 一、繪制甜甜圈 上篇文中已經(jīng)實(shí)現(xiàn)由OpenGL圖元繪制一些簡(jiǎn)單的圖形,今天我們來(lái)嘗試?yán)L制一個(gè)甜甜圈并且看下會(huì)不會(huì)有...
    Sheisone閱讀 1,072評(píng)論 1 0

友情鏈接更多精彩內(nèi)容