半透明在游戏中通常用于若隐若现的特殊效果,如雾,隐形单位。半透明的原理是通过前景图片与背景图片像素的混合来实现的。
用公式表示即为:半透明色 = 前景色X不透明度 + 背景色X(1-不透明度)
为了制作半透明效果,需要先了解一些基本的知识:
windows 位图结构
typedef struct tagBITMAP{
LONG bmType; //位图类型,必须为0
LONG bmWidth; //位图宽度
LONG bmHeight; //位图高度
LONG bmWidthBytes; //每一行像素所占的byte数
WORD bmPlanes; //颜色平面数
WORD bmBitsPixel; //像素的位数
LPVOID bmBits; //位图内存指针
}BITMAP;
步骤:
- 获取位图结构
函数原型:int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject); HBITMAP hBitmapImag; BITMAP bitmap ; hBitmapImag = LoadBitmap (hInstance, TEXT ("D:\\photos\\sample.bmp")) ; GetObject (hBitmapImag, sizeof (BITMAP), &bitmap) ;
- 建立暂存数组
unsigned char * px = new unsigned char[bm.bmHeight * bm.bmWidthBytes];
- 取得位图位
函数原型:LONG GetBitmapBits(HBITMAP hbmp, LONG cbBuffer, LPVOID lpvBits); BITMAP bitmap; GetObject(hBitmap, sizeof(BITMAP), &bitmap); DWORD dwSize = bitmap.bmHeight * bitmap.bmWidthBytes; unsigned char* pBits = new unsigned char[dwSize]; LONG dl = GetBitmapBits(hBitmap, dwSize, pBits);
- 合成像素半透明颜色
这一步根据需要透明的效果,根据上面的公式计算即可。
- 重设位图颜色
函数原型:LONG SetBitmapBits(HBITMAP hmbp, DWORD cBytes, CONST VOID (lpBits);
再结合之前GDI透明效果,就能实现透明半透明效果了。
主要是通过多使用一张内存DC与位图对象,先在内存DC上完成透明,再取此DC的位图来进行半透明处理即可
关键代码:
bg = (HBITMAP)LoadImage(NULL,"testbg.bmp",IMAGE_BITMAP,512,384,LR_LOADFROMFILE); //背景图
bmp = (HBITMAP)LoadImage(NULL,"sample2.bmp",IMAGE_BITMAP,276,232,LR_LOADFROMFILE);//屏蔽图
GetObject(bg,sizeof(BITMAP),&bm1); //获取背景位图结构
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc); //而外创建的内存DC
test = CreateCompatibleBitmap(hdc,276,232); //内存位图
SelectObject(mdc,test);
// 先进行透明处理
SelectObject(bufdc,bg);
BitBlt(mdc,0,0,276,232,bufdc,xstart,ystart,SRCCOPY);
SelectObject(bufdc,bmp);
BitBlt(mdc,0,0,276,232,bufdc,0,0,SRCAND);
bmp = (HBITMAP)LoadImage(NULL,"sample1.bmp",IMAGE_BITMAP,276,232,LR_LOADFROMFILE);
SelectObject(bufdc,bmp);
BitBlt(mdc,0,0,276,232,bufdc,0,0,SRCPAINT);
unsigned char *px1,*px2;
//背景位图的位数组
px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];
GetBitmapBits(bg,bm1.bmHeight * bm1.bmWidthBytes,px1);
//透明位图的位数组
GetObject(test,sizeof(BITMAP),&bm2);
px2 = new unsigned char [bm2.bmHeight * bm2.bmWidthBytes];
GetBitmapBits(test,bm2.bmHeight * bm2.bmWidthBytes,px2);
int x,y,xend,yend;
int i;
int rgb_b;
int PxBytes = bm1.bmBitsPixel / 8 ;
xend = xstart + 276;
yend = ystart + 232;
//背景色不透明度处理
for(y=ystart;y<yend;y++)
{
for(x=xstart;x<xend;x++)
{
rgb_b = y * bm1.bmWidthBytes + x * PxBytes ;
px1[rgb_b] = px1[rgb_b] * 0.5;
px1[rgb_b+1] = px1[rgb_b+1] * 0.5;
px1[rgb_b+2] = px1[rgb_b+2] * 0.5;
}
}
//前景色不透明度处理
for(y=0;y<(bm2.bmHeight); y++)
{
for(x=0;x<bm2.bmWidth; x++)
{
rgb_b = y * bm2.bmWidthBytes + x * PxBytes ;
i = (ystart+y) * bm1.bmWidthBytes + (xstart+x) * PxBytes;
px2[rgb_b] = px2[rgb_b] *0.5 + px1[i];
px2[rgb_b+1] = px2[rgb_b+1] *0.5 + px1[i+1];
px2[rgb_b+2] = px2[rgb_b+2] *0.5 + px1[i+2];
}
}
SetBitmapBits(test,bm2.bmHeight*bm2.bmWidthBytes,px2);
..............................................
SelectObject(mdc,bg);
BitBlt(hdc,0,0,512,384,mdc,0,0,SRCCOPY);
SelectObject(mdc,test);
BitBlt(hdc,xstart,ystart,276,232,mdc,0,0,SRCCOPY);
最终效果图: