write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
隱藏表面消除(深度測(cè)試)
其實(shí)這是個(gè)滯后的話(huà)題了,事實(shí)上應(yīng)該在光照一節(jié)就應(yīng)該詳述的,但是因?yàn)楣庹盏膬?nèi)容本來(lái)就多,所以當(dāng)時(shí)并沒(méi)有再牽涉此內(nèi)容。
在我們填充三維物體時(shí),與平面繪制不同,因?yàn)闋可娴搅饲懊嫖矬w遮擋后面物體的問(wèn)題,假如沒(méi)有一個(gè)很好的內(nèi)置機(jī)制,我們就只能通過(guò)程序記住每個(gè)物體的Z軸(其實(shí)也不一定是Z軸,看當(dāng)時(shí)的觀(guān)察方向),然后按順序?qū)⑦h(yuǎn)的物體先繪制,然后再繪制離我們近的,通過(guò)這種方式,可以讓離我們近的物體繪制在后面,覆蓋掉遠(yuǎn)的物體。
當(dāng)然,假如覺(jué)得不麻煩的話(huà),這樣做倒也不是不行,但是假如這些事情是由硬件實(shí)現(xiàn)的話(huà),效率可是會(huì)上一個(gè)層次的,所以O(shè)penGL也提供了此方法,被稱(chēng)作深度測(cè)試。(Depth Test)使用方法那是相當(dāng)簡(jiǎn)單,僅僅需要通過(guò)glEnable啟用就可以了,我們現(xiàn)在看看使用前后的區(qū)別。
我們通過(guò)以下函數(shù)繪制一大一小兩個(gè)球
void DrawBigRedSphere () { GLfloat mat_specular [] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat mat_shininess [] = { 50.0 }; GLfloat mat_ambient [] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat mat_diffuse [] = { 1.0, 0.0, 0.0, 1.0 }; glMaterialfv ( GL_FRONT , GL_SPECULAR , mat_specular ); glMaterialfv ( GL_FRONT , GL_SHININESS , mat_shininess ); glMaterialfv ( GL_FRONT , GL_AMBIENT , mat_ambient ); glMaterialfv ( GL_FRONT , GL_DIFFUSE , mat_diffuse ); glutSolidSphere (0.5, 32, 32); } void DrawSmallBlueSphere () { GLfloat mat_specular [] = { 0.0, 0.0, 1.0, 1.0 }; GLfloat mat_shininess [] = { 50.0 }; GLfloat mat_ambient [] = { 0.0, 0.0, 1.0, 1.0 }; GLfloat mat_diffuse [] = { 0.0, 0.0, 1.0, 1.0 }; glMaterialfv ( GL_FRONT , GL_SPECULAR , mat_specular ); glMaterialfv ( GL_FRONT , GL_SHININESS , mat_shininess ); glMaterialfv ( GL_FRONT , GL_AMBIENT , mat_ambient ); glMaterialfv ( GL_FRONT , GL_DIFFUSE , mat_diffuse ); glutSolidSphere (0.3, 32, 32); }
DrawBigRedSphere繪制的是大的紅球,DrawSmallBlueSphere繪制的是小的藍(lán)球,繪制的時(shí)候都采用默認(rèn)坐標(biāo),即繪制在屏幕的中央,并且Z軸也不動(dòng),那么,從理論上來(lái)講,大球會(huì)包含小球,小球就被大球遮掩了,我們顯示要的應(yīng)該也是這種效果。
看一下未開(kāi)啟深度測(cè)試情況下的情況我們先繪制大球,再繪制小球的和用相反順序再繪制的情形:
代碼如下:
void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix (); glTranslatef (-0.5, 0.0, 0.0); DrawBigRedSphere (); DrawSmallBlueSphere (); glPopMatrix (); glPushMatrix (); glTranslatef (0.5, 0.0, 0.0); DrawSmallBlueSphere (); DrawBigRedSphere (); glPopMatrix (); glFlush (); }
我們會(huì)觀(guān)察到很明顯的繪制順序?qū)е碌膯?wèn)題,左邊的圖因?yàn)橄壤L制大球再繪制小球,小的籃球竟然覆蓋掉了應(yīng)該在其外部的紅球。實(shí)際使用中,我們可以都自己判斷,然后用右邊的正確繪制方式,隨著圖形的增多,會(huì)增加一定的計(jì)算量,OpenGL提供的深度測(cè)試就是為我們提供了更簡(jiǎn)便高效的方式,事實(shí)上,由于OpenGL使用的方式因?yàn)榭梢栽跍y(cè)試后,直接繪制出最終圖形而忽略繪制被覆蓋掉的圖形,效率上比覆蓋繪制會(huì)更高一些(需要硬件支持)。
上述代碼,僅僅需要添加一行,
glEnable(GL_DEPTH_TEST);
以啟用深度測(cè)試,效果大不一樣:
天下至簡(jiǎn)之事莫過(guò)于此:)
為節(jié)省篇幅僅貼出關(guān)鍵片段,完整源代碼見(jiàn)我博客源代碼的2009-11-12/glDepthTest/ 目錄,獲取方式見(jiàn)文章最后關(guān)于獲取博客完整源代碼的說(shuō)明。
霧
扇子驅(qū)不散大霧 -- 阿拉伯諺語(yǔ)
像云像霧 又像風(fēng) -- 某電視劇名
霧作為一種常見(jiàn)的天氣現(xiàn)象,OpenGL中有所模擬體現(xiàn)也算是正常,但是在OpenGL中霧的作用卻又不止這些,事實(shí)上,霧效果還用于實(shí)現(xiàn)模糊效果,用于關(guān)于模擬模糊,薄霧,煙,污染。
使用步驟非常簡(jiǎn)單,一如OpenGL慣例,首先通過(guò)glEnable開(kāi)啟,然后又有一個(gè)glFog*這個(gè)用于設(shè)置霧效果的函數(shù)可以使用,呵呵,OpenGL學(xué)多了,會(huì)發(fā)現(xiàn)除了概念不一樣,基本上的使用步驟都差不多,開(kāi)始覺(jué)得OpenGL的這種一個(gè)函數(shù)通過(guò)pname參數(shù)去決定函數(shù)作用的方式不太符合好的API的設(shè)計(jì)哲學(xué),(可以參考《 設(shè)計(jì)Qt風(fēng)格的C++API【轉(zhuǎn)】 》)但是想來(lái),API的設(shè)計(jì)還不一定有絕對(duì)意義上的好壞,這樣的設(shè)計(jì)倒是在一定程度上減少了API的數(shù)量,并且查找時(shí)會(huì)稍微方便一點(diǎn),雖然同時(shí)增加了查文檔看參數(shù)作用的負(fù)擔(dān),這些又是題外話(huà)了。
首先看沒(méi)有霧效果時(shí),我用OpenGL繪制的3個(gè)紅球,紅球的Z軸是依次向內(nèi)。
主要代碼如下:
void DrawRedSphere () { GLfloat mat_specular [] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat mat_shininess [] = { 50.0 }; GLfloat mat_ambient [] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat mat_diffuse [] = { 1.0, 0.0, 0.0, 1.0 }; glMaterialfv ( GL_FRONT , GL_SPECULAR , mat_specular ); glMaterialfv ( GL_FRONT , GL_SHININESS , mat_shininess ); glMaterialfv ( GL_FRONT , GL_AMBIENT , mat_ambient ); glMaterialfv ( GL_FRONT , GL_DIFFUSE , mat_diffuse ); glutSolidSphere (0.25, 32, 32); } //這里進(jìn)行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix (); glTranslatef (-0.75, 0.0, 0.0); DrawRedSphere (); glPopMatrix (); glPushMatrix (); glTranslatef (0.0, 0.0, -1.0); DrawRedSphere (); glPopMatrix (); glPushMatrix (); glTranslatef (0.75, 0.0, -2.0); DrawRedSphere (); glPopMatrix (); glFlush (); }
從圖形上效果上看不出Z軸的變化,因?yàn)槭褂玫氖钦队胺绞健,F(xiàn)在我們啟用霧效果來(lái)試一下。
添加進(jìn)如下語(yǔ)句:
glEnable ( GL_FOG ); GLfloat fogColor [4] = {1.0, 1.0, 1.0, 1.0}; glFogi ( GL_FOG_MODE , GL_EXP ); glFogfv ( GL_FOG_COLOR , fogColor ); glFogf ( GL_FOG_DENSITY , 0.5);
效果如下:
因?yàn)殪F的顏色為白色,第3個(gè)紅球基本上已經(jīng)全白了。。。。大家可以調(diào)整上述代碼中的參數(shù)以獲取不同的效果。
比如說(shuō),偏藍(lán)色的霧:
glEnable ( GL_FOG ); GLfloat fogColor [4] = {0.0, 0.0, 0.5, 1.0}; glFogi ( GL_FOG_MODE , GL_EXP ); glFogfv ( GL_FOG_COLOR , fogColor ); glFogf ( GL_FOG_DENSITY , 0.5);
為節(jié)省篇幅僅貼出關(guān)鍵片段,完整源代碼見(jiàn)我博客源代碼的2009-11-12/glFogSample/ 目錄,獲取方式見(jiàn)文章最后關(guān)于獲取博客完整源代碼的說(shuō)明。
主要函數(shù)其實(shí)也就一個(gè)glFog*,但是參數(shù)那是相當(dāng)?shù)亩喟。舸蠹易约簢L試了。
glFog — specify fog parameters
C Specification
void glFogf( GLenum pname,
GLfloat param);
void glFogi( GLenum pname,
GLint param);
Parameterspname
Specifies a single-valued fog parameter.
GL_FOG_MODE,
GL_FOG_DENSITY,
GL_FOG_START,
GL_FOG_END,
GL_FOG_INDEX, and
GL_FOG_COORD_SRC
are accepted.
paramSpecifies the value that pname will be set to.
C Specification
void glFogfv( GLenum pname,
const GLfloat * params);
void glFogiv( GLenum pname,
const GLint * params);
Parameterspname
Specifies a fog parameter.
GL_FOG_MODE,
GL_FOG_DENSITY,
GL_FOG_START,
GL_FOG_END,
GL_FOG_INDEX,
GL_FOG_COLOR, and
GL_FOG_COORD_SRC
are accepted.
paramsSpecifies the value or values to be assigned to pname.
GL_FOG_COLOR requires an array of four values.
All other parameters accept an array containing only a single value.Description
Fog is initially disabled.
While enabled, fog affects rasterized geometry,
bitmaps, and pixel blocks, but not buffer clear operations. To enable
and disable fog, call glEnable and glDisable with argument
GL_FOG.glFog assigns the value or values in params to the fog parameter
specified by pname.
The following values are accepted for pname:GL_FOG_MODE
params is a single integer or floating-point value that specifies
the equation to be used to compute the fog blend factor,
f.
Three symbolic constants are accepted:
GL_LINEAR,
GL_EXP,
and GL_EXP2.
The equations corresponding to these symbolic constants are defined below.
The initial fog mode is GL_EXP.
GL_FOG_DENSITYparams is a single integer or floating-point value that specifies
density,
the fog density used in both exponential fog equations.
Only nonnegative densities are accepted.
The initial fog density is 1.
GL_FOG_STARTparams is a single integer or floating-point value that specifies
start,
the near distance used in the linear fog equation.
The initial near distance is 0.
GL_FOG_ENDparams is a single integer or floating-point value that specifies
end,
the far distance used in the linear fog equation.
The initial far distance is 1.
GL_FOG_INDEXparams is a single integer or floating-point value that specifies
i
f
,
the fog color index.
The initial fog index is 0.
GL_FOG_COLORparams contains four integer or floating-point values that specify
C
f
,
the fog color.
Integer values are mapped linearly such that the most positive representable
value maps to 1.0,
and the most negative representable value maps to
-1.0
.
Floating-point values are mapped directly.
After conversion,
all color components are clamped to the range
0
1
.
The initial fog color is (0, 0, 0, 0).
GL_FOG_COORD_SRCparams contains either of the following symbolic constants:
GL_FOG_COORD or GL_FRAGMENT_DEPTH. GL_FOG_COORD
specifies that the current fog coordinate should be used as distance value
in the fog color computation. GL_FRAGMENT_DEPTH specifies that the
current fragment depth should be used as distance value in the fog
computation.
本系列其他文章見(jiàn)OpenGL專(zhuān)題 《 Win32 OpenGL系列專(zhuān)題 》
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊(cè)
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機(jī)械工業(yè)出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關(guān)的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個(gè)面向?qū)ο蟮目蚣埽鳛檠菔境绦騺?lái)說(shuō),這樣的框架非常合適。也有 中文版 ,各取所需吧。
4. 《OpenGL入門(mén)學(xué)習(xí)》 ,eastcowboy著,這是我在網(wǎng)上找到的一個(gè)比較好的教程,較為完善,而且非常通俗。這是第一篇的地址: http://bbs.pfan.cn/post-184355.html
完整源代碼獲取說(shuō)明
由于篇幅限制,本文一般僅貼出代碼的主要關(guān)心的部分,代碼帶工程(或者makefile)完整版(如果有的話(huà))都能用Mercurial在Google Code中下載。文章以博文發(fā)表的日期分目錄存放,請(qǐng)直接使用Mercurial克隆下庫(kù):
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見(jiàn)《 分布式的,新一代版本控制系統(tǒng)Mercurial的介紹及簡(jiǎn)要入門(mén) 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創(chuàng)文章作者保留版權(quán) 轉(zhuǎn)載請(qǐng)注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
