在高級三維建模中都少不了Alpha,它作爲RGBA顏色模型中的一個分量,表徵了物體的透明度。和RGB取值範圍一樣,Alpha取值從0.0到1.0。 0.0表示完全透明,1.0表示完全不透明。
鑑於Alpha的性質,它可以用於模擬玻璃、水。也可以混合合成圖像,對幾何圖元進行反走樣處理。
混合是OpenGL提供的基於像素級的顏色操作,它只支持RGBA顏色模式。在顏色索引表模式下,混合是無效的。
混合是將像素和片元融合起來產生一個新的像素顏色。如果片元是處在混合狀態的,那麼OpenGL先從幀緩衝中讀出像素的顏色,然後和片元的顏色混合,再寫回幀緩衝中。
啓動和禁用混合效果需要使用glEnable(GL_BLEND)和glDisable(GL_BLEND)。OpenGL缺省狀態爲禁用混合。
針對混合,片元和像素均有一個因子來控制各自對最終像素顏色的貢獻。可以使用glBlendFunc來設置這些因子。glBlendFunc指定了像素混合計算方法,其原型如下:
void glBlendFunc(
GLenum sfactor,
GLenum dfactor
);
sfactor參數表示紅、綠、藍、Alpha混合源值的計算方式,共有9種方式
GL_ZERO
GL_ONE
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_SRC_ALPHA_SATURATE
dfactor參數表示紅、綠、藍、Alpha混合目標值的計算方式,共有8種方式
GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
glBlendFunc()定義了混合操作的方式,sfactor 參數指定了用於縮放源顏色值的方法,dfactor 參數指定了用於縮放目標顏色值的方法,共有11種可能,每一種方式都定義了4個縮放因子,分別對應紅色、綠色、藍色和Alpha分量。
假設顏色的源值和目標值分別是(RS,GS,BS,AS)和(Rd,Gd,Bd,Ad),其顏色數目是一個整數,爲(kR,kG,kR,kA),其中
kR = 2mR – 1
kG = 2mG – 1
kB = 2mB – 1
kA = 2mA – 1
其中(mR ,mG ,mB ,mA) 是紅、綠、藍、Alpha的顏色位數,如256色的8位、16M色的16位,真彩色的24位和32位等。
如果用(sR ,sG ,sB ,sA) 和(dR ,dG ,dB ,dA)分別表示源因子和目標因子,則下表9-2列出了源因子或目標因子的取值,所有的因子取值範圍均是[0,1]。
表9-2 混合方式
源因子/目標因子 |
(f (R) ,f (G) ,f (B) ,f (A) ) |
GL_ZERO |
(0,0,0,0) |
GL_ONE |
(1,1,1,1) |
GL_SRC_COLOR |
(RS/kR,GS/kG,BS/kB,AS/kA) |
GL_ONE_MINUS_SRC_COLOR |
(1,1,1,1) - (RS/kR,GS/kG,BS/kB,AS/kA) |
GL_DST_COLOR |
(Rd/kR,Gd/kG,Bd/kB,Ad/kA) |
GL_ONE_MINUS_DST_COLOR |
(1,1,1,1) |
GL_SRC_ALPHA |
(Rd/kR,Gd/kG,Bd/kB,Ad/kA) - (AS/kA,AS/kA,AS/kA,AS/kA) |
GL_ONE_MINUS_SRC_ALPHA |
(1,1,1,1) - (AS/kA,AS/kA,AS/kA,AS/kA) |
GL_DST_ALPHA |
(AD/kA,AD/kA,AD/kA,AD/kA) |
GL_ONE_MINUS_DST_ALPHA |
(1,1,1,1) - (AD/kA,AD/kA,AD/kA,AD/kA) |
GL_SRC_ALPHA_SATURATE |
(i,i,i,1) |
在表9-2中
i = min (AS,kA– AD) / /kA
在RGB模式下,OpenGL使用下面的公式計算像素的混合RGBA值。
R (d) = min(kR,RssR+RddR)
G (d) = min(kG,GssG+GddG)
B (d) = min(kB,BssB+BddB)
A (d) = min(kA,AssA+AddA)
事實上,混合算法並不是很精確,因爲混合操作使用的是整數顏色值。爲了簡便起見,通常使用(RssR+RddR, GssG+GddG, BssB+BddB, AssA+AddA)來作爲混合後的顏色值。例如,針對由遠及近繪製的的物體,實現透明效果可以使用glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA),需要注意的是,透明度的計算不需要用到幀緩衝中的Alpha分量。
如果需要實現點線任意方向的反走樣,可以使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 。使用glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE)還可以對多邊形進行反走樣處理。在進行多邊形反走樣處理前還必須使用glEnable(GL_POLYGON_SMOOTH)啓用多邊形的光滑繪製。
爲了達到正確混合,目標Alpha位必須有效,否則混合無法實現。源Alpha還可以看作是材質的不透明性,範圍從1.0到0.0,表示完全不透明到完全透明。
下面我們來對紋理貼圖的立方體進行混合處理。
//global variant
GLfloat z = -10.0f; //立方體在z軸的距離
BOOL bBlend = TRUE; //是否使用混合的標誌
int glInit()
{
// 啓用紋理映射
glEnable(GL_TEXTURE_2D);
//啓用陰影平滑(Smooth Shading)。
glShadeModel(GL_SMOOTH);
//背景色,alpha爲半透明
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
//設置深度緩衝
glClearDepth(1.0f);
//啓動深度測試
glEnable(GL_DEPTH_TEST);
//深度測試的類型
glDepthFunc(GL_LEQUAL);
//進行透視修正
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//以baby.bmp文件創建一個紋理
g_Texture[0] = CreateTexture("baby.bmp");
if(!g_Texture[0]) //創建失敗則返回
{
MessageBox(g_hWnd, "創建紋理失敗!", "提示", MB_OK);
return FALSE;
}
//啓動霧化效果
glEnable(GL_FOG);
float fogColor[4] = {0.5f, 0.5f, 0.5f, 1.0f};
glFogi(GL_FOG_MODE, GL_EXP2);
glFogfv(GL_FOG_COLOR, fogColor);
glFogf(GL_FOG_DENSITY, 0.1f);
// 霧的計算精度
glHint(GL_FOG_HINT, GL_DONT_CARE);
glFogf(GL_FOG_START, 0);
glFogf(GL_FOG_END, 30.0f);
//啓動混合
glEnable(GL_BLEND);
//設置混合顏色
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return TRUE;
}
void glMain()
{
static int angle =0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //加載單位矩陣
glTranslatef(0.0f, 0.0f, z);
glRotated(angle, 1, 1, 1);
glFogi(GL_FOG_MODE, fogMode[fog]);
if(!bFog)
glDisable(GL_FOG);
else
glEnable(GL_FOG);
//檢查混合標誌
if(!bBlend)
{
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
}
else
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
}
glBindTexture(GL_TEXTURE_2D, g_Texture[0]); // 選擇紋理
DrawCube();
angle++;
SwapBuffers(g_hDC);
}
對是否啓用混合的控制還是在WindProc()中。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_ACTIVATE:
{
if (!HIWORD(wParam))
{
g_bActive=TRUE;
}
else
{
g_bActive=FALSE;
}
return 0;
} // 監視窗口激活消息
case WM_SIZE:
{
glSceneResize(LOWORD(lParam),HIWORD(lParam));
return 0;
}
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
case VK_SPACE:
if(fog==2)
fog=0;
else
fog++;
break;
case VK_F1:
bFog= !bFog;
break;
case VK_F2: //F2鍵切換是否使用混合
bBlend=!bBlend;
break;
case VK_UP: //向上方向鍵拉近立方體和觀察者的距離
z+=0.2;
break;
case VK_DOWN: //向下方向鍵拉遠立方體和觀察者的距離
z-=0.2;
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
程序運行後,可以使用F2鍵來切換是否使用混合,按向上的方向鍵和向下的方向鍵則改變立方體和觀察者的距離,霧的效果仍存在有效,如果9-2所示。