OpenGL學(xué)習(xí)之渲染技巧

一、正背面踢除(Face Culling)

在渲染3D場(chǎng)景過(guò)程中可能會(huì)產(chǎn)生以下問(wèn)題

  • 我們需要決定哪些部分是對(duì)觀察者可?的,或者哪些部分是對(duì)觀察者不可見(jiàn)的?
  • 對(duì)于不可見(jiàn)的我們應(yīng)該怎么處理?

解決方案

1. 油畫(huà)算法

  • 先繪制場(chǎng)景中較遠(yuǎn)的物體,再繪制較近的物體

弊端

  • 使?用油畫(huà)算法,只要將場(chǎng)景按照物理理距離觀察者的距離遠(yuǎn)近排序,由遠(yuǎn)及近的繪制即可.那么會(huì)出現(xiàn) 什什么問(wèn)題? 如果三個(gè)三?角形是疊加的情況,油畫(huà)算法將?無(wú)法處理理.

2. 正背面踢除(Face Culling)

  • 以一個(gè)正方形為例,我們正??吹降闹挥腥齻€(gè)面,那么背后三個(gè)看不見(jiàn)的面就可以不用繪制,

  • 如果我們丟棄這部分?jǐn)?shù)據(jù),OpenGL的渲染速度提升50%;

  • OpenGL 可以做到檢查所有正?面朝向觀察者的?面,并渲染它們.從?而丟棄背?面朝向的?面. 這樣可以 節(jié)約?片元著?色器器的性能.

  • OpenGL通過(guò)分析頂點(diǎn)數(shù)據(jù)的順序來(lái)判斷哪個(gè)是正面,哪個(gè)是背面。

  • 一般我們繪制三角形的時(shí)候,使用逆時(shí)針繪制時(shí)時(shí)正面,順時(shí)針繪制時(shí)時(shí)背面。

3.使用方法

  • 開(kāi)啟表面面剔除(默認(rèn)背?面剔除)

void glEnable(GT_CULL_FACE);

  • 關(guān)閉表面踢除

void glDisable(GL_CULL_FACE);

  • 用戶踢除哪個(gè)面(正面/背面)

void glCullFace(GLenum mode);
mode參數(shù)為:GL_FONT,GL_BACK,GL_FONT_BACK, 默認(rèn)GL_BACK

  • 用戶指定的哪個(gè)繞續(xù)為正面

void glFontFace(GLenum mode);
mode參數(shù):GL_CW、GL_GL_CCW,默認(rèn)GL_CCW;

4.使用例子

  • 踢除正面實(shí)現(xiàn)1
void glCullFace(GL_FONT);
  • 踢除正面實(shí)現(xiàn)1
void glCullFace(GL_BACK);
void glFontFace(CL_CW);

二、深度

1. 了解深度

1.1 什么是深度?

深度就是在3D世界中的世界坐標(biāo)系中距離相機(jī)的距離,就是z值。

1.2 深度緩沖區(qū)

深度緩沖區(qū)就是一塊內(nèi)存區(qū)域,專門(mén)存儲(chǔ)每個(gè)像素點(diǎn)的深度值,深度值(z值)越大,距離相機(jī)越遠(yuǎn)

1.3 為什么需要深度緩沖區(qū)

在不使?深度測(cè)試的時(shí)候,如果我們先繪制一個(gè)距離比較近的物體,再繪制距離較遠(yuǎn)的物體,則距離遠(yuǎn)的位圖因?yàn)楹罄L制,會(huì)把距離近的物體覆蓋掉. 有了深度緩沖區(qū)后,繪制物體的順序就不那么??重要的. 實(shí)際上,只要存在深度緩沖區(qū),OpenGL 都會(huì)把像素的深度值寫(xiě)入到緩沖區(qū)中. 除?調(diào)? glDepthMask(GL_FALSE).來(lái)禁?寫(xiě)?

2.深度測(cè)試

深度緩沖區(qū)和顏色緩沖區(qū)是相對(duì)應(yīng)的。顏色緩沖區(qū)存儲(chǔ)著像素的顏色信息,深度緩沖區(qū)存儲(chǔ)著像素的深度信息。再?zèng)Q定繪制一個(gè)物體表面時(shí),首先要拿當(dāng)前像素的深度值與深度緩沖區(qū)的深度值進(jìn)行比較,如果大于深度緩沖區(qū)的深度值就丟棄,否則使用這個(gè)像素像素的對(duì)應(yīng)的顏色值和深度值繪制,分別更新深度緩沖區(qū)和顏色緩沖區(qū)。這叫深度測(cè)試。

2.1 使用深度測(cè)試

  • 開(kāi)啟深度測(cè)試
glEnable(GL_DEPTH_TEST);

在繪制場(chǎng)景前,清除顏?色緩存區(qū),深度緩沖

glClearColor(1.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

清除深度緩沖區(qū)默認(rèn)值為1.0,表示最大的深度值,深度值的范圍為(0,1)之間. 值越?表示越靠近觀察者,值越大表示 越遠(yuǎn)離觀察者

  • 關(guān)閉深度測(cè)試
glDisable(GL_DEPTH_TEST);
  • 指定深度測(cè)試判斷模式
void glDepthFunc(GLEnum mode);
函數(shù) 說(shuō)明
GL_ALWAYS 總是測(cè)試通過(guò)的
GL_NEVER 總是不通過(guò)測(cè)試
GL_LESS 當(dāng)前深度值 < 存儲(chǔ)的深度值時(shí)通過(guò)(默認(rèn))
GL_EQUAL 當(dāng)前深度值 = 存儲(chǔ)的深度值時(shí)通過(guò)
GL_LLEQUAL 當(dāng)前深度值 <= 存儲(chǔ)的深度值時(shí)通過(guò)
GL_GREARTER 當(dāng)前深度值 > 存儲(chǔ)的深度值時(shí)通過(guò)
GL_NOTEQUAL 當(dāng)前深度值 != 存儲(chǔ)的深度值時(shí)通過(guò)
GL_GEQUAL 當(dāng)前深度值 >= 存儲(chǔ)的深度值時(shí)通過(guò)
  • 打開(kāi)/阻斷 深度緩存區(qū)寫(xiě)?入
// value : GL_TURE 開(kāi)啟深度緩沖區(qū)寫(xiě)入; GL_FALSE 關(guān)閉深度緩沖區(qū)寫(xiě)?
void glDepthMask(GLBool value);

四、ZFighting閃爍問(wèn)題

1. 問(wèn)題原因

因?yàn)殚_(kāi)啟深度測(cè)試后,OpenGL 就不會(huì)再去繪制模型被遮擋的部分. 這樣實(shí)現(xiàn)的顯示更加真實(shí).但是 由于深度緩沖區(qū)精度的限制對(duì)于深度相差?常小的情況下.(例如在同?平?上進(jìn)行2次繪制),OpenGL 就可能出現(xiàn)不能正確判斷兩者的深度值,會(huì)導(dǎo)致深度測(cè)試的結(jié)果不可預(yù)測(cè).顯示出來(lái)的 現(xiàn)象時(shí)交錯(cuò)閃爍.的前面2個(gè)畫(huà)面,交錯(cuò)出現(xiàn)

2.解決辦法

第1步、啟用 Polygon Offset 方式解決

解決方法: 讓深度值之間產(chǎn)生間隔.如果2個(gè)圖形之間有間隔,是不是意味著就不會(huì)產(chǎn)??涉.可以理解為在執(zhí)行深度測(cè)試前將立?體的深度值做?些細(xì)微的增加.于是就能將??疊的2個(gè)圖形深度值之前有所區(qū)分.

//啟?用Polygon Offset ?方式 
glEnable(GL_POLYGON_OFFSET_FILL)

參數(shù)列列表:
GL_POLYGON_OFFSET_POINT 對(duì)應(yīng)光柵化模式: GL_POINT
GL_POLYGON_OFFSET_LINE 對(duì)應(yīng)光柵化模式: GL_LINE
GL_POLYGON_OFFSET_FILL 對(duì)應(yīng)光柵化模式: GL_FILL

第2步、指定偏移量

  • 通過(guò)glPolygonOffset 來(lái)指定.glPolygonOffset 需要2個(gè)參數(shù): factor , units 每個(gè)Fragment 的深度值都會(huì)增加如下所示的偏移量量:

    Offset = ( m * factor ) + ( r * units);

    m : 多邊形的深度的斜率的最大值,理解一個(gè)多邊形越是與近裁剪?平行,m 就越接近于0.
    r : 能產(chǎn)?于窗口坐標(biāo)系的深度值中可分辨的差異最小值.r 是由具體OpenGL 平臺(tái)指定的?個(gè)常量.

  • 一個(gè)?于0的Offset 會(huì)把模型推到離你(攝像機(jī))更遠(yuǎn)的位置,相應(yīng)的?個(gè)小于0的Offset 會(huì)把模型拉近

  • ?般?言,只需要將-1.0 和 -1 這樣簡(jiǎn)單賦值給glPolygonOffset 基本可以滿?足需求.

第3步: 關(guān)閉Polygon Offset

glDisable(GL_POLYGON_OFFSET_FILL)

2.2 ZFighting閃爍問(wèn)題預(yù)防

  • 不要將兩個(gè)物體靠的太近,避免渲染時(shí)三?角形疊在一起。這種方式要求對(duì)場(chǎng)景中物體插入?一個(gè)少量的偏移,那么就可能避免ZFighting現(xiàn)象。例如上面的立?體和平面問(wèn)題中,將平面下移0.001f就可以解決這個(gè)問(wèn)題。當(dāng)然手動(dòng)去插入這個(gè)小的偏移是要付出代價(jià)的。

  • 盡可能將近裁剪面設(shè)置得離觀察者遠(yuǎn)一些。上?我們看到,在近裁剪平?附近,深度的精確度是很高的,因此盡可能讓近裁剪面遠(yuǎn)一些的話,會(huì)使整個(gè)裁剪范圍內(nèi)的精確度變?高一些。但是這種?式會(huì)使離觀察者較近的物體被裁減掉,因此需要調(diào)試好裁剪面參數(shù)。

  • 使用更高位數(shù)的深度緩沖區(qū),通常使用的深度緩沖區(qū)是24位的,現(xiàn)在有?些硬件使?32位的緩沖區(qū),使精確度得到提高

五 剪裁

在OpenGL 中提?渲染的一種?式.只刷新屏幕上發(fā)?變化的部分.OpenGL允許將要進(jìn)?渲染的窗?只去指定一個(gè)裁剪框.

基本原理:?于渲染時(shí)限制繪制區(qū)域,通過(guò)此技術(shù)可以再屏幕(幀緩沖)指定一個(gè)矩形區(qū)域。

啟?剪裁測(cè)試之后,不在此矩形區(qū)域內(nèi)的片元被丟棄,只有在此矩形區(qū)域內(nèi)的片元才有可能進(jìn)?幀緩沖。因此實(shí)際達(dá)到的效果就是在屏幕上開(kāi)辟了一個(gè)小窗?,可以再其中進(jìn)行指定內(nèi)容的繪制。

//1 開(kāi)啟裁剪測(cè)試 glEnable(GL_SCISSOR_TEST);
//2.關(guān)閉裁剪測(cè)試 glDisable(GL_SCISSOR_TEST);
//3.指定裁剪窗?口
void glScissor(Glint x,Glint y,GLSize width,GLSize height);

x,y:指定裁剪框左下?角位置; width , height:指定裁剪尺?寸

六 混合

我們把OpenGL 渲染時(shí)會(huì)把顏色值存在顏色緩存區(qū)中,每個(gè)片段的深度值也是放在深度緩沖區(qū)。當(dāng)深度緩沖區(qū)被關(guān)閉時(shí),新的顏色將簡(jiǎn)單的覆蓋原來(lái)顏色緩存區(qū)存在的顏色值,當(dāng)深度緩沖區(qū)再次打開(kāi)時(shí),新的顏色片段只是當(dāng)它們比原來(lái)的值更接近鄰近的裁剪平面才會(huì)替換原來(lái)的顏??段。

glEnabled(GL_BLEND);

1.組合顏色公式

?標(biāo)顏?:已經(jīng)存儲(chǔ)在顏色緩存區(qū)的顏色值
源顏?:作為當(dāng)前渲染命令結(jié)果進(jìn)入顏色緩存區(qū)的顏?值
當(dāng)混合功能被啟動(dòng)時(shí),源顏色和?標(biāo)顏色的組合方式是混合?程式控制的。在默認(rèn)情況下,混合?程式如下所示:
Cf = (Cs * S) + (Cd * D)
Cf :最終計(jì)算參數(shù)的顏?
Cs :源顏?
Cd :?標(biāo)顏?
S :源混合因?
D :?標(biāo)混合因?

1.1混合因子

設(shè)置混合因子,需要?到glBlendFun函數(shù)

glBlendFunc(GLenum S,GLenum D); 

S:源混合因?
D:?標(biāo)混合因?

表中R、G、B、A 分別代表 紅、綠、藍(lán)、alpha。
表中下標(biāo)S、D,分別代表源、目標(biāo)
表中C 代表常量顏?(默認(rèn)?色)

1.2

下?通過(guò)?個(gè)常見(jiàn)的混合函數(shù)組合來(lái)說(shuō)明問(wèn)題;

glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); 

如果顏?緩存區(qū)已經(jīng)有一種顏色紅色(1.0f,0.0f,0.0f,0.0f),這個(gè)?標(biāo)顏色Cd,如果在這上面??種alpha為0.6的藍(lán)色(0.0f,0.0f,1.0f,0.6f)
Cd (?標(biāo)顏色) = (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)
等價(jià)于 = (Blue * 0.6f) + (Red * 0.4f)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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