本文為L_Ares個人寫作武学,包括圖片皆為個人親自操作火窒,以任何形式轉(zhuǎn)載請表明原文出處熏矿。
第八褪储、第九節(jié)的問題還沒有完全解決鲤竹,那么這里就涉及到了深度的問題辛藻。本節(jié)將主要學習深度吱肌。
一氮墨、深度的概念
首先要明確的知道,OpenGL中深度到底是什么東西粒褒?
深度就是該像素點在3D世界中诚镰,距離攝像機的距離清笨,也就是常說的Z值抠艾。
在OpenGL中,有頂點緩沖區(qū)齐苛,有顏色緩沖區(qū)凹蜂,之前的代碼也都有涉及到汰瘫,還有一個經(jīng)常寫混弥,但是沒有說明含義的緩沖區(qū)——深度緩沖區(qū)剑逃。
什么是深度緩沖區(qū)蛹磺?
深度緩沖區(qū)是一塊內(nèi)存區(qū)域,它專門的存儲每個像素點(繪制在屏幕上的)深度值俗或。深度值越大(Z值越大)辛慰,那么該點距離攝像機就越遠帅腌。
為什么需要深度緩沖區(qū)?
因為會出現(xiàn)像素點重復繪制溺职,或者覆蓋的問題浪耘。在不使用深度測試的時候七冲,如果我們先繪制一個距離攝像機更近一點的物體癞埠,再繪制一個距離攝像機較遠的物體苗踪,因為距離遠的物體是后繪制的通铲,就會把先繪制的朋截,距離攝像機更近的物體覆蓋遮擋掉部服。有了深度緩沖區(qū)后廓八,距離攝像機的遠近就不那么的重要剧蹂。
事實上,只要存在深度緩沖區(qū)其爵,OpenGL都會把像素的深度值寫入到深度緩沖區(qū)中窄驹,除非調(diào)用
glDepthMask(GL_FALSE)
在禁止寫入
什么是深度測試抗斤?
深度緩沖區(qū)(DepthBuffer)和顏色緩沖區(qū)(ColorBuffer)是具有聯(lián)系的龙宏。當我們需要繪制一個物體表面的時候辆影,OpenGL會把表面對應的像素點的深度值和深度緩沖區(qū)中的深度值進行大小比較蛙讥,如果需要繪制的表面的深度值大于深度緩沖區(qū)中存儲的深度值,則會丟棄大于深度緩沖區(qū)深度值的這部分的繪制。而沒有大于的這部分則會將他們的像素值和深度值替換掉原有的深度緩沖區(qū)和顏色緩沖區(qū)的存儲值闻妓,這個過程也就是深度測試。
這里有一點很重要@绻Α!限嫌!深度緩沖區(qū)存儲的是像素點的深度,是以像素點未單位的稚叹,而不是你所繪制的圖形的z值,因為你可以繪制很多很多的圖形季率,圖形是存在重疊的情況的鞭光,那么重疊的地方,用的都是相同的像素點啡省,保存的是距離觀察者最近的圖形的z值轉(zhuǎn)換成的像素點的深度,而不是圖形的z值。
關(guān)于深度值到底是怎么計算的徐鹤,會開辟延展節(jié)單獨做學習,內(nèi)容比較多劲赠。
二估蹄、使用深度測試
深度緩沖區(qū)最铁,一般由窗口管理系統(tǒng)GLFW創(chuàng)建,深度值一般由16,24嗤无,32位值表示,默認是24位嘉栓,位數(shù)越高,則深度精確度越好馋辈。
開啟深度測試
glEnable(GL_DEPTH_TEST)
這里要注意的是尔崔,如果開啟了深度測試烙常,則證明需要用到深度緩沖區(qū),那么在之前的代碼中,我們經(jīng)常使用的glClearColor()
和glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
則是必不可少的挣棕。
清除深度緩沖區(qū),其默認值為1.0词身,表示最大的深度值损敷。
深度值的范圍:(0,1)之間溯街。值越小呈昔,表示越靠近觀察者,值越大則越遠離觀察者涡相。
另外,當我們退出這個繪制界面的時候,最好把深度測試關(guān)閉掉犬缨。
深度測試判斷式
void glDepthFunc(GLenum mode)
參數(shù)選擇及含義如下圖2.1:
打開/阻斷深度值的寫入
void glDepthMask(GLBool value)
GL_TRUE
:開啟深度緩沖區(qū)寫入迷郑。
GL_FALSE
:阻斷深度緩沖區(qū)寫入。
甜甜圈代碼
現(xiàn)在我們補全之前的代碼十电,只需要在void RenderScene()
中的開啟正背面剔除的下面增加下面的代碼即可首妖,因為我們要對比象踊,所以這里添加了if判斷袖外。
if (isDepth) {
glEnable(GL_DEPTH_TEST);
}
else{
glDisable(GL_DEPTH_TEST);
}
現(xiàn)在,這個甜甜圈終于不是破輪胎了熔酷。
但是這就沒問題了嘛躺酒?如果深度值重復了,或者說深度值都相同的話量愧,那會不會還有問題呢浑此?
三料饥、ZFighting閃爍問題
先看一下岸啡,當OpenGL無法分辨深度值大小的時候可能會產(chǎn)生的后果擂送。如圖3.1和圖3.2所示:
這就是ZFighting問題蟀拷。
為什么會出現(xiàn)ZFighting問題呢?
因為當OpenGL開啟了深度測試之后,OpenGL就不會再去繪制模型被遮擋的部分,但是由于深度值的精確度的限制,對于深度值相差非常非常小的情況下衰琐,OpenGL也無法精確的判斷他們的深度值大小掐隐,這就會導致深度測試出現(xiàn)不確定性僧凰,也就會出現(xiàn)這種交錯閃爍的情況虑啤。
如何解決ZFighting問題叉寂?
思路也不難,產(chǎn)生這個問題的原因是深度值差別太小,那么我們給他們之間人為添加一個空隙,騙過OpenGL,這就是多邊形偏移方法。
而且這個空隙都不需要由我們來計算看政,OpenGL有提供方法如下:
第一步:啟用Polygon Offset方法解決
glEnable(GL_POLYGON_OFFSET_FILL)
參數(shù)可選,主要根據(jù)光柵化的模式來選擇參數(shù):
GL_POLYGON_OFFSET_FILL
對應光柵化模式:GL_FILL
GL_POLYGON_OFFSET_POINT
對應光柵化模式:GL_POINT
GL_POLYGON_OFFSET_LINE
對應光柵化模式:GL_LINE
第二步:指定偏移量
通過
void glPolygonOffset(GLFloat factor,GLFloat units)
來指定。每個片元的深度值增加的偏移量如下:
Offset = (m * factor) + (r * units)
m:多邊形的深度的斜率的最大值,多邊形越是與近剪裁面平行,m的值也就越接近0恕出。
r:能產(chǎn)生于窗口坐標系中的可分辨的差異最小值渊抄,r是一個具體的值丧裁,是由OpenGL平臺分配的一個常量煎娇。
一個大于0的Offset會把模型推到離觀察者(攝像機)更遠的位置眨猎,而小于0的Offset會把模型拉近觀察者(攝像機)
一般情況下兰迫,只需要將-1.0和-1賦值給
glPolygonOffset
即可玲躯。
關(guān)閉偏移量
用完了記得關(guān)茅郎。
glDisable(GL_POLYGON_OFFSET_FILL)
如何預防ZFighting問題?
首先就是不要把兩個物體靠的太近框仔∫ㄎ洌可以手動添加一個很小的偏移量,但是不建議离斩,因為如果繪制的物體很多银舱,本身距離又存在相差不大的情況,手動添加偏移量只可能解決這一個的問題洲脂,但是可能會造成新的問題苟耻。
近剪裁面離觀察者遠一點驱闷,因為更遠的情況下,深度值的精度要求也就更高诚欠,但是這種方法可能造成離觀察者近的物體隨著距離增加而剪裁,所以重點是調(diào)試好剪裁面參數(shù)漾岳。
剛才說了深度緩沖區(qū)的位數(shù)有三種轰绵,位數(shù)越高,精度越高尼荆。16左腔、24、32捅儒,默認是24液样,既然24的不行振亮,那就換32位深度緩沖區(qū)。
四鞭莽、剪裁
理解即可双炕。
關(guān)于窗口、視口撮抓、剪裁區(qū)域
先確定這三者的關(guān)系妇斤,下面我用一張圖來說明,如圖4.1所示:
窗口
就是項目的顯示界面視口
窗口中用來顯示圖形的一塊區(qū)域丹拯,一般情況下和窗口內(nèi)平面等大站超。當然也是可以比窗口大或者小。
這里要注意乖酬,超出視口的圖形部分是不予顯示的死相。
我們可以通過glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
函數(shù)設置視口的x,y,w,h剪裁區(qū)域
如圖4.1所示,可以通過void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
函數(shù)來設置咬像。
這里的left和right是用視口矩形區(qū)域的最大和最小x坐標算撮,bottom和top也一樣,只不過用的是y坐標县昂,千萬別用窗口的肮柜。也可以指定最近和最遠的z坐標,這樣就會變成一個立體的剪裁區(qū)域倒彰。
定義
在OpenGL中提高渲染的一種方式审洞,只刷新屏幕上發(fā)生變化的部分。
OpenGL可以做到讓要發(fā)生渲染的窗口只指定一個剪裁框待讳。
原理
用于渲染時限制繪制區(qū)域芒澜,可以在屏幕上指定一個矩形區(qū)域進行繪制,其他的不更新繪制创淡。啟用剪裁測試后痴晦,不在矩形區(qū)域內(nèi)的片元被丟棄,只有在矩形區(qū)域內(nèi)的片元才有可能進入幀緩沖琳彩。
就像在屏幕上畫出來一塊矩形區(qū)誊酌,然后在矩形區(qū)域中可以進行指定內(nèi)容的繪制。
使用方法
- 開啟剪裁測試
glEnable(GL_SCISSOR_TEST)
- 關(guān)閉剪裁測試
glEnable(GL_SCISSOR_TEST)
- 指定剪裁窗口
void glScissor(GLint x,GLint y,GLsizei width,GLsizei height)
x,y分別是指定的剪裁窗口的左下角的橫縱坐標值汁针。width,height就是寬高术辐,用來設置剪裁框的尺寸。
至此施无,關(guān)于深度的問題也學習完成了辉词,圓環(huán)也繪制成功了。