一山孔、渲染中可能會出現(xiàn)的問題(不希望出現(xiàn)的幾何圖形)
默認(rèn)情況下狞贱,我們所渲染的每個點澈缺、線或三角形都會再屏幕上進(jìn)行光柵化草戈,并按照在組合圖元批次時指定的順序排列塌鸯,這在某些情況下會產(chǎn)生問題。
二弹灭、解決方法
1. 油畫法(painters algorithm):
對這些三角形排序,先渲染較遠(yuǎn)的三角形揪垄,再在它們上方渲染較近的三角形穷吮。但這種方法在圖形處理中效率很低,必須在任何發(fā)生重疊的地方對每個像素進(jìn)行兩次寫操作福侈,速度會變慢酒来。并且對獨立的三角形排序的開銷會過高卢未。所以一般不推薦使用肪凛。
2. 正面&背面剔除:
對正面和背面三角形進(jìn)行區(qū)分的原因之一就是為了進(jìn)行剔除。背面剔除能極大提高性能辽社,避免上圖出現(xiàn)的問題伟墙。它很高效,在渲染的圖元裝配階段就整體拋棄了一些三角形滴铅。
開啟背面剔除:
glEnable(GL_CULL_FACE);
關(guān)閉背面剔除:
glDisable(GL_CULL_FACE);
請注意戳葵,我們并沒有知名剔除的是正面還是背面。這是由另外一個函數(shù) glCullFace 控制的汉匙。
void glCullFace(GLenum mode);
mode 參數(shù)的可用值為 GL_FRONT拱烁、GL_BACK 或 GL_FRONT_AND_BACK。這樣要消除不透明物體的內(nèi)部幾何圖形就需要兩行代碼:
void glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
在某些情況下噩翠,剔除實體幾何體的正面也很有必要戏自,比如要顯示圖形內(nèi)部渲染的時候。在渲染透明對象時(下面馬上就會講到混合)伤锚,我們經(jīng)常會對一個對象進(jìn)行兩次渲染擅笔,第一次會開啟透明并剔除正面,第二次則消除背面屯援。這樣就在渲染正面之前渲染了背面猛们,這也是渲染透明物體的需要。
但是在開啟背面剔除后狞洋,會發(fā)現(xiàn)上面的游泳圈模型還是顯示的有問題弯淘,如圖:這是因為沒有開啟深度測試。
3. 深度測試:
- 深度:
深度就是在openGL坐標(biāo)系中吉懊,像素點的 Z 坐標(biāo)距離觀察者的距離耳胎。觀察者可能放在坐標(biāo)系的任何位置惯吕,那么,就不能簡單的說 Z 數(shù)值越大或越小怕午,就是越靠近觀察者废登。
如果觀察者在Z軸的正方向,Z 值大的靠近觀察者郁惜,如果是在Z軸的反方向堡距,則 Z 值小的更靠近觀察者。- 深度緩沖區(qū)(DepthBuffer):
深度緩沖區(qū)原理就是把一個距離觀察平面(近裁剪面)的深度值(或距離)與窗口中的每個像素相關(guān)聯(lián)兆蕉。
首先羽戒,使用glClear(GL_DEPTH_BUFFER_BIT)
,把所有像素的深度值設(shè)置為最大值虎韵。
如果啟用了深度緩沖區(qū)易稠,在繪制每個像素之前,OpenGL會把它的深度值和已經(jīng)存儲在這個像素的深度值進(jìn)行比較包蓝。如果驶社,新像素深度值 < 原先像素深度值,則新像素值會取代原先的测萎;反之亡电,新像素值被遮擋,它的顏色值和深度將被丟棄硅瞧。
這個比較份乒、丟棄的過程就叫做 深度測試,深度測試是另一種高效消除隱藏面的技術(shù)腕唧。
申請一個顏色緩沖區(qū)和一個深度緩沖區(qū):
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
要啟用深度測試或辖,只需調(diào)用
glEnable(GL_DEPTH_TEST);
關(guān)閉深度測試:
glDisable(GL_DEPTH_TEST);
如果沒有深度緩沖區(qū),那么啟動深度測試的命令將被忽略枣接。
在繪制場景前颂暇,清除顏色緩沖區(qū)和深度緩沖區(qū):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
開啟了深度測試后,我們終于得到了一個我們想要的游泳圈模型:清除深度緩沖區(qū)的默認(rèn)值是1.0月腋,表示最大的深度值蟀架,深度值的范圍在[0,1]之間。
用戶通過glDepthFunc(GLenum func)
函數(shù)指定深度測試的規(guī)則榆骚,這個函數(shù)包括一個參數(shù)片拍,如下表:
參數(shù) | 說明 |
---|---|
GL_ALWAYS | 總是通過測試 |
GL_NEVER | 總是不通過測試 |
GL_LESS | 當(dāng)前深度值 < 存儲的深度值時通過 |
GL_EQUAL | 當(dāng)前深度值 = 存儲的深度值時通過 |
GL_LEQUAL | 當(dāng)前深度值 <= 存儲的深度值時通過 |
GL_GREATER | 當(dāng)前深度值 > 存儲的深度值時通過 |
GL_NOTEQUAL | 當(dāng)前深度值 != 存儲的深度值時通過 |
GL_GEQUAL | 當(dāng)前深度值 >= 存儲的深度值時通過 |
z-fighting(z沖突、閃爍)問題:
當(dāng)深度值精確度很低時妓肢,容易引起ZFighting現(xiàn)象捌省,表現(xiàn)為兩個物體靠的很近時確定誰在前,誰在后時出現(xiàn)了歧義碉钠。
- 避免深度值相同造成的z-fighting沖突問題的幾種做法:
- 在第二次繪制時纲缓,插入一個少量的偏移卷拘。
- 使用
glPolygonOffset
函數(shù)調(diào)節(jié)片段的深度值,使得深度值偏移而不產(chǎn)生重疊祝高。
- 使用更高位數(shù)的深度緩沖區(qū)栗弟,通常使用的深度緩沖區(qū)是24位的,現(xiàn)在有一些硬件使用使用32位的緩沖區(qū)工闺,使精確度得到提高乍赫。
以上的總結(jié)參考了并部分摘抄了以下文章,非常感謝以下作者的分享B襟 :
1雷厂、《OpenGL超級寶典 第5版》
2、《OpenGL編程指南(第八版)》
3叠殷、作者 The fool 的《OpenGL學(xué)習(xí)腳痈啮辍:深度測試(depth testing)》
4、作者 lysc_forever的《OpenGL中的深度林束、深度緩存像棘、深度測試》
轉(zhuǎn)載請備注原文出處,不得用于商業(yè)傳播——凡幾多