write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
隱藏表面消除(深度測試)
其實這是個滯后的話題了,事實上應該在光照一節就應該詳述的,但是因為光照的內容本來就多,所以當時并沒有再牽涉此內容。
在我們填充三維物體時,與平面繪制不同,因為牽涉到了前面物體遮擋后面物體的問題,假如沒有一個很好的內置機制,我們就只能通過程序記住每個物體的Z軸(其實也不一定是Z軸,看當時的觀察方向),然后按順序將遠的物體先繪制,然后再繪制離我們近的,通過這種方式,可以讓離我們近的物體繪制在后面,覆蓋掉遠的物體。
當然,假如覺得不麻煩的話,這樣做倒也不是不行,但是假如這些事情是由硬件實現的話,效率可是會上一個層次的,所以OpenGL也提供了此方法,被稱作深度測試。(Depth Test)使用方法那是相當簡單,僅僅需要通過glEnable啟用就可以了,我們現在看看使用前后的區別。
我們通過以下函數繪制一大一小兩個球
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繪制的是小的藍球,繪制的時候都采用默認坐標,即繪制在屏幕的中央,并且Z軸也不動,那么,從理論上來講,大球會包含小球,小球就被大球遮掩了,我們顯示要的應該也是這種效果。
看一下未開啟深度測試情況下的情況我們先繪制大球,再繪制小球的和用相反順序再繪制的情形:
代碼如下:
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 (); }
我們會觀察到很明顯的繪制順序導致的問題,左邊的圖因為先繪制大球再繪制小球,小的籃球竟然覆蓋掉了應該在其外部的紅球。實際使用中,我們可以都自己判斷,然后用右邊的正確繪制方式,隨著圖形的增多,會增加一定的計算量,OpenGL提供的深度測試就是為我們提供了更簡便高效的方式,事實上,由于OpenGL使用的方式因為可以在測試后,直接繪制出最終圖形而忽略繪制被覆蓋掉的圖形,效率上比覆蓋繪制會更高一些(需要硬件支持)。
上述代碼,僅僅需要添加一行,
glEnable(GL_DEPTH_TEST);
以啟用深度測試,效果大不一樣:
天下至簡之事莫過于此:)
為節省篇幅僅貼出關鍵片段,完整源代碼見我博客源代碼的2009-11-12/glDepthTest/ 目錄,獲取方式見文章最后關于獲取博客完整源代碼的說明。
霧
扇子驅不散大霧 -- 阿拉伯諺語
像云像霧 又像風 -- 某電視劇名
霧作為一種常見的天氣現象,OpenGL中有所模擬體現也算是正常,但是在OpenGL中霧的作用卻又不止這些,事實上,霧效果還用于實現模糊效果,用于關于模擬模糊,薄霧,煙,污染。
使用步驟非常簡單,一如OpenGL慣例,首先通過glEnable開啟,然后又有一個glFog*這個用于設置霧效果的函數可以使用,呵呵,OpenGL學多了,會發現除了概念不一樣,基本上的使用步驟都差不多,開始覺得OpenGL的這種一個函數通過pname參數去決定函數作用的方式不太符合好的API的設計哲學,(可以參考《 設計Qt風格的C++API【轉】 》)但是想來,API的設計還不一定有絕對意義上的好壞,這樣的設計倒是在一定程度上減少了API的數量,并且查找時會稍微方便一點,雖然同時增加了查文檔看參數作用的負擔,這些又是題外話了。
首先看沒有霧效果時,我用OpenGL繪制的3個紅球,紅球的Z軸是依次向內。
主要代碼如下:
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); } //這里進行所有的繪圖工作 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軸的變化,因為使用的是正投影方式。現在我們啟用霧效果來試一下。
添加進如下語句:
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);
效果如下:
因為霧的顏色為白色,第3個紅球基本上已經全白了。。。。大家可以調整上述代碼中的參數以獲取不同的效果。
比如說,偏藍色的霧:
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);
為節省篇幅僅貼出關鍵片段,完整源代碼見我博客源代碼的2009-11-12/glFogSample/ 目錄,獲取方式見文章最后關于獲取博客完整源代碼的說明。
主要函數其實也就一個glFog*,但是參數那是相當的多啊,留待大家自己嘗試了。
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.
本系列其他文章見OpenGL專題 《 Win32 OpenGL系列專題 》
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機械工業出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個面向對象的框架,作為演示程序來說,這樣的框架非常合適。也有 中文版 ,各取所需吧。
4. 《OpenGL入門學習》 ,eastcowboy著,這是我在網上找到的一個比較好的教程,較為完善,而且非常通俗。這是第一篇的地址: http://bbs.pfan.cn/post-184355.html
完整源代碼獲取說明
由于篇幅限制,本文一般僅貼出代碼的主要關心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發表的日期分目錄存放,請直接使用Mercurial克隆下庫:
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見《 分布式的,新一代版本控制系統Mercurial的介紹及簡要入門 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創文章作者保留版權 轉載請注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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