閱讀了該系列之前幾篇文章,相信大家已經(jīng)對OpenGL渲染流程和基本概念有了一個大致的了解, 這里提醒大家,很多名詞和函數(shù), 可以點進去看下源碼是怎么寫的,另外基本概念切勿死記硬背, 靠敲代碼硬背函數(shù)或者API是不可取的, 要于現(xiàn)實生活的實際場景和例子結(jié)合,才更方便我們記住和系統(tǒng)的了解其原理.
廢話不多說,進入正題.
OpenGL渲染技巧(實際繪制中常用方法)
- 正?&背?剔除
- 深度測試
- 顏色混合
- 多邊形偏移
- 等
在講以上幾個常用方法時我們先來了解下什么是 隱藏面消除
在繪制3D場景的時候议纯,由于觀察者和繪制結(jié)果都只能看到其中的一個面仲翎。對于不會被觀察到的面,則我們無需渲染, 那么這樣我們的渲染效率就會提升50%.
例如:在一個不透明墻壁后的物體,就不應該渲染。這種情況就叫做隱藏面消除(Hidden surface elimination)浓恶。
而如何實現(xiàn)隱藏面消除呢?
實際使用中常用有正?&背?剔除, 深度測試等方法
1.油畫算法
油畫算法如其名所說,按照畫油畫的方式,先把底色繪上,再把上面顏色蓋上,其主要原理如下:
先繪制場景中離觀察者較遠的物體,再繪制較近的物體.
那么實際開發(fā)中有使用油畫算法的嗎? 答案是幾乎沒有. 那么為什么呢
- 首先是性能問題, 對于觀察者/繪制結(jié)果來說我們只會看到繪制在最上面的一層(透明度情況除外,下面我們會講到關(guān)于透明度如何處理). 那么如果同一個像素點有五層, 如果按照油畫算法我們需要繪制5次, 顯然我們在性能上就耗費了5倍與此.
-
另外是順序問題,參考下圖
以上這種情況, 油畫算法無法得知繪制順序, 因此,在實際開發(fā)場景中,幾乎沒有油畫算法實現(xiàn)隱藏面消除的身影.
2.正背面剔除(CULL_FACE)
正/背面剔除原理:
1- 我們不去繪制那些根本看不到的面包晰,以某種方式去丟棄這部分數(shù)據(jù)伐憾。
2- 我們可以給平面定義正面和背面,OpenGL可以做到檢查所有正面朝向觀察者的面树肃,并渲染它們,從而丟棄背?朝向的面胸嘴。 OpenGL渲染的性能即可提?超過50%。
默認情況逆時針頂點連接順序為圖形正面,也就是我們所能看到的面.
當然我們也可以指定具體哪個面為正面,但是一般都會使用默認.
注意:
正?和背面是由三角形的頂點順序和觀察者方向共同決定的,隨著觀察者的角度方向的改變,正面背面也會跟著改變乡话。
3.深度測試(DEPTH_TEST)
每個像素點只有一個深度值耳奕,在同一個像素點出現(xiàn)新的深度值時诬像,會與之前進行比較闸婴,如果新的深度值大掠拳,那么離我們更遠,應該是是被遮擋溺欧。如果新的深度值小,那么離我們更近芥牌,我們應該先看到他聂使,這個時候深度緩沖區(qū)儲存小的深度值,并且顏色緩沖區(qū)也將進行對應的更新弃理。比較深度值的這整個過程屎蜓,就叫深度測試。
- 為什么需要深度緩沖區(qū)?
在不使用深度測試的時候辆苔,如果我們先繪制一個距離比較近的物體扼劈,再繪制距離較遠的物體,則距離遠的位圖因為后繪制荐吵,會把距離近的物體覆蓋掉捍靠,有了深度緩沖區(qū)后, 繪制物體的順序就不那么重 要的榨婆, 實際上良风,只要存在深度緩沖區(qū)闷供,OpenGL 都會把像素的深度值寫?到緩沖區(qū)中. 除?調(diào)?glDepthMask(GL_FALSE).來禁?寫入.
使用深度測試:
深度緩沖區(qū),一般由窗口管理系統(tǒng)GLFW創(chuàng)建.深度值一般由16位统诺、24位、32位值表示. 通常是24位.位數(shù)越高,深度精確度更好婿失。
// 1.開啟深度測試
glEnable(GL_DEPTH_TEST);
// 2.關(guān)閉深度測試
glDisable(GL_DEPTH_TEST);
// 3.指定深度測試判斷模式
glDepthFunc(GL_LESS); //GL_LESS 默認值
// 4.打開啄寡、阻斷深度緩沖區(qū)寫入,默認打開
glDepthMask(GL_TRUE); // 開啟深度緩沖區(qū)寫入
glDepthMask(GL_FALSE); // 開啟深度緩沖區(qū)寫入
拓展:開啟深度測試后懒浮,就一定不會出現(xiàn)問題了嗎识藤?
其實不然,如下圖所示稽穆,三個圖形在深度值相等的情況下赶撰,深度測試無法判斷深度值,會導致無法預測的問題。會造成下面2個畫面交替出現(xiàn)的問題绒疗,這個問題叫 ZFighting 閃爍問題
那么如何解決ZFighting閃爍問題呢?
啟用Polygon Offset(多邊形偏移)吓蘑,在執(zhí)行深度測試之前,細微的增加深度值溃蔫,使得兩個重疊的圖形之間有細微的差異
//開啟多邊形偏移 glEnable(GL_POLYGON_OFFSET_FILL);
//關(guān)閉多邊形偏移 glDisable(GL_POLYGON_OFFSET_FILL);
指定偏移量琳猫,負值,將使得z值距離我們更更近统刮,?而正值,將使得z值距離我們更更遠侥蒙。
提示: 如何避免ZFighting閃爍問題?
- 不要將兩個物體靠的太近鞭衩,避免渲染時三?形疊在?一起。這種?方式要求對場景中物體插?一個少量的偏移论衍,那么就可能避免ZFighting現(xiàn)象。例例如上面的?方體和平?面問題中钉凌,將平?下移0.001f就可以解決這個問題,當然手動去插入這個小的偏移是要付出代價的.
- 盡可能將近裁剪?面設置得離觀察者遠一些捂人。上面我們看到,在近裁剪平?附近酸纲,深度的精確度是很?的瑟匆,因此盡可能讓近裁剪面遠一些的話,會使整個裁剪范圍內(nèi)的精確度變?一些疾嗅。但是這種?方式會使?離觀察者較近的物體被裁減掉冕象,因此需要調(diào)試好裁剪?面參數(shù)。
- 使?更高位數(shù)的深度緩沖區(qū)论悴,通常使?的深度緩沖區(qū)是24位的墓律,現(xiàn)在有?些硬件使?32位的緩沖區(qū),使精確度得到提?.
4.顏色混合(前面提到的半透明時解決方法)
我們把OpenGL 渲染時會把顏?色值存在顏?色緩存區(qū)中察纯,每個?片段的深度值也是放在深度緩沖區(qū)。當深度緩沖區(qū)被關(guān)閉時捐寥,新的顏?將簡單的覆蓋原來顏?緩存區(qū)存在的顏色值握恳,當深度緩沖區(qū)再次打開時,新的顏?片段只是當它們比原來的值更接近鄰近的裁剪平面才會替換原來的顏?片段崇裁。
- 使用顏色混合:
glEnable(GL_BlEND);
glDisable(GL_BlEND)
?標顏?:已經(jīng)存儲在顏色緩存區(qū)的顏色值
源顏色:作為當前渲染命令結(jié)果進?顏色緩存區(qū)的顏?值
當混合功能被啟動時束昵,源顏?和目標顏色的組合方式是混合方程式控制的。在默認情況
下巴比,混合?方程式如下所示:
Cf = (Cs * S) + (Cd * D)
Cf :最終計算參數(shù)的顏?
Cs : 源顏?
Cd :目標顏?
S:源混合因子
D:?標混合因子
-
設置混合因?子礁遵,需要?用到glBlendFun函數(shù)
glBlendFunc(GLenum S,GLenum D);
S:源混合因?
D:目標混合因?
- 表中R、G政勃、B兼砖、A 分別代表 紅、綠懒叛、藍耽梅、alpha。
- 表中下標S、D洪己,分別代表源、目標
- 表中C 代表常量顏色(默認黑色)
調(diào)用方法:
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
顏色混合總結(jié):
最終顏色是以原先的紅色(?標顏?)與后來的藍色(源顏色)進行組合逝钥。源顏色的alpha值越高,添加的藍色顏色成分越高持际,?標顏色所保留的成分就會越少哗咆。 混合函數(shù)經(jīng)常用于實現(xiàn)在其他?些不不透明的物體前面繪制一個透明物體的效果。