圖形擦除技術及編程應用

發表于:2007-07-14來源:作者:點擊數: 標簽:
圖形擦除是圖形特技處理中最為常見的一種,在各種 游戲 中圖形擦除技術有著廣泛的應用。圖形擦除在本質上是圖形的消隱,即在兩幅圖片之間進行圖片的平滑過渡顯示。過渡的方式決定了圖形擦除的不同視覺效果,其中最為常見的一種就是圖片淡入淡出的更新:兩幅
圖形擦除是圖形特技處理中最為常見的一種,在各種游戲中圖形擦除技術有著廣泛的應用。圖形擦除在本質上是圖形的消隱,即在兩幅圖片之間進行圖片的平滑過渡顯示。過渡的方式決定了圖形擦除的不同視覺效果,其中最為常見的一種就是圖片淡入淡出的更新:兩幅圖片由明到暗、由暗到明的循環交替顯示。這種特技效果在編程中的實現,往往是通過DirectX技術實現的:DirectX Transform為我們提供了一個“Microsoft DirectAnimation Control”的類(在注冊表中可以找到該類的注冊信息HKEY_CLASS_ROOT\CLSID\{B6FFC24C-7E13-11D0- 9B47-00C04FC2F51D})供調用,以此實現高質量的圖片擦除。不過,對于DirectX編程,大部分的編程愛好者對其程序框架難以適應,可以說,花在理解DirectX編程上的工夫要遠遠大于對圖形擦除技術本身的理解。有沒有一種更簡單的方法,使用常規的編程方式來實現圖形擦除呢?

解決方案
不同于Windows 95中的GUI(圖形用戶接口),在Windows 98以后的版本中,GUI增加了對Alpha Blending(通道混合)的支持,Alpha Blending在概念上最為明顯的就是對“通道”的應用。熟悉圖形處理的朋友對“通道”這個概念并不會感到陌生, Alpha通道是用來表示數字圖像的透明度,改變各種通道的特性,就相當于改變各種基本顏色的濃度。通常情況下,Alpha通道使用8位(Byte)二進制數,可以表示256級灰度,即256級的透明度。假設我們想要在目標區(Dst)里顯示一個像素(Src:Alpha通道值為Src.Alpha),并且要求系統進行“通道合成”運算,那么,進行合成運算的具體公式為:

  Dst.Red   = Src.Red+ (1 - Src.Alpha) ? Dst.Red
  Dst.Green = Src.Green+ (1 - Src.Alpha) ? Dst.Green

  Dst.Blue = Src.Blue + (1 - Src.Alpha) ? Dst.Blue


從上面的公式可以看出,在進行合成運算之后,更新顯示后的目標區域顏色值(RGB)并不完全是源位圖的RGB值的拷貝,而是源位圖和目標區域進行了“合成”之后的RGB值。和BitBlt函數的像素運算不同,Alpha Blending強調的是源位圖的透明度,正是利用這樣一種合成運算,我們能夠達到圖像“透明”的效果。

在VC中,系統提供了AlphaBlend函數來實現位圖的通道合成運算,AlphaBlend 函數主要用來顯示透明或半透明的位圖,其調用格式如下:

BOOL AlphaBlend(
HDC hdcDest,
// 目標設備環境句柄
int nXOriginDest,
// 目標坐標x
int nYOriginDest,
// 目標坐標y
int nWidthDest,
// 目標寬度
int nHeightDest,
//目標高度
HDC hdcSrc,
//源設備環境句柄
int nXOriginSrc,
// 源坐標x
int nYOriginSrc,
// 源坐標y
int nWidthSrc,
//源寬度
int nHeightSrc,
//源高度
BLENDFUNCTION blendFunction
// 合成方式具體數據結構
);


BLENDFUNCTION定義了在源位圖和目標位圖之間進行合成的具體方式,其具體數據成員及含義如下:

typedef struct _BLENDFUNCTION {
BYTE BlendOp;
BYTE BlendFlags;//必須為零
BYTE SourceConstantAlpha;//位圖使用的透明度,0為完全透明、255為正常方式顯示
BYTE AlphaFormat;//通常為零,如果源位圖為32位真彩色,此值可取為AC_SRC_ALPHA
}BLENDFUNCTION, ?PBLENDFUNCTION, ?LPBLENDFUNCTION;


由上面的函數說明我們知道,AlphaBlend能夠以特定的透明度來顯示一幅位圖,那么,如果讓AlphaBlend以不同的通道值(從0到255)不斷地交替顯示兩幅圖片,這樣就實現了“擦除”效果。

編程實現
了解了上述原理,編程中的具體運用就不會再是難事了,下面以在VC中為例,說明這種圖形處理技術在編程中的具體實現。

首先在VC中新建一基于對話框的項目WipeImage。準備好兩幅等大的圖片(IDB_CROSS、IDB_LANTERN),并將圖片引入資源管理器。在CWipeImageDlg類中加入以下的全局成員變量聲明:

class CWipeImageDlg : public CDialog
{
// Construction
public:
BLENDFUNCTION m_bf;
CBitmap cross,lantern;
BITMAP bmp;
int bmpWidth,bmpHeight;
CDC dcForCross,dcForLantern;
CDC? dc;
BOOL bShowLantern;
………(系統自動生成部分)
};


接著在類向導中加入對WM_INITDIALOG和WM_TIMER消息的響應,其響應代碼分別如下:

BOOL CWipeImageDlg::OnInitDialog()
{
………(系統自動生成部分)
// TODO: Add extra initialization here
//初始化全局成員變量
this->bShowLantern=TRUE;
m_bf.BlendOp = AC_SRC_OVER;
m_bf.BlendFlags = 0;
m_bf.SourceConstantAlpha =10;
m_bf.AlphaFormat = 0;
//為節約篇幅,以下代碼中略去對操作不成功的處理代碼
if(!cross.LoadBitmap(IDB_CROSS))
{
AfxMessageBox("裝載位圖出錯!");
return FALSE;
}
cross.GetBitmap(&&bmp);
lantern.LoadBitmap(IDB_LANTERN);
cross.GetBitmap(&&bmp);
//獲得位圖的大小信息
bmpWidth=bmp.bmWidth;
bmpHeight=bmp.bmHeight;
dc=this->GetDC();
dcForCross.CreateCompatibleDC(dc);
dcForLantern.CreateCompatibleDC(dc);
//將位圖裝入設備環境句柄
dcForCross.SelectObject(&&cross);
dcForLantern.SelectObject(&&lantern);
//打開計時器
SetTimer(1000,50,NULL);
return TRUE;
}
void CWipeImageDlg::OnTimer(UINT nIDEvent)
{
//圖片透明度每次遞增5點
m_bf.SourceConstantAlpha+=5;
//當第一幅圖片完全可見之后,顯示另一張圖片
if(m_bf.SourceConstantAlpha>=200)
{
m_bf.SourceConstantAlpha=10;
//將bShowLantern做為顯示標志,確認應該顯示哪一張圖片 
bShowLantern=!bShowLantern;
}
if(bShowLantern)
{
//按透明度遞增的方式顯示“吊燈”圖片 AlphaBlend(?dc,0,0,bmpWidth,bmpHeight,dcForLantern,0,0,bmpWidth,bmpHeight,m_bf);
}
else
{
//按透明度遞增的方式顯示“背景”圖片
AlphaBlend(?dc,0,0,bmpWidth,bmpHeight,dcForCross,0,0,bmpWidth,bmpHeight,m_bf);
}
CDialog::OnTimer(nIDEvent);
}


編譯說明
由于AlphaBlend函數是在“Msimg32.dll”(對應于Msimg32.lib庫文件)中定義的。所以,為了避免LNK2001錯誤,在編譯前應該將“Msimg32.lib”文件加入FadeImage項目,然后運行上面的程序,你會發現,在或明或暗之間,你的兩幅位圖已經出現在屏幕之上了。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97