OpenGL學習之渲染技巧

一、正背面踢除(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)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容