引言
融合(blending)、霧化(fog)與反走樣(antialiasing)是OpenGL中的三種特殊效果 處理方法。融合提供了一種透明或半透明顯示的技術;霧化處理則根據物體距離視點的遠近對其進行恰當的模糊處理;反走樣則可減少在繪製離散化的圖形時所產生 的誤差走樣。
實現融合特效
融合可將兩種顏色的R、G、B分量按一定比例混在一起形成一種新的顏 色,RGBA顏色模式中的A即表示Alpha值,對應於顏色的混合比例。由於只有在RGBA模式中才能對A值進行說明,因此融合不能在色彩索引模式下使 用。融合操作可通過源因子(Sr、Sg、Sb、Sa)與目的因子(Dr、Dg、Db、Da)計算鍀出,融合結果為(Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)每個元素值都在範圍[0, 1]內。可以看出,融合處理的關鍵就是對融合因子(Sr,Sg,Sb,Sa)和(Dr,Dg,Db,Da)的設定。在OpenGL中,源因子和目的因子通 過glBlendFunc()函數產生,其函數形式為:
| void glBlendFunc(GLenum sfactor,GLenum dfactor) |
通過指定參數sfactor和dfactor來分別指出計算源因子和目的因子的方式。具體取值可參見下表。在產生了融合因子值後,還需調用glEnable(GL_BLEND)和glDisable(GL_BLEND)來啟用、關閉融合處理。
| 常數 |
相關因子 |
融合因子結果 |
| GL_ZERO |
源因子或目的因子 |
(0,0,0,0) |
| GL_ONE |
源因子或目的因子 |
(1,1,1,1) |
| GL_DST_COLOR |
源因子 |
(Rd,Gd,Bd,Ad) |
| GL_SRC_COLOR |
目的因子 |
(Rs,Gs,Bs,As) |
| GL_ONE_MINUS_DST_COLOR |
源因子 |
(1,1,1,1)-(Rd,Gd,Bd,Ad) |
| GL_ONE_MINUS_SRC_COLOR |
目的因子 |
(1,1,1,1)-(Rs,Gs,Bs,As) |
| GL_SRC_ALPHA |
源因子或目的因子 |
(As,As,As,As) |
| GL_ONE_MINUS_SRC_ALPHA |
源因子或目的因子 |
(1,1,1,1)-(As,As,As,As) |
| GL_DST_ALPHA |
源因子或目的因子 |
(Ad,Ad,Ad,Ad) |
| GL_ONE_MINUS_DST_ALPHA |
源因子或目的因子 |
(1,1,1,1)-(Ad,Ad,Ad,Ad) |
| GL_SRC_ALPHA_SATURATE |
源因子 |
(f,f,f,1); f=min(As,1-Ad) |
下面是應用了融合技術的一個簡單例子,通過圖1的繪製結果可以看出在啟用了融合處理後在兩個具有不同顏色方塊的交疊部分顏色發生了變化,該地區即為融合所產生的結果:
void CALLBACK Display() { glClear(GL_COLOR_BUFFER_BIT); // 清屏 glColor4f(0.0, 1.0, 0.0, 0.5); // 繪製矩形 glRectf(0.1, 0.1, 0.6, 0.6); glColor4f(1.0, 1.0, 0.0, 0.7); // 繪製矩形 glRectf(0.4, 0.3, 0.9, 0.8); glFlush(); // 強制繪圖完成 } void Init() { glEnable (GL_BLEND); // 啟用融合 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 產生融合因子 glShadeModel (GL_FLAT); // 設定平面明暗處理 glClearColor (0.0, 0.0, 0.0, 0.0); // 清屏 } |
圖1 有顏色方塊的融合
霧化特效
霧化是一種類比自然界中霧氣對情境物體視覺效果產生影響的圖形繪製技術。此技術從視點到物體逐漸將物體的繪製 顏色淡化,直至背景色。通過霧化處理可較好的表現出物體到視點的距離感。雖然霧化的具體計算非常複雜,但在OpenGL中的使用卻非常簡單。首先調用 glEnable(GL_FOG)以啟用霧化處理,啟用後離視點較遠的物體開始淡化成霧的顏色。然後可通過glFog*()函數來選擇控制霧的濃度和顏色 的方程,具體形式為:
| void glFog{if}[v](GLenum pname,TYPE param); |
該函數設定了霧化參數和函數,在pname為GL_FOG MODE時,參數param可以為GL_EXP(指數)、GL_EXP2(指數平方)和GL_LINEAR(線性);如果參數pname為 GL_FOG_DENSITY、GL_FOG_START或GL_FOG_END,參數param將分別指定在不同霧化數學模型下的不同計算公式參量;在 參數pname為GL_FOG_COLOR時,param將為一個指向顏色向量的指標。最後,如果有必要,還可以調用函數glHint (GL_FOG_HINT)進一步指定霧化效果。下面給出實現霧化效果的部分具體範例程式碼及其繪製結果(圖2):
void CALLBACK Display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清屏 glPushMatrix(); // 繪製近視點景物 glTranslatef(-3.0, -1.5, -2.0); auxSolidTorus(0.6, 1.5); glPopMatrix(); glPushMatrix(); // 繪製遠視點景物 glTranslatef(2.0, 0.8, -10.0); auxSolidTorus(0.6, 1.5); glPopMatrix(); glFlush(); // 強制繪圖完成 } void Init() { GLfloat mat_ambient[] = {0.7, 0.6, 0.0, 1.0}; // 設定光照模型 GLfloat mat_diffuse[] = {0.7, 0.6, 0.0, 1.0}; GLfloat mat_specular[] = {1.0, 0.0, 1.0, 1.0}; GLfloat mat_shininess[] = {50.0}; GLfloat position[] = {5.0, 5.0, 5.0, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glFrontFace(GL_CW); glEnable(GL_FOG); // 啟用霧化處理 { glFogi(GL_FOG_MODE, GL_LINEAR); // 採用線性變化的霧化效果 GLfloat fogColor[] = {0.3, 0.3, 0.3, 1.0}; // 指定霧化顏色 glFogfv(GL_FOG_COLOR, fogColor); glFogf(GL_FOG_START, 3.0); // 指定按線性變化時計算公式的參量 glFogf(GL_FOG_END, 15.0); glHint(GL_FOG_HINT, GL_DONT_CARE); //規定霧化效果的品質 } } |
實現繪圖反走樣
由於在圖形繪製到螢幕時,數字化的映像通過離散的象素點來表達,因此所繪製的圖元將會在光滑的曲線上產 生鋸齒,這種鋸齒即為走樣。反走樣也叫做反混淆,它將根據圖元的象素地區來確定象素的顏色值,通過這種處理可在一定程度上消除鋸齒的影響。在OpenGL 中,可通過函數glHint()來對映像品質和繪製速度之間的權衡作一些控制,其函數形式為:
| void glHint(GLenum target,GLenum hint); |
參數target說明控制什麼行為,具體的,GL_POINT_SMOOTH_HINT、GL_LINE_SMOOTH_HINT和 GL_POLYGON_SMOOTH_HINT分別指定點、線和多邊形的採樣品質;GL_FOG_HINT指出霧化是按象素進行(GL_NICEST)還 是按頂點進行(GL_FASTEST);GL_PERSPECTIVE_CORRECTION_HINT指定了顏色紋理插值的品質並可糾正由單純線性插值 所帶來的一些視覺錯誤。參數hint可以是:GL_FASTEST(給出最有效選擇)、GL_NICEST(給出最高品質的選擇)、 GL_DONT_CARE(沒有選擇)。
雖然在OpenGL的色彩索引模式下也可以實現反走樣,但仍建議在RGBA模式下進行。對圖 元進行反走樣時也要先調用glEnable()函數啟動反走樣(其參數為GL_POINT、GL_LINE_SMOOTH或 GL_POLYGON_SMOOTH)。如果是在RGBA模式下進行反走樣,還必須與融合配合使用,通常使用GL_SRC_ALPHA和 GL_ONE_MINUS_SRC_ALPHA分別作為源和目的因子。下面給出一段在RGBA模式下啟用反走樣繪製多面體的範例程式碼,從繪製結果(圖3) 可以明顯看出在多邊形的直線邊界出現的鋸齒得到了較好的平滑:
void CALLBACK Display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清屏 auxWireDodecahedron(1.0); // 繪製二十面體 glFlush(); // 強制繪圖完成 } void Init() { glEnable(GL_LINE_SMOOTH); // 啟用反走樣 glEnable(GL_BLEND); // 啟動融合 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 產生融合因子 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);// 權衡映像品質與繪製速度 glLineWidth(2.0); // 線寬 glShadeModel(GL_FLAT); // 平面明暗處理 glClearColor(0.0, 0.0, 0.0, 0.0); // 清屏 glDepthFunc(GL_LESS); // 啟用深度比較 glEnable(GL_DEPTH_TEST); } |
圖3 反走樣多面體