OpenGL系統設計-霧與混合(2)

 

在高級三維建模中都少不了Alpha,它作爲RGBA顏色模型中的一個分量,表徵了物體的透明度。和RGB取值範圍一樣,Alpha取值從0.01.00.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,kAAD) / /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.00.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所示。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章