OpenGL入門第4課--深度

爛筆桿發表於2019-05-25

深度相關的概念

深度

     深度說白了就是距離觀察者的距離,同一個物體的不同頂點距離觀察者的距離不一定相同,所以深度是相對於畫素點的概念。深度就是該畫素點在3D世界中距離攝像機的距離,其實就是該畫素點的Z座標值 。

深度緩衝區

     深度緩衝區就是一塊記憶體區域,專門儲存著每個畫素點(繪製在螢幕上的)深度值.深度值(Z值)越⼤大, 則離攝像機就越遠 。

      深度緩衝區,一般由窗⼝管理系統,GLFW建立.深度值⼀般由16位,24位,32位值表示. 通常是24位.數越高,深度精確度更好 

深度測試

     深度緩衝區(DepthBuffer)和顏色緩衝區(ColorBuffer)是對應的,顏色緩衝區儲存畫素的顏色資訊,而深度緩衝區儲存畫素的深度資訊. 在決定是否繪製一個物體表面時, 首先要將表面對應像素的深度值與當前深度緩衝區中的值進⾏比較. 如果⼤於深度緩衝區中的值,則丟棄這部分.否則利用這個畫素對應的深度值和顏色值.分別更新深度緩衝區和顏色緩衝區. 這個過程稱為”深度測試”。

     例如假設有這麼一種場景:物體A被物體B遮檔了一部分,即A和B有一部分的畫素的x,y座標相同,只有z不同。如圖:

                                  OpenGL入門第4課--深度

      假設沒有深度緩衝區或者不開啟深度測試,如果我們先繪製一個距離⽐較近的物體(B),再繪製距離較遠的物體,則距離遠的點陣圖因為後繪製,會把距離近的物體覆蓋掉. 有了深度緩衝區並且開啟深度測試後,繪製物體的順序就不那麼重要了. 實際上,只要存在深度緩衝區,OpenGL 都會把畫素的深度值寫⼊到緩衝區中. 除⾮調⽤ glDepthMask(GL_FALSE).來禁⽌止寫入. 

指定深度測試比較運算子

       OpenGL允許修改深度測試中使用的比較運算子,來控制OpenGL什麼時候該通過或丟棄一個片段,什麼時候去更新深度緩衝。我們可以呼叫glDepthFunc函式來設定比較運算子。

glDepthFunc(GL_LESS);
複製程式碼

這個函式接受下面表格中的比較運算子:

                     OpenGL入門第4課--深度

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

深度衝突

        由於深度緩衝區精度的限制,一個很常見的視覺錯誤會在兩個平面或者三角形非常緊密地平行排列在一起時會發生,深度緩衝沒有足夠的精度來決定兩個形狀哪個在前面。結果就是這兩個形狀不斷地在切換前後順序,這會導致很奇怪的花紋。這個現象叫做深度衝突(Z-fighting),因為它看起來像是這兩個形狀在爭奪(Fight)誰該處於頂端。

       深度衝突是深度緩衝的一個常見問題,當物體在遠處時效果會更明顯(因為深度緩衝在z值比較大的時候有著更小的精度)一個常用的解決方法就是讓深度值之間產生間隔(Polygon Offset ,多邊形偏移),程式碼如下:

glEnable(GL_POLYGON_OFFSET_FILL) //啟用多邊形偏移
						glPolygonOffset(-1,-1);//指定偏移量複製程式碼

      啟用多邊形偏移的引數有一下三種:

  • GL_POLYGON_OFFSET_POINT:對應光柵化模式: GL_POINT
  • GL_POLYGON_OFFSET_LINE :對應光柵化模式: GL_LINE
  • GL_POLYGON_OFFSET_FILL:對應光柵化模式: GL_FILL

      glPolygonOffset 需要2個引數: factor , units。每個Fragment的深度值都會增加如下所示的偏移量:Offset = ( m * factor ) + ( r * units);m是指多邊形的深度的斜率的最大值,一個多邊形越是與近裁剪⾯平⾏,m就越接近於0. r是指能產⽣於窗⼝座標系的深度值中可分辨的差異最⼩值,它是是由具體OpenGL平臺指定的一個常量.一個大於0的Offset 會把模型推到離你(攝像機)更遠的位置,相應的一個小於0的Offset會把模型拉近。一般而言,只需要將-1.0 和 -1 這樣簡單賦值給glPolygonOffset 基本可以滿足需求.  

      由於OpenGL是狀態機所以用完別忘了關閉多邊形偏移:

glDisable(GL_POLYGON_OFFSET_FILL) 複製程式碼

      深度衝突不能夠被完全避免,但一般會有一些技巧有助於在你的場景中減輕或者完全避免深度衝突。

         第一個也是最重要的技巧是永遠不要把多個物體擺得太靠近,以至於它們的一些三角形會重疊。通過在兩個物體之間設定一個使用者無法注意到的偏移值,你可以完全避免這兩個物體之間的深度衝突。

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

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

       我們上面討論的三個技術是最普遍也是很容易實現的抗深度衝突技術了。還有一些更復雜的技術,但它們依然不能完全消除深度衝突。深度衝突是一個常見的問題,但如果你組合使用了上面列舉出來的技術,你可能不會再需要處理深度衝突了。


相關文章