一步步學(xué)習(xí)計算機視覺in IOS(三)OpenGL渲染-3D遮蓋問題處理

image.png

在繪制3D場景時,為了盡可能的逼真需要有近大遠(yuǎn)小的效果,而且可能會出現(xiàn)互相遮蓋的情況。

image.png

對于OpenGL中渲染的多邊形而言,遮蓋的問題同樣存在,一個物體在光照下是有兩面的:陽面(光照覆蓋的面)和陰面(背光的面),上圖中黃色部分就是我們理解的陽面,黑色即為陰面,但是上圖的甜甜圈
看起來特別奇怪,本該顯示陽面的部分確顯示了陰面。OpenGL需要判斷當(dāng)前需要展示的渲染數(shù)據(jù)。

如果我們不進(jìn)行判斷,那么OpenGL不知道該顯示哪些界面,只根據(jù)繪制的先后順序決定顯示結(jié)果,就會導(dǎo)致本來是觀察者不應(yīng)該看到且該丟棄部分,不僅看到了,而且沒有將隱藏部分丟棄。

不進(jìn)行判斷的后果

下面讓我們使用lines圖元來看下為何會黑化。


image.png
image.png

在渲染系統(tǒng)中,各種復(fù)雜的圖像都是由普通的三角形組成的。因為我們沒有處理覆蓋問題,OpenGL不知道1和2兩個圖元的渲染順序,導(dǎo)致圖元2中的黑色元素替換了1中的元素,出現(xiàn)黑色。

正背面剔除

那么,如果OpenGL可以做到檢查所有正面朝向觀察者的面,可以輕松地獲取渲染順序。此外,背后朝向的面則不再渲染,也可以節(jié)約片元著色器的性能。

OpenGL是通過分析頂點順序來區(qū)分正背面的,默認(rèn)情況下是按照逆時針頂點連接順序的三?形?為正面,按照順時針頂點連接順序的三角形?為背面。

image.png

那么,我們只要渲染正面圖元1,不渲染反面圖元2,就可以得到正確的渲染數(shù)據(jù)。

但是,有沒有可能相互覆蓋的圖元都是正面的呢?這也是有可能的。

1
2

如上圖所示,圖1中的兩塊圖元區(qū)域都是正面的,如果旋轉(zhuǎn)到這兩塊區(qū)域重疊,那么正背面剔除法是無法解決的。

image.png

深度混合

就上圖的情況,如何渲染是依賴于觀察者的。對觀察者而言,離觀察者更近的區(qū)域應(yīng)該渲染。那么如何定義渲染物體與觀察者的距離呢?為了解決這個問題,就需要引入深度以及深度緩沖區(qū)的概念:

  • 深度是指OpenGL坐標(biāo)系中,像素點的Z坐標(biāo)距觀察者的距離

深度與圖形中像素點的Z坐標(biāo)有如下關(guān)系:
如果觀察者在Z軸的正方向,Z值越大則越靠近觀察者
如果觀察者在Z軸的負(fù)方向,Z值越小則越靠近觀察者

  • 深度緩沖區(qū)是用來存儲繪制到屏幕上每一個像素點的深度信息的—塊內(nèi)存緩沖區(qū)。它為每個像素存儲一個深度值(z值),深度緩沖區(qū)的大小和顏色緩沖區(qū)(Frame Buffer)的大小一致。

在代碼中,我們此次刷新時都要清空的數(shù)據(jù)中,就有深度緩沖區(qū):

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

深度測試

一個物體在繪制時,像素點新的深度值需要與深度緩存中已經(jīng)存在的深度值作比較,如果 新值 > 舊值,說明該像素點離觀察者較遠(yuǎn),丟棄新像素不繪制,反之,將新的深度值更新至深度緩存區(qū),繪制新像素。

Z-Fighting(Z沖突,閃爍)問題

深度測試中比對了像素的Z值,那么如果Z值相等,或者說差值極小呢?這就會帶來Z-Fighting問題。

image.png

其問題產(chǎn)生的主要原因是由于圖形靠的太近,導(dǎo)致無法區(qū)分出圖層先后次序,針對該問題,OpenGL提供了一種多邊形偏移(Polygon Offset)方案,讓深度值之間產(chǎn)生間隔,避免干涉。

//開啟Polygon Offset
glEnable(GL_POLYGON_OFFSET_FILL)
//指定偏移量
//參數(shù)一般填 -1 和 -1
glPolygonOffset (GLfloat factor, GLfloat units);
// 關(guān)閉Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL);

混合

在深度測試中,我們直接用深度較淺的圖元的渲染數(shù)據(jù)替換了之前的渲染數(shù)據(jù),但是如果我們想讓遮蓋的新圖元透明,那么就需要進(jìn)行顏色混合了。

OpenGL渲染時會把顏色值存在顏?緩存區(qū)中,每個?段的深度值也是放在深度緩沖區(qū)。

  • 當(dāng)深度緩沖區(qū)被關(guān)閉時,新的顏色將簡單地覆蓋原來顏色緩存區(qū)存在的顏色值。
  • 當(dāng)深度緩沖區(qū)再次打開時,新的顏?片段只是當(dāng)它們比原來的值更接近鄰近的裁剪平?才會替換原來的顏?片段。
//開啟混合
gl_Enable(GL_BIEND);
  • ?標(biāo)顏色:已經(jīng)存儲在顏色緩存區(qū)的顏色值 (已經(jīng)存在的顏色,舊顏色)
  • 源顏色:作為當(dāng)前渲染命令結(jié)果進(jìn)入顏色緩存區(qū)的顏?值 (新進(jìn)來的顏色 ,新顏色)
    混合后的顏色有顏色方程式?jīng)Q定:
//Cf: 最終計算參數(shù)的顏?
//Cs: 源顏?
//Cd: 目標(biāo)顏?
//S: 源混合因?,源Alpha混合因子
//D: ?標(biāo)混合因?,?標(biāo)Alpha混合因子
Cf = (Cs * S) + (Cd * D);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容