Visual C++游戏编程基础之透明半透明效果
一、基本思路
1.半透明的原理
一张位图由许多像素组成,而每一像素包含R、G、B三原色,三原色的值决定了像素的色彩,要实现半透明效果,需要把前景图 和背景图彼此对应的像素颜色按某一比例进行调配,称为 ‘不透明度’,直接贴图,则前景图不透明度为100%,背景图为0%;
公式:半透明图色彩=前景图色彩 * 不透明度 + 背景图色彩 * (1-不透明度)
2.半透明操作步骤
(1)取得位图结构,需要使用GetObject函数,介绍如下:
函数原型:int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject);
函数功能:表示获取位图的信息
参数一 : 要获取的位图句柄
参数二 : 指定将要写到缓冲区的信息的字节数目,在这里是位图类型的字节数
参数三 : 在这里是指向位图结构变量的地址,该变量当作缓冲区
关于位图结构BITMAP介绍如下:
(2)建立暂存数组,目的是为了存储位图中所有像素的颜色值
unsigned char * px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];
其中数组的大小即为整个位图所有像素占的字节数,若一个像素24bits,则占3个字节,也就是3个数组元素
(3)取得位图中所有的颜色值,并存储到暂存数组中,函数介绍如下:
函数原型:LONG GetBitmapBits(HBITMAP hbmp, LONG cbBuffer, LPVOID lpvBits);
函数功能:把位图的色彩值存储到暂存数组中
参数一 :位图句柄
参数二 :要取得的字节数
参数三 :指向暂存数组
(4)合成像素颜色值,这里介绍基本思想:
假设每个像素24bit,则每个像素占3字节,关于背景图,首先要取得整张图像素各原色值所在的索引值,即:
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.7; //PxBytes为每个像素所占的字节数px1[rgb_b+1] = px1[rgb_b+1] * 0.7; //bmWidthBytes为每一列像素占的字节数px1[rgb_b+2] = px1[rgb_b+2] * 0.7; }}
举个简单的例子,假设从(xstart,ystary)~(xend,yend) 为 (0,0)~(1,1),则有如下情况:
[0][1][2] [3][4][5]
[6][7][8] [9][10][11]
注释:每个像素占3个字节;每一列像素占6字节,书里都把行称为列,也不知道为啥
同理:处理前景图时,直接进行颜色合成:前景图30%的不透明度+背景图70%的不透明度,存放到px2
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.3 + px1[i]; //半透明色彩合成px2[rgb_b+1] = px2[rgb_b+1] *0.3 + px1[i+1]; px2[rgb_b+2] = px2[rgb_b+2] *0.3 + px1[i+2];}}
(5)重设位图颜色,根据暂存数组中的内容重设位图颜色
函数原型:LONG SetBitmapBits(HBITMAP hmbp, DWORD cBytes, CONST VOID (lpBits));
函数功能:重设位图颜色
参数一 :要设置的位图句柄
参数二 :暂存数组的字节数
参数三 :指向暂存数组
二、结合前面所学的实现透明半透明效果,代码如下:
#include "stdafx.h"
#include <stdio.h>HINSTANCE hInst;
HBITMAP bg,girl;
HDC mdc;const int xstart = 222;
const int ystart = 50;ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void MyPaint(HDC hdc);int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{MSG msg;MyRegisterClass(hInstance);if (!InitInstance (hInstance, nCmdShow)) {return FALSE;}while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;
}ATOM MyRegisterClass(HINSTANCE hInstance)
{WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = (WNDPROC)WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = NULL;wcex.hCursor = NULL;wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = NULL;wcex.lpszClassName = "canvas";wcex.hIconSm = NULL;return RegisterClassEx(&wcex);
}BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{HWND hWnd;HDC hdc,bufdc;HBITMAP bmp;BITMAP bm1,bm2;hInst = hInstance;hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){return FALSE;}MoveWindow(hWnd,10,10,600,445,true);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,600,400,LR_LOADFROMFILE); //背景图句柄bmp = (HBITMAP)LoadImage(NULL,"girlmask.bmp",IMAGE_BITMAP,766,345,LR_LOADFROMFILE);//前景图句柄GetObject(bg,sizeof(BITMAP),&bm1); //get the message of image to bm1if(bm1.bmBitsPixel != 32 && bm1.bmBitsPixel != 24) //bit of pixe l{MessageBox(NULL,"此程序只能在32 bit 或 24 bit 显示模式中运行","警告",0);return FALSE;}hdc = GetDC(hWnd);mdc = CreateCompatibleDC(hdc);//建立与窗口DC兼容的内存DC "mdc"bufdc = CreateCompatibleDC(hdc);//建立与窗口DC兼容的内存DC "bufdc",选择前景图或背景图,贴到mdc作透明处理girl = CreateCompatibleBitmap(hdc,383,345);//建立一个与窗口相兼容的空位图"girl",298*329像素,处理后就是要贴到窗口的透明半透明图案SelectObject(mdc,girl);//girl 存到 mdc,在mdc上进行透明处理SelectObject(bufdc,bg);//bg replace bufdc,背景图bg存入bufdcBitBlt(mdc,0,0,383,345,bufdc,xstart,ystart,SRCCOPY);//将透明区域的背景图贴到mdc中SelectObject(bufdc,bmp);//将包含屏蔽图的前景图存入bufdcBitBlt(mdc,0,0,383,345,bufdc,383,0,SRCAND);//屏蔽图在整张图中,左上角坐标(298,0),屏蔽图与背景图and运算BitBlt(mdc,0,0,383,345,bufdc,0,0,SRCPAINT);//前景图与背景图or运算,得到透明后的前景图,接下来进行半透明处理unsigned char *px1,*px2;px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];GetBitmapBits(bg,bm1.bmHeight * bm1.bmWidthBytes,px1);//px1储存位图颜色值GetObject(girl,sizeof(BITMAP),&bm2);//bme得到girl的全部信息px2 = new unsigned char [bm2.bmHeight * bm2.bmWidthBytes];GetBitmapBits(girl,bm2.bmHeight * bm2.bmWidthBytes,px2);//px2储存位图bm2的颜色值int x,y,xend,yend;int i;int rgb_b;int PxBytes = bm1.bmBitsPixel / 8 ;xend = xstart + 383;yend = ystart + 345;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.7; px1[rgb_b+1] = px1[rgb_b+1] * 0.7; px1[rgb_b+2] = px1[rgb_b+2] * 0.7; }}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.3 + px1[i]; px2[rgb_b+1] = px2[rgb_b+1] *0.3 + px1[i+1]; px2[rgb_b+2] = px2[rgb_b+2] *0.3 + px1[i+2]; }}SetBitmapBits(girl,bm2.bmHeight*bm2.bmWidthBytes,px2);MyPaint(hdc);ReleaseDC(hWnd,hdc);DeleteDC(bufdc);DeleteObject(bmp);delete [] px1;delete [] px2;return TRUE;
}void MyPaint(HDC hdc)
{SelectObject(mdc,bg);//bg replace mdc,bg存入到mdc中BitBlt(hdc,0,0,600,400,mdc,0,0,SRCCOPY);//将mdc贴到hdcSelectObject(mdc,girl);BitBlt(hdc,xstart,ystart,383,345,mdc,0,0,SRCCOPY);
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;switch (message){case WM_PAINT: hdc = BeginPaint(hWnd, &ps);MyPaint(hdc);EndPaint(hWnd, &ps);break;case WM_DESTROY: DeleteDC(mdc);DeleteObject(bg);DeleteObject(girl);PostQuitMessage(0);break;default: return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}
四、效果
Visual C++游戏编程基础之透明半透明效果相关推荐
- Visual C++游戏编程基础之多背景循环动画
一.基本思路 1.现在有三张背景图:天空和草地.山峦.房屋: 2.天空在最远处,其次是草地和山峦(因为山峦在草地上),最后是房屋: 3.背景的循环速度是天空最慢.然后是山峦.最后是草地和房屋: 4.恐 ...
- Visual C++游戏编程基础之景物贴图
一.基本思路 1.首实现斜角贴图,需要显示菱形图块,使用矩形图块贴图,但是要将它的周围进行透明处理,只显示菱形部分 2.计算图块索引值的公式: 列编号 = 索引值 / 每一列的图块个数: 行编号 = ...
- Visual C++游戏编程基础之键盘消息
一.键盘 1.虚拟键码:Windows系统下所有的按键被视为虚拟键(包含鼠标在内),每一个虚拟键都有其对应的虚拟键码: 2.键盘消息 (1)VM_KEWDOWN:按下按键消息: (2)VM_KEYUP ...
- Visual C++游戏编程基础之摩擦力、加速度、重力
一.基本思路 1.假设小球在空中只受到重力作用,一开始给它一个水平的速度,就像是平抛运动一样: 2.当小球碰到地面时,受到摩擦力作用,分为x方向和y方向: 3.在摩擦力作用下,1.减少水平方向的速度, ...
- Visual C++游戏编程基础之利用鼠标消息实现贴图
一.鼠标键入消息 1.WM_LBUTTONDBLCLK 双击鼠标左键: 2.WM_LBUTTONDOWN 单击鼠标左键: 3.WM_LBUTTONUP ...
- Visual C++游戏编程基础之追逐移动
一.基本思路 1.追逐移动的实现与飞机追随鼠标光标原理类似: 2.现在小鸟作为追逐者,设定其贴图坐标为(nowX-25,nowY-16),其中(nowX,nowY)是飞机的贴图坐标: 3.通过判断小鸟 ...
- VC++游戏编程基础无法找到“d3d9.h”问题
经反复查阅是缺少Direct X SDK导致的,我用的是VC++6.0,支持Direct X SDK 9.0b及之前的版本,最新版DX SDK(JUNE)VC6驾驭不了...下面是我解决问题的思路(只 ...
- 游戏编程基础(五)背景地图滚动显示
在游戏过程中,背景地图需要跟着人物的移动而动态的滚动变换.C++游戏编程基础中介绍了2D游戏中常用的3种动态背景表现手法.其原理和实现技巧分析如下: 方法一:单一背景滚动 原理是:利用 ...
- 小学生python游戏编程arcade----动画图片实现爆炸效果
小学生python游戏编程arcade----动画图片实现爆炸效果 前言 动画图片实现爆炸效果 1.爆炸类的的实现 1.1爆炸图片 1.2 类的定义 1.3 爆炸类的引用 1.4 爆炸类的更新 1.5 ...
最新文章
- JForum 的 SSO集成
- Python图像处理:图像腐蚀与图像膨胀
- 全国成人计算机考试题,成人计算机考试试题.docx
- 名片去噪识别-aip
- Python : 什么是*args和**kwargs[转载]
- 物料单位转换的两个函数
- #pragma 详解
- 各种锁的介绍、锁之间的区别
- python内存分配失败_关于python:如何避免[Errno 12]无法分配使用子进程模块导致的内存错误...
- react中创建组件
- javaMail发送邮件设置发件人中文昵称
- 用java怎么做微信公众号,用Java搭建微信公众号(一)构建基础请求框架
- ​在Windows 10 下安装 Vmware 时遇到的问题和解决​方法
- 详解17000tps的以太坊snark侧链方案
- 提问 未来计算机的发展趋势是什么,计算机今后的发展趋势是什么?
- 电脑如何剪辑视频?自学视频剪辑的朋友看过来
- “海底数据中心”被打捞出水,故障率仅为陆地1/8;京东超大规模联邦学习平台开源...
- 腾讯提供的TBS调试小程序页面
- 如何设置Windows XP自动登录
- 佳顺通用进销存系统去广告_母婴收银系统应该如何选择?