OpenGL學習(四)-- 正面&背面剔除和深度測試

個人 OpenGL 專題學習目錄,但願和你們一塊兒學習交流進步!編程


1、渲染中可能會出現的問題(不但願出現的幾何圖形)

默認狀況下,咱們所渲染的每一個點、線或三角形都會再屏幕上進行光柵化,並按照在組合圖元批次時指定的順序排列,這在某些狀況下會產生問題。緩存

若是咱們繪製一個由不少個三角形組成的實體對象,那麼第一個繪製的三角形可能會被後面繪製的三角形覆蓋。以下圖這個像游泳圈似的模型,其中一些三角形在游泳圈的背面,另外一些在正面,正常咱們應該是看不到背面的(不考慮透明幾何體的特殊狀況)。這樣的話,三角形繪製的順序可能會一團糟,就變成了下圖的樣子:函數

存在問題的圖形.png

2、解決方法

1. 油畫法(painters algorithm):

對這些三角形排序,先渲染較遠的三角形,再在它們上方渲染較近的三角形。但這種方法在圖形處理中效率很低,必須在任何發生重疊的地方對每一個像素進行兩次寫操做,速度會變慢。而且對獨立的三角形排序的開銷會太高。因此通常不推薦使用。post

2. 正面&背面剔除:

對正面和背面三角形進行區分的緣由之一就是爲了進行剔除。背面剔除能極大提升性能,避免上圖出現的問題。它很高效,在渲染的圖元裝配階段就總體拋棄了一些三角形。性能

開啓背面剔除: glEnable(GL_CULL_FACE);學習

關閉背面剔除: glDisable(GL_CULL_FACE);測試

請注意,咱們並無知名剔除的是正面仍是背面。這是由另一個函數 glCullFace 控制的。spa

void glCullFace(GLenum mode);
複製代碼

mode 參數的可用值爲 GL_FRONTGL_BACKGL_FRONT_AND_BACK。這樣要消除不透明物體的內部幾何圖形就須要兩行代碼:.net

void glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
複製代碼

在某些狀況下,剔除實體幾何體的正面也頗有必要,好比要顯示圖形內部渲染的時候。在渲染透明對象時(下面立刻就會講到混合),咱們常常會對一個對象進行兩次渲染,第一次會開啓透明並剔除正面,第二次則消除背面。這樣就在渲染正面以前渲染了背面,這也是渲染透明物體的須要。3d

可是在開啓背面剔除後,會發現上面的游泳圈模型仍是顯示的有問題,如圖:

未開啓深度測試.png
這是由於沒有開啓深度測試。

3. 深度測試:

  • 深度:

深度 就是在 openGL 座標系中,像素點的 Z 座標距離觀察者的距離。觀察者可能放在座標系的任何位置,那麼,就不能簡單的說 Z 數值越大或越小,就是越靠近觀察者。 若是觀察者在Z軸的正方向,Z 值大的靠近觀察者,若是是在Z軸的反方向,則 Z 值小的更靠近觀察者。

  • 深度緩衝區(DepthBuffer):

深度緩衝區 原理就是把一個距離觀察平面(近裁剪面)的深度值(或距離)與窗口中的每一個像素相關聯。 首先,使用 glClear(GL_DEPTH_BUFFER_BIT),把全部像素的深度值設置爲最大值。 若是啓用了深度緩衝區,在繪製每一個像素以前,OpenGL 會把它的深度值和已經存儲在這個像素的深度值進行比較。若是,新像素深度值 < 原先像素深度值,則新像素值會取代原先的;反之,新像素值被遮擋,它的顏色值和深度將被丟棄。 這個比較、丟棄的過程就叫作 深度測試,深度測試是另外一種高效消除隱藏面的技術。

申請一個顏色緩衝區和一個深度緩衝區:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
複製代碼

啓用 深度測試,只需調用 glEnable(GL_DEPTH_TEST);

關閉 深度測試: glDisable(GL_DEPTH_TEST);

若是沒有深度緩衝區,那麼啓動深度測試的命令將被忽略。 在繪製場景前,清除顏色緩衝區和深度緩衝區:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
複製代碼

開啓了深度測試後,咱們終於獲得了一個咱們想要的游泳圈模型:

完美的游泳圈.png

清除深度緩衝區的默認值是1.0,表示最大的深度值,深度值的範圍在[0,1]之間。 用戶經過 glDepthFunc(GLenum func) 函數指定深度測試的規則,這個函數包括一個參數,以下表:

參數 說明
GL_ALWAYS 老是經過測試
GL_NEVER 老是不經過測試
GL_LESS 當前深度值 < 存儲的深度值時經過
GL_EQUAL 當前深度值 = 存儲的深度值時經過
GL_LEQUAL 當前深度值 <= 存儲的深度值時經過
GL_GREATER 當前深度值 > 存儲的深度值時經過
GL_NOTEQUAL 當前深度值 != 存儲的深度值時經過
GL_GEQUAL 當前深度值 >= 存儲的深度值時經過

z-fighting(z衝突、閃爍)問題:

閃爍問題.png
當深度值精確度很低時,容易引發ZFighting現象,表現爲兩個物體靠的很近時肯定誰在前,誰在後時出現了歧義。

  • 避免深度值相同形成的z-fighting衝突問題的幾種作法:
    1. 在第二次繪製時,插入一個少許的偏移。
    1. 使用 glPolygonOffset 函數調節片斷的深度值,使得深度值偏移而不產生重疊。
    1. 使用更高位數的深度緩衝區,一般使用的深度緩衝區是 24 位的,如今有一些硬件使用使用 32 位的緩衝區,使精確度獲得提升。

以上的總結參考了並部分摘抄瞭如下文章,很是感謝如下做者的分享!:

一、《OpenGL超級寶典 第5版》

二、《OpenGL編程指南(第八版)》

三、做者 The fool 的《OpenGL學習腳印:深度測試(depth testing)》

四、做者 lysc_forever的《OpenGL中的深度、深度緩存、深度測試》

轉載請備註原文出處,不得用於商業傳播——凡幾多

相關文章
相關標籤/搜索