1. 程式人生 > >OpenGL學習腳印:深度測試(depth testing)

OpenGL學習腳印:深度測試(depth testing)

寫在前面
上一節我們使用AssImp載入了3d模型,效果已經令人激動了。但是繪製效率和場景真實感還存在不足,接下來我們還是要保持耐心,繼續學習一些高階主題,等學完後面的高階主題,我們再次來改進我們載入模型的過程。本節將會學習深度測試,文中示例程式原始碼均可以在我的github下載

通過本節可以瞭解到

  • 為什麼需要深度緩衝區?
  • OpenGL中怎麼使用深度緩衝區 ?
  • 視覺化深度值
  • 深度值的精度問題-ZFighting

問題背景

在繪製3D場景的時候,我們需要決定哪些部分對觀察者是可見的,或者說哪些部分對觀察者不可見,對於不可見的部分,我們應該及早的丟棄,例如在一個不透明的牆壁後的物體就不應該渲染。這種問題稱之為

隱藏面消除(Hidden surface elimination),或者稱之為找出可見面(Visible surface detemination)。

解決這一問題比較簡單的做法是畫家演算法(painter’s algorithm)。畫家演算法的基本思路是,先繪製場景中離觀察者較遠的物體,再繪製較近的物體。例如繪製下面圖中的物體(來自Z buffer 和 W buffer 簡介),先繪製紅色部分,再繪製黃色,最後繪製灰色部分,即可解決隱藏面消除問題。

畫家演算法舉例

使用畫家演算法時,只要將場景中物體按照離觀察者的距離遠近排序,由遠及近的繪製即可。畫家演算法很簡單,但另一方面也存在缺陷,例如下面的圖中,三個三角形互相重疊的情況,畫家演算法將無法處理:

畫家演算法失效

解決隱藏面消除問題的演算法有很多,具體可以參考Visible Surface Detection。結合OpenGL,我們使用的是Z-buffer方法,也叫深度緩衝區Depth-buffer。

深度緩衝區(Detph buffer)同顏色緩衝區(color buffer)是對應的,顏色緩衝區儲存的畫素的顏色資訊,而深度緩衝區儲存畫素的深度資訊。在決定是否繪製一個物體的表面時,首先將表面對應畫素的深度值與當前深度緩衝區中的值進行比較,如果大於等於深度緩衝區中值,則丟棄這部分;否則利用這個畫素對應的深度值和顏色值,分別更新深度緩衝區和顏色緩衝區。這一過程稱之為深度測試(Depth Testing)。在OpenGL中執行深度測試時,我們可以根據需要指定深度值的比較函式,後面會詳細介紹具體使用。

OpenGL中使用深度測試

深度緩衝區一般由視窗管理系統,例如GLFW來建立,深度值一般由16位,24位或者32位值表示,通常是24位。位數越高的話,深度的精確度越好。前面我們已經見過了如何在OpenGL中使用深度測試,這裡複習下過程。首先我們需要開啟深度測試,預設是關閉的:

   glEnable(GL_DEPTH_TEST);

另外還需要在繪製場景前,清除顏色緩衝區時,清除深度緩衝區:

   glClearColor(0.18f, 0.04f, 0.14f, 1.0f);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

清除深度緩衝區的預設值是1.0,表示最大的深度值,深度值的範圍在[0,1]之間,值越小表示越靠近觀察者,值越大表示遠離觀察者。
上面提到了在進行深度測試時,當前深度值和深度緩衝區中的深度值,進行比較的函式,可以由使用者通過glDepthFunc指定,這個函式包括一個引數,具體的引數如下表所示:

函式 說明
GL_ALWAYS 總是通過測試
GL_NEVER 總是不通過測試
GL_LESS 在當前深度值 < 儲存的深度值時通過
GL_EQUAL 在當前深度值 = 儲存的深度值時通過
GL_LEQUAL 在當前深度值 <= 儲存的深度值時通過
GL_GREATER 在當前深度值 > 儲存的深度值時通過
GL_NOTEQUAL 在當前深度值 不等於 儲存的深度值時通過
GL_GEQUAL 在當前深度值 >= 儲存的深度值時通過

例如我們可以使用GL_AWALYS引數,這與預設不開啟深度測試效果是一樣的:

  glDepthFunc(GL_ALWAYS);

下面我們繪製兩個立方體和一個平面,通過對比開啟和關閉深度測試來理解深度測試。
當關閉深度測試時,我們得到的效果卻是這樣的:
沒有啟用深度測試
這裡先繪製立方體,然後繪製平面,如果關閉深度測試,OpenGL只根據繪製的先後順序決定顯示結果。那麼後繪製的平面遮擋了一部分先繪製的本應該顯示出來的立方體,這種效果是不符合實際的。

我們開啟深度測試後繪製場景,得到正常的效果如下:
這裡寫圖片描述

使用深度測試,最常見的錯誤時沒有使用glEnable(GL_DEPTH_TEST);
開啟深度測試,或者沒有使用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);清除深度緩衝區。

與深度緩衝區相關的另一個函式是glDepthMask,它的引數是布林型別,GL_FALSE將關閉緩衝區寫入,預設是GL_TRUE,開啟了深度緩衝區寫入。

視覺化深度值

在視覺化深度值之前,首先我們要明白,這裡的深度值,實際上是螢幕座標系下的zwin座標,螢幕座標系下的(x,y)座標分別表示螢幕座標系下以左下角(0,0)為起始點的座標。zwin我們如何獲取呢? 可以通過著色器的輸入變數gl_FragCoord.z來獲取,這個gl_FragCoord的z座標表示的就是深度值。

我們在著色器中以這個深度值為顏色輸出:

  // 原樣輸出
float asDepth()
{
  return gl_FragCoord.z;
}
void main()
{
    float depth = asDepth();
    color = vec4(vec3(depth), 1.0f);
}

輸出後的效果如下圖所示:
預設深度值視覺化

可以看到圖中,只有離觀察者較近的部分有些黑色,其餘的都是白色。這是因為深度值zwinzeye是成非線性關係的,在離觀察者近的地方,精確度較高,zwin值都保持在較小範圍,成黑色。但是一旦超出一定距離,精確度變小,zwin值都擠在1.0附近,因此成白色。當我們向後移動,拉遠場景與觀察者的距離後,zwin值都落在1.0附近,整個場景都變成白色,如下圖所示:
當拉遠場景與觀察者距離後深度值都變為1.0

作為深度值的視覺化,我們能不能使用線性的關係來表達zwinzeye ? 這裡我們做一個嘗試,從zwinz_{eye}$。在投影矩陣和視口變換矩陣一節,我們計算出了相機座標系下座標和規範化裝置座標系下座標之間的關係如下:

zndc=f+nfnzeye2fnfnzeye=f+nfn+2fn(fn)zeye(1)

繼而可以得到規範化裝置座標系和螢幕裝置座標系之間的關係如下:

zwin=fsns2zndc+fs+ns2(2)

預設情況下glDepthRange函式的n=0,f=1,因此從(2)式可以得到:
zwin=12zndc+12(3)
zndc=2zwin1(4)

從式子(1)我們可以得到:
zeye=2fnzndc(fn)(f+n)(5)

上面的式子(5)如果用來作為深度值,由於結果是負數,會被截斷到0.0,結果都是黑色,因此我們對分母進行反轉,寫為式子(6)作為深度值。

zeye=2fn(f+n)znd

相關推薦

OpenGL學習腳印深度測試(depth testing)

寫在前面 上一節我們使用AssImp載入了3d模型,效果已經令人激動了。但是繪製效率和場景真實感還存在不足,接下來我們還是要保持耐心,繼續學習一些高階主題,等學完後面的高階主題,我們再次來改進我們載入模型的過程。本節將會學習深度測試,文中示例程式原始碼均可

OpenGL學習腳印模板測試(stencil testing)

寫在前面 上一節介紹了深度測試,本節繼續學習一個高階主題-模板測試(stencil testing)。模板緩衝同之前介紹的顏色緩衝、深度緩衝類似,通過它我們可以實現很多的特效,例如輪廓、鏡面效果,陰影效果等。本節示例程式均可以從我的github下載。 通過本

OpenGL學習腳印 反走樣初步(Anti-aliasing basic)

寫在前面 目前,我們繪製的圖形中存在瑕疵的,觀察下面這個立方體: 仔細看,立方體的邊緣部分存在折線,如果我們放大了看,則可以看到這種瑕疵更明顯: 這種繪製的物體邊緣部分出現鋸齒的現象稱之為走樣(aliasing)。反走樣(Anti-

OpenGL學習腳印立方體紋理和天空包圍盒(Cubemaps And Skybox)

寫在前面 之前學習了2D紋理對映,實際上還有其他型別的紋理有待我們進一步學習,本節將要學習的立方體紋理(cubemaps),是一種將多個紋理圖片複合到一個立方體表面的技術。在遊戲中應用得較多的天空包圍盒可以使用cubemap實現。本節示例程式均可

OpenGL學習腳印建立更多的例項(instancing object)

寫在前面 前面我們學習了模型載入的相關內容,併成功載入了模型,令人十分興奮。那時候載入的是少量的模型,如果需要載入多個模型,就需要考慮到效率問題了,例如下圖所示的是載入了400多個納米戰鬥服機器人的效果圖: 渲染一個模型更多的例項,需要使用到例項

OpenGL學習腳印幾何著色器(geometry shader)

寫在前面 一直以來我們使用了頂點著色器(vertex shader)和片元著色器(fragment shader),實際上OpenGL還提供了一個可選的幾何著色器(geometry shader)。幾何著色器位於頂點和片元著色器之間,如果沒有使用時,則

OpenGL學習腳印Blinn-Phong光照模型

寫在前面 在前面基礎光照部分,我們學習了Phong Shading模型,Blinn-Phong模型對Phong模型的鏡面光成分進行了改進,雖然在物理上解釋沒有Phong好,但是能更好地模擬光照。本節程式碼可以在我的github下載。 Phong不

零基礎學習OpenGL(三)--深度測試

       深度緩衝:在每個片段中儲存了資訊,以16、24、32位float的形式儲存它的深度值。(片段著色器執行之後,在螢幕空間中執行。)        當深度測試啟用,OpenGL會將一個片段的深度值和深度緩衝

OpenGL學習筆記常用物件的建立及使用

·頂點陣列物件(Vertex Array Object,VAO) 頂點陣列物件(Vertex Array Object,VAO),用來記錄頂點的資訊,如:位置、資料格式、紋理座標等。使用VAO的好處是:在配置繪製物件的頂點屬性時,你只需要配置一次(VAO會自動記錄你的設定),想要繪製物件

OpenGL學習筆記GLAD和第一個視窗

環境 系統:Windows10 64位 家庭中文版 IDE:Visual Studio 2017 專業版 參考教程:https://learnopengl-cn.github.io/01 Getting started/03 Hello Window/ 步驟 1.獲取GLAD

OpenGL學習筆記編譯GLFW庫

環境 系統:Windows10 64位 家庭中文版 IDE:Visual Studio 2017 專業版 工具:CMake 步驟 1.安裝CMake,CMake最新安裝包:64位 32位; 2.下載GLFW原始碼包,並解壓(記住解壓的路徑,等下要用到,如:D:\glfw-3.2.

機器學習8深度學習——全連線

深度模型最直觀的解釋就是多層網路,最簡單的深度模型是全連線。深度網路的每個全連線層其實質就是一個邏輯迴歸模型,每層包括線性函式與啟用函式。如圖所示: ——全連線細節展示,每一層都是,表示sigmod函式。 ——全連線模型 通過多層組合,可以得到如下的解析模型: 對於模型中的隱藏

分享《TensorFlow學習指南深度學習系統構建詳解》英文PDF+原始碼+部分中文PDF

下載:https://pan.baidu.com/s/1v4B-Jp-lQClBWiCfDd1_dw 更多分享:http://blog.51cto.com/14050756 《TensorFlow學習指南:深度學習系統構建詳解》英文PDF+原始碼+部分中文PDF英文完整版PDF,242頁,帶目錄書籤,彩色

《TensorFlow學習指南深度學習系統構建詳解》英文PDF+原始碼+部分中文PDF

下載:https://pan.baidu.com/s/1v4B-Jp-lQClBWiCfDd1_dw 更多資料:https://pan.baidu.com/s/1g4hv05UZ_w92uh9NNNkCaA 《TensorFlow學習指南:深度學習系統構建詳解》英文PDF+原始碼+部分中文PDF英文完整版

分享《TensorFlow學習指南深度學習系統構建詳解》英文PDF+源代碼+部分中文PDF

size 分布式 部署 模型 -o 卷積神經網絡 ref ima 源代碼 下載:https://pan.baidu.com/s/1v4B-Jp-lQClBWiCfDd1_dw 更多分享:http://blog.51cto.com/14050756 《TensorFlow學習

TensorFlow 學習指南深度學習系統構建詳解

內容簡介 面向廣泛的技術受眾(從資料科學家、工程師到學生和研究人員),本書介紹了 TensorFlow 的基本原理和實踐方法。從 TensorFlow 中的一些基本示例開始,深入探討諸如神經網路體系結構、TensorBoard 視覺化、TensorFlow 抽象庫和多執行緒輸入管道等主題。閱讀本書

OpenGL學習腳印: 模型變換(model transformation)

寫在前面 前面為本節內容準備了向量和矩陣、線性變換等內容,本節開始學習OpenGL中的座標處理。OpenGL中的座標處理過程包括模型變換、視變換、投影變換、視口變換等內容,這個主題的內容有些多,因此分節學習,主題將分為5節內容來學習。本節主要學習模型變

OpenGL學習腳印: 投影矩陣和視口變換矩陣(math-projection and viewport matrix)

寫在前面 前面幾節分別介紹了模型變換,視變換,本節繼續學習OpenGL座標變換過程中的投影變換。這裡主要是從數學角度推導投影矩陣。對數學不感興趣的,可以稍微瞭解下,或者跳過本節內容。 ,這裡對他的推導思路稍微進行了整理。 通過本節可以瞭解到 透

OpenGL學習腳印:模型載入初步-載入obj模型(load obj model)

寫在前面 前面介紹了光照基礎內容,以及材質和lighting maps,和光源型別,我們對使用光照增強場景真實感有了一定了解。但是到目前為止,我們通過在程式中指定的立方體資料,繪製立方體,看起來還是很乏味。本節開始介紹模型載入,通過載入豐富的模型,能夠豐富我們

深度學習大講堂深度學習在目標跟蹤中的應用

本文作者徐霞清,中國科學院計算技術研究所VIPL組碩士生,導師常虹副研究員。研究方向為深度學習與計算機視覺(目標跟蹤等)。 開始本文之前,我們首先看上方給出的3張圖片,它們分別是同一個視訊的第1,40,80幀。在第1幀給出一個跑步者的邊框(bounding-box)