OpenGL中的正面&背面剔除和深度測試

一山孔、渲染中可能會出現(xiàn)的問題(不希望出現(xiàn)的幾何圖形)

默認(rèn)情況下狞贱,我們所渲染的每個點澈缺、線或三角形都會再屏幕上進(jìn)行光柵化草戈,并按照在組合圖元批次時指定的順序排列塌鸯,這在某些情況下會產(chǎn)生問題。

如果我們繪制一個由很多個三角形組成的實體對象唐片,那么第一個繪制的三角形可能會被后面繪制的三角形覆蓋丙猬。如下圖這個像游泳圈似的模型涨颜,其中一些三角形在游泳圈的背面,另一些在正面茧球,正常我們應(yīng)該是看不到背面的(不考慮透明幾何體的特殊情況)庭瑰。這樣的話,三角形繪制的順序可能會一團(tuán)糟抢埋,就變成了下圖的樣子:
存在問題的圖形.png

二弹灭、解決方法

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)上面的游泳圈模型還是顯示的有問題弯淘,如圖:
未開啟深度測試.png

這是因為沒有開啟深度測試。

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);

開啟了深度測試后,我們終于得到了一個我們想要的游泳圈模型:
完美的游泳圈.png

清除深度緩沖區(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沖突、閃爍)問題:

閃爍問題.png

當(dāng)深度值精確度很低時妓肢,容易引起ZFighting現(xiàn)象捌省,表現(xiàn)為兩個物體靠的很近時確定誰在前,誰在后時出現(xiàn)了歧義碉钠。

  • 避免深度值相同造成的z-fighting沖突問題的幾種做法:
    1. 在第二次繪制時纲缓,插入一個少量的偏移卷拘。
    1. 使用 glPolygonOffset 函數(shù)調(diào)節(jié)片段的深度值,使得深度值偏移而不產(chǎn)生重疊祝高。
    1. 使用更高位數(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è)傳播——凡幾多

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诊县,一起剝皮案震驚了整個濱河市讲弄,隨后出現(xiàn)的幾起案子措左,更是在濱河造成了極大的恐慌依痊,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怎披,死亡現(xiàn)場離奇詭異胸嘁,居然都是意外死亡,警方通過查閱死者的電腦和手機凉逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門性宏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人状飞,你說我怎么就攤上這事毫胜。” “怎么了诬辈?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵酵使,是天一觀的道長。 經(jīng)常有香客問我焙糟,道長口渔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任穿撮,我火速辦了婚禮缺脉,結(jié)果婚禮上痪欲,老公的妹妹穿的比我還像新娘。我一直安慰自己攻礼,他們只是感情好业踢,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礁扮,像睡著了一般陨亡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上深员,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天负蠕,我揣著相機與錄音,去河邊找鬼倦畅。 笑死遮糖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叠赐。 我是一名探鬼主播欲账,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芭概!你這毒婦竟也來了赛不?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤罢洲,失蹤者是張志新(化名)和其女友劉穎踢故,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惹苗,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡殿较,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了桩蓉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淋纲。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖院究,靈堂內(nèi)的尸體忽然破棺而出洽瞬,到底是詐尸還是另有隱情,我是刑警寧澤业汰,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布伙窃,位于F島的核電站,受9級特大地震影響蔬胯,放射性物質(zhì)發(fā)生泄漏对供。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望产场。 院中可真熱鬧鹅髓,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至醒串,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鄙皇,已是汗流浹背芜赌。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伴逸,地道東北人缠沈。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像错蝴,于是被迫代替她去往敵國和親洲愤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容