前言
大家先看看下面這張圖(1.png):1.png從上面圖片看到了什么?這里议慰,容我賣個關(guān)子蠢古,留個懸念。
一别凹、定義
- 隱藏面消除
在繪制3D場景的時候草讶,我們需要決定哪些部分是對觀察者可見的,或者哪些部分是對觀察者不可見的炉菲。對于不可見的部分堕战,應(yīng)該及早丟棄。例如:在一個不透明的墻壁后,就不不應(yīng)該渲染拍霜。這種情況叫做“隱藏面消除“(Hidden surface elimination)嘱丢。
二、隱藏面消除的解決方案
既然對于不可見的部分不進(jìn)行渲染祠饺,那到底有多少種方法可以做到呢越驻?那他們又有哪些優(yōu)缺點(diǎn)呢?又該如何選擇最優(yōu)解決方案吠裆?
-
方案一:油畫算法
繪制原理:先繪制場景中的離觀察者較遠(yuǎn)的物體伐谈,再繪制較近的物體。
圖例(2.png): 先繪制紅?部分试疙,再繪制??部分,最后再繪制灰色部分抠蚣,即可解決隱藏?消除的問題祝旷。
2.png
利弊:
使?油畫算法,只要將場景按照物理距離觀察者的距離遠(yuǎn)近排序嘶窄,由遠(yuǎn)及近的繪制即可怀跛。那么會出現(xiàn) 什么問題? 如果三個三角形是疊加的情況,油畫算法將?無法處理柄冲。3.png
-
方案二:正背面剔除(Face Culling)
繪制原理:繪制觀察者所看到的面吻谋,不繪制看不到的面。
注解:
既然正背面剔除的繪制原理是這樣现横,那我們怎么知道某個面在觀察者的視野中不會出現(xiàn)漓拾?
我們都知道,任何平面都有2個面戒祠,正面和背面骇两,同一個時刻,你只能看到其中一面姜盈。
那哪個是正面低千,哪個又是背面呢?OpenGL又是如何區(qū)分的呢馏颂?
下面示血,我們試著分析頂點(diǎn)的順序來看下:
4.png
OpenGL正背面默認(rèn)是這樣區(qū)分的:
正面: 按照逆時針頂點(diǎn)連接順序的三?形面
背面:按照順時針頂點(diǎn)連接順序的三?形面
那通過立方體來分析又是怎樣的呢棋傍?
5.png
從上圖看:
左側(cè)三角形頂點(diǎn)順序為:1 -> 2 -> 3; 右側(cè)三角形的頂點(diǎn)順序為:1 -> 2 -> 3难审。
當(dāng)觀察者在右側(cè)時舍沙,則右邊的三角形?向為逆時針方向則為正面,而左側(cè)的三角形為順時針則為背?剔宪。
當(dāng)觀察者在左側(cè)時拂铡,則左邊的三角形為逆時針?向判定為正面,而右側(cè)的三角形為順時針判定為背?葱绒。
總的來說感帅,正面和背面是由三角形的頂點(diǎn)定義順序和觀察者?向共同決定的。隨著觀察者的角度方向的改變地淀,正面背面也會跟著改變失球。
優(yōu)勢:
采用正背面剔除,意味著帮毁,我們只需要繪制看得到的面实苞,這在OpenGL渲染的性能上可提高超過50%。
那代碼上又是如何實現(xiàn)的呢烈疚?
//開啟表面剔除(默認(rèn)背面剔除)
void glEnable(GL_CULL_FACE);
//關(guān)閉表面剔除(默認(rèn)背面剔除)
void glDisable(GL_CULL_FACE);
//用戶選擇剔除哪個面(正面/背面)
void glCullFace(GLenum mode);
mode參數(shù)為: GL_FRONT黔牵,GL_BACK,GL_FRONT_AND_BACK 爷肝;默認(rèn)GL_BACK
//用戶指定繞序哪個為正?
void glFrontFace(GLenum mode);
mode參數(shù)為: GL_CW(順時針)猾浦,GL_CCW(逆時針);默認(rèn)GL_CCW
舉個例子灯抛,如果我們要剔除正面金赦,那該如何實現(xiàn)?有兩種方式:
//第一種:
glCullFace(GL_BACK);
glFrontFace(GL_CW);
//第二種:
glCullFace(GL_FRONT);
-
方案三:Z-buffer方法(深度緩沖區(qū)Depth-buffer)
在說Z-buffer方法之前对嚼,我們先通過幾個問題來了解下深度夹抗。
(1)什么是深度?
深度其實就是該像素點(diǎn)在3D世界中距離攝像機(jī)的距離,Z值纵竖。
(2)什么是深度緩沖區(qū)?
深度緩存區(qū)漠烧,就是一塊內(nèi)存區(qū)域,專門存儲著每個像素點(diǎn)(繪制在屏幕上的)深度值磨确。深度值(Z值)越大沽甥,則離攝像機(jī)就越遠(yuǎn)。
(3)為什么需要深度緩沖區(qū)?
在不使?深度測試的時候乏奥,如果我們先繪制?個距離比較近的物理摆舟,再繪制距離較遠(yuǎn)的物理,則距離遠(yuǎn)的位圖因為后繪制,會把距離近的物體覆蓋掉恨诱。有了深度緩沖區(qū)后媳瞪,繪制物體的順序就不那么?? 要了。 實際上照宝,只要存在深度緩沖區(qū)蛇受,OpenGL 都會把像素的深度值寫入到緩沖區(qū)中。除非調(diào)用glDepthMask(GL_FALSE)
來禁?寫?厕鹃。
那到底什么是深度測試呢兢仰?
深度緩沖區(qū)(DepthBuffer)和顏色緩存區(qū)(ColorBuffer)是對應(yīng)的。顏色緩存區(qū)存儲像素的顏?色信息剂碴,而深度緩沖區(qū)存儲像素的深度信息把将。 在決定是否繪制一個物體表面時,首先要將表面對應(yīng)的像素的深度值與當(dāng)前深度緩沖區(qū)中的值進(jìn)行比較忆矛。如果?于深度緩沖區(qū)中的值察蹲,則丟棄這部分。否則利用這個像素對應(yīng)的深度值和顏色值催训,分別更新深度緩沖區(qū)和顏色緩存區(qū)洽议。 這個過程稱為“深度測試”。
繪制原理:繪制一個物體表面時漫拭,首先要將表面對應(yīng)的像素的深度值與當(dāng)前深度緩沖區(qū)中的值進(jìn)行比較亚兄,如果?于深度緩沖區(qū)中的值,則丟棄這部分嫂侍。否則利用這個像素對應(yīng)的深度值和顏色值儿捧,分別更新深度緩沖區(qū)和顏色緩存區(qū)。
深度緩沖區(qū)挑宠,一般由窗?管理系統(tǒng)GLFW創(chuàng)建。深度值?般由16位颓影,24位各淀,32位值表示。 通常是24位诡挂。位數(shù)越高碎浇,深度精確度更好。
圖例(6.png):
6.png
那深度測試代碼上又是怎樣的璃俗?
//開啟深度測試
glEnable(GL_DEPTH_TEST);
/*
在繪制場景前奴璃,需要清除顏色緩存區(qū),深度緩沖
清除深度緩沖區(qū)默認(rèn)值為1.0城豁,表示最大的深度值苟穆,深度值的范圍為(0,1)之間。值越小表示越靠近觀察者,值越大表示越遠(yuǎn)離觀察者雳旅。
*/
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//指定深度測試判斷模式
void glDepthFunc(GLEnum mode);
mode參數(shù):具體見下圖(7.png)
//打開h或阻斷深度緩存區(qū)寫入
void glDepthMask(GLBool value);
value:GL_TURE 開啟深度緩沖區(qū)寫入跟磨;GL_FALSE 關(guān)閉深度緩沖區(qū)寫入。默認(rèn)開啟
7.png
好啦攒盈,深度測試就講到這里抵拘。
最后的最后,
那隱藏面消除的幾種方案講解到此就也結(jié)束啦型豁!
現(xiàn)在再回過去看最上面的那張圖(1.png)僵蛛,你看到什么了嗎?