win32下 如何绘制像素,也许到你看到这个问题的时候会马上想到win32的绘制像素函数SetPixel(),如果SetPixel函数来做这个软件渲染器的话,那运行效率将低的可怜,假设我们的视口屏幕为800X600的分辨率,也就是屏幕上有800X600个(48万个)像素点,也就是绘制整个屏幕的像素你得至少调用48W次SetPixel函数,那将是多么低的效率。有一种更高效的方法,就是定义一个缓存,然后在缓存相应位置(对应屏幕的一个像素的位置)存入一个代表颜色的数据,在每帧的最后将缓存的数据作为颜色全部输入到屏幕,这样效率大大提高,下面请看实现代码:
//屏幕宽度和高度
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define bits 24 //每个像素的位数
//背后缓存,深度缓存
BYTE buffer[SCREEN_WIDTH*SCREEN_HEIGHT*bits / 8]; //每三个byte为一个像素,总共有800*600个像素,800*600*3个byte,BGR的颜色存储顺序,
//主窗口的HDC和handle
static HDC screen_hdc;
static HWND screen_hwnd;
static HDC hCompatibleDC; //兼容HDC
static HBITMAP hCompatibleBitmap; //兼容BITMAP
static HBITMAP hOldBitmap; //旧的BITMAP
static BITMAPINFO binfo; //BITMAPINFO结构体
//填充BITMAPINFO结构体
ZeroMemory(&binfo, sizeof(BITMAPINFO));
binfo.bmiHeader.biBitCount = 24; //每个像素多少位,也可直接写24(RGB)或者32(RGBA)
binfo.bmiHeader.biCompression = BI_RGB;
binfo.bmiHeader.biHeight = -SCREEN_HEIGHT;
binfo.bmiHeader.biPlanes = 1;
binfo.bmiHeader.biSizeImage = 0;
binfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
binfo.bmiHeader.biWidth = SCREEN_WIDTH;
//获取屏幕HDC
screen_hwnd = hwnd;
screen_hdc = GetDC(screen_hwnd);
//获取兼容HDC和兼容Bitmap,兼容Bitmap选入兼容HDC(每个HDC内存每时刻仅能选入一个GDI资源,GDI资源要选入HDC才能进行绘制)
hCompatibleDC = CreateCompatibleDC(screen_hdc);
hCompatibleBitmap = CreateCompatibleBitmap(screen_hdc, SCREEN_WIDTH, SCREEN_HEIGHT);
hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, hCompatibleBitmap);
//将颜色数据打印到屏幕上,这下面两个函数每帧都得调用
SetDIBits(screen_hdc, hCompatibleBitmap, 0, SCREEN_HEIGHT, buffer, (BITMAPINFO*)&binfo, DIB_RGB_COLORS);
BitBlt(screen_hdc, -1, -1, SCREEN_WIDTH, SCREEN_HEIGHT, hCompatibleDC, 0, 0, SRCCOPY);
不过在这里我用byte数组存储的颜色数值,每一个byte存储RGB颜色的一个分量,假设我想视口屏幕位置(x,y)写入颜色rgb,则代码如下:
buffer[int(y) * 800 * 3 + (int(x) + 1) * 3 - 1] = b;
buffer[int(y) * 800 * 3 + (int(x) + 1) * 3 - 2] = g;
buffer[int(y) * 800 * 3 + (int(x) + 1) * 3 - 3] = r;
细心的你也许会发现在位置上颜色顺序为bgr,这点我也不知道是为什么
写了好几篇技术博客,放出程序的运行截图:
放出我的软件渲染器源代码:
https://github.com/2047241149/SoftRender
http://download.csdn.net/detail/qq_29523119/9698519