一、正背面踢除(Face Culling)
在渲染3D場景過程中可能會產生以下問題
- 我們需要決定哪些部分是對觀察者可?的,或者哪些部分是對觀察者不可見的?
- 對于不可見的我們應該怎么處理?
解決方案
1. 油畫算法
- 先繪制場景中較遠的物體,再繪制較近的物體
弊端
- 使?用油畫算法,只要將場景按照物理理距離觀察者的距離遠近排序,由遠及近的繪制即可.那么會出現 什什么問題? 如果三個三?角形是疊加的情況,油畫算法將?無法處理理.
2. 正背面踢除(Face Culling)
以一個正方形為例,我們正常看到的只有三個面,那么背后三個看不見的面就可以不用繪制,
如果我們丟棄這部分數據,OpenGL的渲染速度提升50%;
OpenGL 可以做到檢查所有正?面朝向觀察者的?面,并渲染它們.從?而丟棄背?面朝向的?面. 這樣可以 節約?片元著?色器器的性能.
OpenGL通過分析頂點數據的順序來判斷哪個是正面,哪個是背面。
一般我們繪制三角形的時候,使用逆時針繪制時時正面,順時針繪制時時背面。
3.使用方法
- 開啟表面面剔除(默認背?面剔除)
void glEnable(GT_CULL_FACE);
- 關閉表面踢除
void glDisable(GL_CULL_FACE);
- 用戶踢除哪個面(正面/背面)
void glCullFace(GLenum mode);
mode參數為:GL_FONT,GL_BACK,GL_FONT_BACK, 默認GL_BACK
- 用戶指定的哪個繞續為正面
void glFontFace(GLenum mode);
mode參數:GL_CW、GL_GL_CCW,默認GL_CCW;
4.使用例子
- 踢除正面實現1
void glCullFace(GL_FONT);
- 踢除正面實現1
void glCullFace(GL_BACK);
void glFontFace(CL_CW);
二、深度
1. 了解深度
1.1 什么是深度?
深度就是在3D世界中的世界坐標系中距離相機的距離,就是z值。
1.2 深度緩沖區
深度緩沖區就是一塊內存區域,專門存儲每個像素點的深度值,深度值(z值)越大,距離相機越遠
1.3 為什么需要深度緩沖區
在不使?深度測試的時候,如果我們先繪制一個距離比較近的物體,再繪制距離較遠的物體,則距離遠的位圖因為后繪制,會把距離近的物體覆蓋掉. 有了深度緩沖區后,繪制物體的順序就不那么??重要的. 實際上,只要存在深度緩沖區,OpenGL 都會把像素的深度值寫入到緩沖區中. 除?調? glDepthMask(GL_FALSE)
.來禁?寫?
2.深度測試
深度緩沖區和顏色緩沖區是相對應的。顏色緩沖區存儲著像素的顏色信息,深度緩沖區存儲著像素的深度信息。再決定繪制一個物體表面時,首先要拿當前像素的深度值與深度緩沖區的深度值進行比較,如果大于深度緩沖區的深度值就丟棄,否則使用這個像素像素的對應的顏色值和深度值繪制,分別更新深度緩沖區和顏色緩沖區。這叫深度測試。
2.1 使用深度測試
- 開啟深度測試
glEnable(GL_DEPTH_TEST);
在繪制場景前,清除顏?色緩存區,深度緩沖
glClearColor(1.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
清除深度緩沖區默認值為1.0,表示最大的深度值,深度值的范圍為(0,1)之間. 值越?表示越靠近觀察者,值越大表示 越遠離觀察者
- 關閉深度測試
glDisable(GL_DEPTH_TEST);
- 指定深度測試判斷模式
void glDepthFunc(GLEnum mode);
函數 | 說明 |
---|---|
GL_ALWAYS | 總是測試通過的 |
GL_NEVER | 總是不通過測試 |
GL_LESS | 當前深度值 < 存儲的深度值時通過(默認) |
GL_EQUAL | 當前深度值 = 存儲的深度值時通過 |
GL_LLEQUAL | 當前深度值 <= 存儲的深度值時通過 |
GL_GREARTER | 當前深度值 > 存儲的深度值時通過 |
GL_NOTEQUAL | 當前深度值 != 存儲的深度值時通過 |
GL_GEQUAL | 當前深度值 >= 存儲的深度值時通過 |
- 打開/阻斷 深度緩存區寫?入
// value : GL_TURE 開啟深度緩沖區寫入; GL_FALSE 關閉深度緩沖區寫?
void glDepthMask(GLBool value);
四、ZFighting閃爍問題
1. 問題原因
因為開啟深度測試后,OpenGL 就不會再去繪制模型被遮擋的部分. 這樣實現的顯示更加真實.但是 由于深度緩沖區精度的限制對于深度相差?常小的情況下.(例如在同?平?上進行2次繪制),OpenGL 就可能出現不能正確判斷兩者的深度值,會導致深度測試的結果不可預測.顯示出來的 現象時交錯閃爍.的前面2個畫面,交錯出現
2.解決辦法
第1步、啟用 Polygon Offset 方式解決
解決方法: 讓深度值之間產生間隔.如果2個圖形之間有間隔,是不是意味著就不會產??涉.可以理解為在執行深度測試前將立?體的深度值做?些細微的增加.于是就能將??疊的2個圖形深度值之前有所區分.
//啟?用Polygon Offset ?方式
glEnable(GL_POLYGON_OFFSET_FILL)
參數列列表:
GL_POLYGON_OFFSET_POINT 對應光柵化模式: GL_POINT
GL_POLYGON_OFFSET_LINE 對應光柵化模式: GL_LINE
GL_POLYGON_OFFSET_FILL 對應光柵化模式: GL_FILL
第2步、指定偏移量
-
通過glPolygonOffset 來指定.glPolygonOffset 需要2個參數: factor , units 每個Fragment 的深度值都會增加如下所示的偏移量量:
Offset = ( m * factor ) + ( r * units);
m : 多邊形的深度的斜率的最大值,理解一個多邊形越是與近裁剪?平行,m 就越接近于0.
r : 能產?于窗口坐標系的深度值中可分辨的差異最小值.r 是由具體OpenGL 平臺指定的?個常量. 一個?于0的Offset 會把模型推到離你(攝像機)更遠的位置,相應的?個小于0的Offset 會把模型拉近
?般?言,只需要將-1.0 和 -1 這樣簡單賦值給glPolygonOffset 基本可以滿?足需求.
第3步: 關閉Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)
2.2 ZFighting閃爍問題預防
不要將兩個物體靠的太近,避免渲染時三?角形疊在一起。這種方式要求對場景中物體插入?一個少量的偏移,那么就可能避免ZFighting現象。例如上面的立?體和平面問題中,將平面下移0.001f就可以解決這個問題。當然手動去插入這個小的偏移是要付出代價的。
盡可能將近裁剪面設置得離觀察者遠一些。上?我們看到,在近裁剪平?附近,深度的精確度是很高的,因此盡可能讓近裁剪面遠一些的話,會使整個裁剪范圍內的精確度變?高一些。但是這種?式會使離觀察者較近的物體被裁減掉,因此需要調試好裁剪面參數。
使用更高位數的深度緩沖區,通常使用的深度緩沖區是24位的,現在有?些硬件使?32位的緩沖區,使精確度得到提高
五 剪裁
在OpenGL 中提?渲染的一種?式.只刷新屏幕上發?變化的部分.OpenGL允許將要進?渲染的窗?只去指定一個裁剪框.
基本原理:?于渲染時限制繪制區域,通過此技術可以再屏幕(幀緩沖)指定一個矩形區域。
啟?剪裁測試之后,不在此矩形區域內的片元被丟棄,只有在此矩形區域內的片元才有可能進?幀緩沖。因此實際達到的效果就是在屏幕上開辟了一個小窗?,可以再其中進行指定內容的繪制。
//1 開啟裁剪測試 glEnable(GL_SCISSOR_TEST);
//2.關閉裁剪測試 glDisable(GL_SCISSOR_TEST);
//3.指定裁剪窗?口
void glScissor(Glint x,Glint y,GLSize width,GLSize height);
x
,y
:指定裁剪框左下?角位置; width
, height
:指定裁剪尺?寸
六 混合
我們把OpenGL 渲染時會把顏色值存在顏色緩存區中,每個片段的深度值也是放在深度緩沖區。當深度緩沖區被關閉時,新的顏色將簡單的覆蓋原來顏色緩存區存在的顏色值,當深度緩沖區再次打開時,新的顏色片段只是當它們比原來的值更接近鄰近的裁剪平面才會替換原來的顏??段。
glEnabled(GL_BLEND);
1.組合顏色公式
?標顏?:已經存儲在顏色緩存區的顏色值
源顏?:作為當前渲染命令結果進入顏色緩存區的顏?值
當混合功能被啟動時,源顏色和?標顏色的組合方式是混合?程式控制的。在默認情況下,混合?程式如下所示:
Cf = (Cs * S) + (Cd * D)
Cf :最終計算參數的顏?
Cs :源顏?
Cd :?標顏?
S :源混合因?
D :?標混合因?
1.1混合因子
設置混合因子,需要?到glBlendFun
函數
glBlendFunc(GLenum S,GLenum D);
S:源混合因?
D:?標混合因?
表中R、G、B、A 分別代表 紅、綠、藍、alpha。
表中下標S、D,分別代表源、目標
表中C 代表常量顏?(默認?色)
1.2
下?通過?個常見的混合函數組合來說明問題;
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
如果顏?緩存區已經有一種顏色紅色(1.0f,0.0f,0.0f,0.0f),這個?標顏色Cd,如果在這上面??種alpha為0.6的藍色(0.0f,0.0f,1.0f,0.6f)
Cd (?標顏色) = (1.0f,0.0f,0.0f,0.0f);
Cs (源顏色) = (0.0f,0.0f,1.0f,0.6f);
S = 源alpha值 = 0.6f
D = 1 - 源
alpha值= 1-0.6f = 0.4f
?程式Cf = (Cs * S) + (Cd * D)
等價于 = (Blue * 0.6f) + (Red * 0.4f)