从零开始写光栅化渲染器0:创建windows窗口

0.光栅化渲染器概述

主要实现了以下功能:

2D部分:

  • 光栅化2D点
  • 光栅化2D直线
  • 光栅化2D三角形

3D部分:

  • 把顶点从三维世界空间变换至二维屏幕空间,把顶点连线(如各种三维正多面体)光栅化成wire frame模型
  • 三角形光栅化
  • 使用深度缓冲
  • 实现简单的纹理映射,先做屏幕空间的插值,然后实现简单的透视纹理校正
  • 实现简单的顶点光照,使用顶点颜色插值实现Gouraud shading

具体参考以下前辈的建议与实现

Milo Yip
韦易笑
萧井陌 ·
从零实现3D图像引擎

1.windows窗口结构

要创建一个windows窗口我们得先对窗口结构有一定的了解,MSDN官网:
MSDN WNDCLASSEX structure
这里做一个简要说明

typedef struct tagWNDCLASSEX {
  UINT      cbSize;             //窗口大小(count of byte),设为 sizeof(WNDCLASSEX)
  UINT      style;              //窗口风格
  WNDPROC   lpfnWndProc;        //指向窗口过程函数的函数指针
  int       cbClsExtra;         //窗口类附加内存
  int       cbWndExtra;         //窗口附加内存
  HINSTANCE hInstance;          //指定包含窗口过程的实例句柄
  HICON     hIcon;              //图标句柄
  HCURSOR   hCursor;            //光标句柄
  HBRUSH    hbrBackground;      //背景画刷句柄
  LPCTSTR   lpszMenuName;       //菜单资源的名字
  LPCTSTR   lpszClassName;      //窗口类的名字
  HICON     hIconSm;            //窗口类小图标句柄
} WNDCLASSEX, *PWNDCLASSEX;

2.一个完整的示例

#include 
#include 
#include 
#include 

using namespace std;
const int WIDTH = 800;
const int HEIGHT = 800;

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        if (wparam==VK_ESCAPE)
        {
            DestroyWindow(hwnd);
        }
        break;
    default:
        return DefWindowProc(hwnd,message,wparam,lParam);
    }
    return 0;
}

HWND GameStart(HINSTANCE hInstance,int nShowCmd,string wcName,string title)
{
    //1.创建窗口类
    WNDCLASSEX wndClass = {};
    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = wcName.c_str();

    //2.注册窗口类
    assert(RegisterClassEx(&wndClass));

    //3.创建窗口
    HWND hwnd = CreateWindow(wcName.c_str(),title.c_str(),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,WIDTH,HEIGHT,NULL,NULL,hInstance,NULL);

    //4.调整大小,移动,显示,更新
    RECT window_rect = {0,0,WIDTH,HEIGHT};
    AdjustWindowRectEx(&window_rect, GetWindowStyle(hwnd), GetMenu(hwnd) != NULL, GetWindowExStyle(hwnd));
    MoveWindow(hwnd,300,150,window_rect.right-window_rect.left, window_rect.bottom-window_rect.top,false);
    ShowWindow(hwnd,nShowCmd);
    UpdateWindow(hwnd);

    return hwnd;
}

void GameUpdate(HWND hwnd)
{
    /*图形绘制*/
}

void GameEnd(string wcName,HINSTANCE hInstance)
{
    //5.注销窗口类
    UnregisterClass(wcName.c_str(),hInstance);
}


int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd )
{
    //1.创建窗口
    string windowClassName = "MyWindow";
    string title = "3DRender";
    HWND hwnd = GameStart(hInstance,nShowCmd,windowClassName,title);

    //时间初始化
    DWORD curTime = GetTickCount();
    DWORD preTime = GetTickCount();
    //2.消息循环
    MSG msg = {0};
    while (msg.message!=WM_QUIT)
    {
        //获取消息
        if (PeekMessage(&msg,0,NULL,NULL,PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            curTime = GetTickCount();
            if (curTime-preTime>30)
            {
                preTime = curTime;
                GameUpdate(hwnd);
            }
        }
    }

    //3.游戏结束
    GameEnd(windowClassName,hInstance);
    return 0;
}

以下是效果,如果出现字符错误,可以在VS中选择项目->属性->配置属性->常规->字符集->使用多字节字符集。
从零开始写光栅化渲染器0:创建windows窗口_第1张图片

3.项目完整地址:

3DRender: https://github.com/zhanghuanzj/3DRender.git

你可能感兴趣的:(从零开始写软件光栅化渲染器)