OpenGL高階之深度測試

2021-09-27 18:46:11 字數 3904 閱讀 3879

深度緩衝就像顏色緩衝一樣,在每個片段中儲存了資訊,並且和顏色緩衝有著一樣的寬度和高度。

深度緩衝是由視窗系統自動建立的,它會以16、24或32位float的形式儲存它的深度值。在大部分的系統中,深度緩衝的精度都是24位的。

當深度測試被啟用的時候,opengl會將乙個片段的的深度值與深度緩衝的內容進行對比。

opengl會執行乙個深度測試,如果這個測試通過了的話,深度緩衝將會更新為新的深度值。如果深度測試失敗了,片段將會被丟棄。

深度緩衝是在片元著色器執行之後(以及模板測試(stencil testing)執行之後)在螢幕空間中執行的

螢幕空間座標與通過opengl的glviewport所定義的視口密切相關,並且可以直接使用glsl內建變數gl_fragcoord從片段著色器中直接訪問。gl_fragcoord的x和y分量代表了片段的螢幕空間座標(其中(0, 0)位於左下角)。gl_fragcoord中也包含了乙個z分量,它包含了片段真正的深度值。z值就是需要與深度緩衝內容所對比的那個值

現在大部分的gpu都提供乙個叫做提前深度測試(early depth testing)的硬體特性。提前深度測試允許深度測試在片段著色器之前執行。只要我們清楚乙個片段永遠不會是可見的(它在其他物體之後),我們就能提前丟棄這個片段。

片段著色器通常開銷都是很大的,所以我們應該盡可能避免執行它們。當使用提前深度測試時,片段著色器的乙個限制是你不能寫入片段的深度值。如果乙個片段著色器對它的深度值進行了寫入,提前深度測試是不可能的。opengl不能提前知道深度值。

深度測試預設是禁用的,所以如果要啟用深度測試的話,我們需要用gl_depth_test選項來啟用它:

glenable

(gl_depth_test)

;

當它啟用的時候,如果乙個片段通過了深度測試的話,opengl會在深度緩衝中儲存該片段的z值;如果沒有通過深度緩衝,則會丟棄該片段。

如果你啟用了深度緩衝,你還應該在每個渲染迭代之前使用gl_depth_buffer_bit來清除深度緩衝,否則你會仍在使用上一次渲染迭代中的寫入的深度值:

glclear

(gl_color_buffer_bit | gl_depth_buffer_bit)

;

在某些情況下你會需要對所有片段都執行深度測試並丟棄相應的片段,但不希望更新深度緩衝,opengl允許我們禁用深度緩衝的寫入,只需要設定它的深度掩碼(depth mask)設定為gl_false就可以了:

gldepthmask

(gl_false)

;

opengl允許我們修改深度測試中使用的比較運算子。這允許我們來控制opengl什麼時候該通過或丟棄乙個片段,什麼時候去更新深度緩衝。

可以呼叫gldepthfunc函式來設定比較運算子

預設情況下使用的深度函式是gl_less,它將會丟棄深度值大於等於當前深度緩衝值的所有片段

深度緩衝包含了乙個介於0.0和1.0之間的深度值,它將會與觀察者視角所看見的場景中所有物體的z值進行比較。

觀察空間的z值可能是投影平截頭體的近平面(near)和遠平面(far)之間的任何值

需要一種方式來將這些觀察空間的z值變換到[0, 1]範圍之間,其中的一種方式就是將它們線性變換到[0, 1]範圍之間。下面這個(線性)方程將z值變換到了0.0到1.0之間的深度值:

然而,在實踐中是幾乎永遠不會使用這樣的線性深度緩衝(linear depth buffer)的。要想有正確的投影性質,需要使用乙個非線性的深度方程,它是與 1/z 成正比的。

它做的就是在z值很小的時候提供非常高的精度,而在z值很遠的時候提供更少的精度

由於非線性方程與 1/z 成正比,在1.0和2.0之間的z值將會變換至1.0到0.5之間的深度值,這就是乙個float提供給我們的一半精度了,這在z值很小的情況下提供了非常大的精度。在50.0和100.0之間的z值將會只佔2%的float精度,這正是我們所需要的。這樣的乙個考慮了遠近距離的方程是這樣的:

深度值很大一部分是由很小的z值所決定的,這給了近處的物體很大的深度精度

片元著色器中,內建gl_fragcoord向量的z值包含了那個特定片段的深度值。如果我們將這個深度值輸出為顏色,我們可以顯示場景中所有片段的深度值

void

main()

螢幕空間中的深度值是非線性的,即它在z值很小的時候有很高的精度,而z值很大的時候有較低的精度。

片段的深度值會隨著距離迅速增加,所以幾乎所有的頂點的深度值都是接近於1.0的。如果我們小心地靠近物體,你可能會最終注意到顏色會漸漸變暗,顯示它們的z值在逐漸變小

這很清楚地展示了深度值的非線性性質。近處的物體比起遠處的物體對深度值有著更大的影響。只需要移動幾厘公尺就能讓顏色從暗完全變白。

可以讓片段非線性的深度值變換為線性的

首先將深度值從[0, 1]範圍重新變換到[-1, 1]範圍的標準化裝置座標

首先我們將深度值變換為ndc

float z = depth *

2.0-

1.0;

接下來使用獲取到的z值,應用逆變換來獲取線性的深度值:

float lineardepth =

(2.0

* near * far)

/(far + near - z *

(far - near)

);

乙個很常見的視覺錯誤會在兩個平面或者三角形非常緊密地平行排列在一起時會發生,深度緩衝沒有足夠的精度來決定兩個形狀哪個在前面

結果就是這兩個形狀不斷地在切換前後順序,這會導致很奇怪的花紋

深度衝突是深度緩衝的乙個常見問題,當物體在遠處時效果會更明顯(因為深度緩衝在z值比較大的時候有著更小的精度)。深度衝突不能夠被完全避免,但一般會有一些技巧有助於在你的場景中減輕或者完全避免深度衝突

第乙個也是最重要的技巧是永遠不要把多個物體擺得太靠近,以至於它們的一些三角形會重疊

第二個技巧是盡可能將近平面設定遠一些精度在靠近近平面時是非常高的,所以如果我們將近平面遠離觀察者,我們將會對整個平截頭體有著更大的精度。然而,將近平面設定太遠將會導致近處的物體被裁剪掉,所以這通常需要實驗和微調來決定最適合你的場景的近平面距離。

另外乙個很好的技巧是犧牲一些效能,使用更高精度的深度緩衝。大部分深度緩衝的精度都是24位的,但現在大部分的顯示卡都支援32位的深度緩衝,這將會極大地提高精度。所以,犧牲掉一些效能,你就能獲得更高精度的深度測試,減少深度衝突

openGL 深度測試

opengl裡常出現深度測試,一直不清楚。今天就來弄清楚。1 什麼是深度?深度其實就是該象素點在3d世界中距離攝象機的距離 繪製座標 深度快取中儲存著每個象素點 繪製在螢幕上的 的深度值!深度值 z值 越大,則離攝像機越遠。深度值是存貯在深度快取裡面的,我們用深度快取的位數來衡量深度快取的精度。深度...

openGL 深度測試

opengl裡常出現深度測試,一直不清楚。今天就來弄清楚。1 什麼是深度?深度其實就是該象素點在3d世界中距離攝象機的距離 繪製座標 深度快取中儲存著每個象素點 繪製在螢幕上的 的深度值!深度值 z值 越大,則離攝像機越遠。深度值是存貯在深度快取裡面的,我們用深度快取的位數來衡量深度快取的精度。深度...

openGL 深度測試

opengl裡常出現深度測試,一直不清楚。今天就來弄清楚。1 什麼是深度?深度其實就是該象素點在3d世界中距離攝象機的距離 繪製座標 深度快取中儲存著每個象素點 繪製在螢幕上的 的深度值!深度值 z值 越大,則離攝像機越遠。深度值是存貯在深度快取裡面的,我們用深度快取的位數來衡量深度快取的精度。深度...