《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D编程基础

Posted f91og

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D编程基础相关的知识,希望对你有一定的参考价值。

第11章 Direct3D编程基础

2D游戏是贴图的艺术,3D游戏是渲染的艺术。这句话在我学过了之前的GDI编程之后,前一句算是有所体会,现在是来理解后一句的时候了。

安装DirectX SDK配置啥的就不说了,直接进入正题,先来个典型的Direct3D程序框架图:

主要分为5个部分:

  • 创建一个Windows窗口
  • Direct3D的初始化
  • 消息循环
  • 渲染图形
  • 结束应用程序,清除在初始化阶段锁创建的COM对象,退出程序

至于COM (Component Object Model, 组件对象模型) 接口,是一项能够使DirectX独立于编程语言并具备向下兼容的技术。COM接口对象通过控制对某对象的引用计数个数来决定其生命周期,由其自行经营。

一个DirectX程序通用框架:

  1 //-----------------------------------【头文件包含部分】---------------------------------------
  2 //    描述:包含程序所依赖的头文件
  3 //------------------------------------------------------------------------------------------------
  4 #include <d3d9.h>
  5 
  6 //-----------------------------------【宏定义部分】--------------------------------------------
  7 //    描述:定义一些辅助宏
  8 //------------------------------------------------------------------------------------------------
  9 #define WINDOW_WIDTH    800                            //为窗口宽度定义的宏,以方便在此处修改窗口宽度
 10 #define WINDOW_HEIGHT    600                            //为窗口高度定义的宏,以方便在此处修改窗口高度
 11 #define WINDOW_TITLE    L"【致我们永不熄灭的游戏开发梦想】Direct3D程序的核心框架"    //为窗口标题定义的宏
 12 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }   //定义一个安全释放宏,便于后面COM接口指针的释放
 13 
 14 //-----------------------------------【全局函数声明部分】-------------------------------------
 15 //    描述:全局函数声明,防止“未声明的标识”系列错误
 16 //------------------------------------------------------------------------------------------------
 17 LRESULT CALLBACK    WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );//窗口过程函数
 18 HRESULT                Direct3D_Init(HWND hwnd);         //在这个函数中进行Direct3D的初始化
 19 HRESULT                Objects_Init(HWND hwnd);         //在这个函数中进行要绘制的物体的资源初始化
 20 VOID                Direct3D_Render(HWND hwnd);     //在这个函数中进行Direct3D渲染代码的书写
 21 VOID                Direct3D_CleanUp( );                //在这个函数中清理COM资源以及其他资源
 22 
 23 //-----------------------------------【WinMain( )函数】---------------------------------------
 24 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
 25 {
 26     //【1】窗口创建四步曲之一:开始设计一个完整的窗口类
 27     WNDCLASSEX wndClass = { 0 };                            //用WINDCLASSEX定义了一个窗口类
 28     wndClass.cbSize = sizeof( WNDCLASSEX ) ;            //设置结构体的字节数大小
 29     wndClass.style = CS_HREDRAW | CS_VREDRAW;    //设置窗口的样式
 30     wndClass.lpfnWndProc = WndProc;                    //设置指向窗口过程函数的指针
 31     wndClass.cbClsExtra        = 0;                                //窗口类的附加内存,取0就可以了
 32     wndClass.cbWndExtra        = 0;                            //窗口的附加内存,依然取0就行了
 33     wndClass.hInstance = hInstance;                        //指定包含窗口过程的程序的实例句柄。
 34     wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
 35     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
 36     wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个白色画刷句柄    
 37     wndClass.lpszMenuName = NULL;                        //用一个以空终止的字符串,指定菜单资源的名字。
 38     wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";        //用一个以空终止的字符串,指定窗口类的名字。
 39 
 40     //【2】窗口创建四步曲之二:注册窗口类
 41     if( !RegisterClassEx( &wndClass ) )                //设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
 42         return -1;        
 43 
 44     //【3】窗口创建四步曲之三:正式创建窗口
 45     HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE,                //喜闻乐见的创建窗口函数CreateWindow
 46         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
 47         WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
 48 
 49     //Direct3D资源的初始化
 50     Direct3D_Init (hwnd);   
 51 
 52     //【4】窗口创建四步曲之四:窗口的移动、显示与更新
 53     MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);        //调整窗口显示时的位置,使窗口左上角位于(250,80)处
 54     ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口
 55     UpdateWindow(hwnd);                        //对窗口进行更新,就像我们买了新房子要装修一样
 56 
 57     //【5】消息循环过程
 58     MSG msg = { 0 };  //初始化msg
 59     while( msg.message != WM_QUIT )            //使用while循环
 60     {
 61         if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
 62         {
 63             TranslateMessage( &msg );        //将虚拟键消息转换为字符消息
 64             DispatchMessage( &msg );        //该函数分发一个消息给窗口程序。
 65         }
 66         else
 67         {
 68             Direct3D_Render(hwnd);   //进行渲染
 69         }
 70     }
 71     //【6】窗口类的注销
 72     UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
 73     return 0;  
 74 }
 75 
 76 //-----------------------------------【WndProc( )函数】--------------------------------------
 77 //    描述:窗口过程函数WndProc,对窗口消息进行处理
 78 //------------------------------------------------------------------------------------------------
 79 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )      
 80 {
 81     switch( message )                        //switch语句开始
 82     {
 83     case WM_PAINT:                        // 若是客户区重绘消息
 84         Direct3D_Render(hwnd);                 //调用Direct3D渲染函数
 85         ValidateRect(hwnd, NULL);        // 更新客户区的显示
 86         break;                                    //跳出该switch语句
 87 
 88     case WM_KEYDOWN:                    // 若是键盘按下消息
 89         if (wParam == VK_ESCAPE)    // 如果被按下的键是ESC
 90             DestroyWindow(hwnd);        // 销毁窗口, 并发送一条WM_DESTROY消息
 91         break;                                    //跳出该switch语句
 92 
 93     case WM_DESTROY:                    //若是窗口销毁消息
 94         Direct3D_CleanUp();            //调用自定义的资源清理函数Game_CleanUp()进行退出前的资源清理
 95         PostQuitMessage( 0 );            //向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
 96         break;                                    //跳出该switch语句
 97 
 98     default:                                        //若上述case条件都不符合,则执行该default语句
 99         return DefWindowProc( hwnd, message, wParam, lParam );        //调用缺省的窗口过程
100     }
101 
102     return 0;                                    //正常退出
103 }
104 
105 //-----------------------------------【Direct3D_Init( )函数】--------------------------------------
106 //    描述:Direct3D初始化函数,进行Direct3D的初始化
107 //------------------------------------------------------------------------------------------------
108 HRESULT Direct3D_Init(HWND hwnd)
109 {
110     if(!(S_OK==Objects_Init(hwnd))) return E_FAIL;     //调用一次Objects_Init,进行渲染资源的初始化
111     return S_OK;
112 }
113 
114 
115 
116 //-----------------------------------【Object_Init( )函数】--------------------------------------
117 //    描述:渲染资源初始化函数,在此函数中进行要被渲染的物体的资源的初始化
118 //--------------------------------------------------------------------------------------------------
119 HRESULT Objects_Init(HWND hwnd)
120 {
121     return S_OK;
122 }
123 
124 
125 //-----------------------------------【Direct3D_Render( )函数】--------------------------------------
126 //    描述:使用Direct3D进行渲染
127 //--------------------------------------------------------------------------------------------------
128 void Direct3D_Render(HWND hwnd)
129 {
130     //暂时为空
131 }
132 
133 
134 //-----------------------------------【Direct3D_CleanUp( )函数】--------------------------------
135 //    描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
136 //---------------------------------------------------------------------------------------------------
137 void Direct3D_CleanUp()
138 {
139     //暂时为空
140 }
View Code

关于上面的程序有两点要提到的是:

1.  #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } 这里的宏定义是定义了一个带参数的宏,我以前以为C++中宏定义只能定义一个全局变量之类的,看来还是理解得不够深入。C++宏定义详解 。

2. 那个S_OK是WinError.h中预定好的宏,#define S_OK  ((HRESULT)0L),其实就是0。HRESULT在msdn中的定义如下:

接下来写的Direct3D程序,简单点说,只需做如下这四步就可以了:

  • 在Direct3D_Init()函数里完成Direct3D的相关初始化
  • 在Objects_Init()函数里完成将要绘制的绘制资源的初始化
  • 在Direct3D_Render()函数里完成渲染
  • 在Direct3D_CleanUp()函数里完成资源的清理

1. Direct3D初始化

下面来介绍下Direct3D初始化4步曲:

  • 创建Direct3D接口对象
  • 获取设备硬件信息
  • 填充 D3DPRESENT_PARAMETERS 结构体
  • 创建Direct3D设备接口

第一步是创建Direct3D接口对象,注意Direct3D接口对象和Direct3D设备接口不是一个概念。

LPDIRECT3D9 pD3D = NULL; //Direct3D接口对象的创建

上面定义了一个LPDIRECT3D9类型的指针,不过我看到这里的时候觉得好奇怪,定义指针不是应该有个 * 号的么?为什么这里不用加呢? 用编译器查找定义功能,终于在 d3d9.h 中找到了答案:

typedef struct IDirect3D9 *LPDIRECT3D9, *PDIRECT3D9;

现在终于明白为什么不需要加 * 号了,因为已经在头文件中定义过了,这里也涉及到了结构体指针的用法,需要自己体会总结一番的。那么下面的问题是IDirect3D9是什么玩意,查了mdsn文档,发现它是一个接口:

Applications use the methods of the IDirect3D9 interface to create Microsoft Direct3D objects and set up the environment. This interface includes methods for enumerating and retrieving capabilities of the device.

然后要将该对象初始化,用 Direct3DCreate9 函数:

Create an IDirect3D9 object and return an interface to it.

IDirect3D9* Direct3DCreate9(
   UINT SDKVersion
);

这个函数返回指向IDirect3D9接口的指针,并进行DirectX的版本协商。所以初始化的第一步可以这样写:

// 【Direct3D初始化四步曲之一,创接口】:创建Direct3D接口对象, 以便用该Direct3D对象创建Direct3D设备对象
    //--------------------------------------------------------------------------------------
    LPDIRECT3D9  pD3D = NULL; //Direct3D接口对象的创建
    if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口对象,并进行DirectX版本协商
        return E_FAIL;

第二步是获取设备信息,使用的是GetDeviceCaps方法,获取指定设备的性能参数,会把所获取的硬件设备的信息保存到一个叫 D3DCAPS9 的预设好的结构体中。

IDirect3D9::GetDeviceCaps method:

HRESULT GetDeviceCaps(
  [in]  UINT       Adapter,
  [in]  D3DDEVTYPE DeviceType,
  [out] D3DCAPS9   *pCaps
);

第一个参数是显卡的序号,通常使用默认值D3DADAPTER_DEFAULT,表示使用当前显卡。第二个参数是D3DDEVTYPE类型的,表示设备类型,取值为D3DDEVTYPE结构体的某一成员:

typedef enum D3DDEVTYPE { 
  D3DDEVTYPE_HAL          = 1,
  D3DDEVTYPE_NULLREF      = 4,
  D3DDEVTYPE_REF          = 2,
  D3DDEVTYPE_SW           = 3,
  D3DDEVTYPE_FORCE_DWORD  = 0xffffffff
} D3DDEVTYPE, *LPD3DDEVTYPE;

 第3个参数是 用于接受设备信息的D3DCAPS9结构体指针,查了下mdsn文档,里面的成员太多了,就不贴出来了。

 

顶点是3D图形学中的基本元素(说道这里,其实我并没有学过有关计算机图形学的内容,直接来学DirectX是不是有点太突兀了),而Direct3D中有硬件顶点运算(显卡支持,速度快)和软件顶点运算这两种方式。所以我们应该优先考虑硬件顶点运算方式。但是老的显卡也许不支持硬件顶点运算,所以我们需要在Direct3D初始化过程中,通过GetDeviceCaps方法检查显卡支持顶点运算模式。

Direct3D初始化的第二步可以这样写:

   D3DCAPS9 caps; int vp = 0;
    if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) )
    {
        return E_FAIL;
    }
    if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
        vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;   //支持硬件顶点运算,我们就采用硬件顶点运算,妥妥的
    else
        vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,无奈只好采用软件顶点运算

注:

上面的 caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT 这里做了个按位与运算,我原来以为是逻辑与。至于这里为什么作个逻辑与运算便可以判断是否支持硬件顶点运算,我也不是很明白。

下面是一些字段在MSDN中的解释:.

D3DDEVTYPE_HAL:Hardware rasterization(光栅化). Shading is done with software, hardware, or mixed transform and lighting.

D3DCAPS9里的成员DevCaps: Flags identifying the capabilities of the device

D3DDEVCAPS_HWTRANSFORMANDLIGHT:#define D3DDEVCAPS_HWTRANSFORMANDLIGHT  0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */

#define FAILED(hr) (((HRESULT)(hr)) < 0)

 

第三步是填充 D3DPRESENT_PARAMETERS 结构体,这个结构体很重要

typedef struct _D3DPRESENT_PARAMETERS_
{
    UINT                BackBufferWidth;  //后台缓冲区宽度
    UINT                BackBufferHeight;  //后台缓冲区高度
    D3DFORMAT           BackBufferFormat;  //后台缓冲区的保存像素格式
    UINT                BackBufferCount;  
    D3DMULTISAMPLE_TYPE MultiSampleType;  //多重采样类型
    DWORD               MultiSampleQuality;  //多重采样的格式
    D3DSWAPEFFECT       SwapEffect;    //指定Direct3D如何将后台缓冲区的内容复制到前台缓存中
    HWND                hDeviceWindow;  //窗口句柄,指定在哪个窗口上进行绘制
    BOOL                Windowed;    //窗体的显示模式,TRUE表示窗口模式,FALSE表示全屏模式
    BOOL                EnableAutoDepthStencil;  //是否为应用程序自动管理深度缓存
    D3DFORMAT           AutoDepthStencilFormat;  
    DWORD               Flags;    //附加属性,通常为0
    /* FullScreen_RefreshRateInHz must be zero for Windowed mode */
    UINT                FullScreen_RefreshRateInHz;     //全屏幕时指定屏幕的刷新率
    UINT                PresentationInterval;          //指定后台缓冲区与前台缓冲区的最大交换频率
} D3DPRESENT_PARAMETERS;

 有好多专业名词,看得也不是很明白。Direct3D初始化的第三步代码:

  D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.BackBufferWidth            = WINDOW_WIDTH;
    d3dpp.BackBufferHeight           = WINDOW_HEIGHT;
    d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
    d3dpp.BackBufferCount            = 1;
    d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality         = 0;
    d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
    d3dpp.hDeviceWindow              = hwnd;
    d3dpp.Windowed                   = true;
    d3dpp.EnableAutoDepthStencil     = true; 
    d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
    d3dpp.Flags                      = 0;
    d3dpp.FullScreen_RefreshRateInHz = 0;
    d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

 注:ZeroMemory函数:Fills a block of memory with zeros.用0来填充一块内存区域

void ZeroMemory(
  [in] PVOID  Destination,    //A pointer to the starting address of the block of memory to fill with zeros.
  [in] SIZE_T Length      //The size of the block of memory to fill with zeros, in bytes.
);

 Direct3D初始化第四步是正式创建Direct3D设备接口,其实就是利用第一步创建的Direct3D接口对象,调用其IDirect3D9::CreateDevice方法:

HRESULT CreateDevice(
  [in]          UINT                  Adapter,  //显卡序号
  [in]          D3DDEVTYPE            DeviceType,  //设备类型
  [in]          HWND                  hFocusWindow,  //窗口句柄,指定当Direct3D程序从前台变换到后台时的提示窗口
  [in]          DWORD                 BehaviorFlags,  //设备行为标识
  [in, out]     D3DPRESENT_PARAMETERS *pPresentationParameters,  //第三步创建的结构体
  [out, retval] IDirect3DDevice9      **ppReturnedDeviceInterface   //指定我们创建的Direct3D设备接口的指针,使用这个指针,已完成之后的绘制过程
);

 Direct3D初始化第四步代码:

if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
        hwnd, vp, &d3dpp, &g_pd3dDevice)))
        return E_FAIL;

 Direct3D初始化的完整代码如下:

  1 #include <d3d9.h>
  2 
  3 //-----------------------------------【库文件包含部分】---------------------------------------
  4 #pragma comment(lib,"winmm.lib")  //调用PlaySound函数所需库文件
  5 #pragma comment(lib,"d3d9.lib")
  6 #pragma comment(lib,"d3dx9.lib")
  7 
  8 //-----------------------------------【宏定义部分】--------------------------------------------
  9 #define WINDOW_WIDTH    800                            //为窗口宽度定义的宏,以方便在此处修改窗口宽度
 10 #define WINDOW_HEIGHT    600                            //为窗口高度定义的宏,以方便在此处修改窗口高度
 11 #define WINDOW_TITLE    L"【致我们永不熄灭的游戏开发梦想】Direct3D初始化四步曲 示例程序"    //为窗口标题定义的宏
 12 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }   //定义一个安全释放宏,便于后面COM接口指针的释放
 13 
 14 //-----------------------------------【全局变量声明部分】-------------------------------------
 15 LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; //Direct3D设备对象
 16 
 17 
 18 //-----------------------------------【全局函数声明部分】-------------------------------------
 19 LRESULT CALLBACK    WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );//窗口过程函数
 20 HRESULT                    Direct3D_Init(HWND hwnd);         //在这个函数中进行Direct3D的初始化
 21 HRESULT                    Objects_Init(HWND hwnd);         //在这个函数中进行要绘制的物体的资源初始化
 22 VOID                            Direct3D_Render(HWND hwnd);     //在这个函数中进行Direct3D渲染代码的书写
 23 VOID                            Direct3D_CleanUp( );                //在这个函数中清理COM资源以及其他资源
 24 
 25 //-----------------------------------【WinMain( )函数】--------------------------------------
 26 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
 27 {
 28     //【1】窗口创建四步曲之一:开始设计一个完整的窗口类
 29     WNDCLASSEX wndClass = { 0 };                            //用WINDCLASSEX定义了一个窗口类
 30     wndClass.cbSize = sizeof( WNDCLASSEX ) ;            //设置结构体的字节数大小
 31     wndClass.style = CS_HREDRAW | CS_VREDRAW;    //设置窗口的样式
 32     wndClass.lpfnWndProc = WndProc;                    //设置指向窗口过程函数的指针
 33     wndClass.cbClsExtra        = 0;                                //窗口类的附加内存,取0就可以了
 34     wndClass.cbWndExtra        = 0;                            //窗口的附加内存,依然取0就行了
 35     wndClass.hInstance = hInstance;                        //指定包含窗口过程的程序的实例句柄。
 36     wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
 37     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
 38     wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个白色画刷句柄    
 39     wndClass.lpszMenuName = NULL;                        //用一个以空终止的字符串,指定菜单资源的名字。
 40     wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";        //用一个以空终止的字符串,指定窗口类的名字。
 41 
 42     //【2】窗口创建四步曲之二:注册窗口类
 43     if( !RegisterClassEx( &wndClass ) )                //设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
 44         return -1;        
 45 
 46     //【3】窗口创建四步曲之三:正式创建窗口
 47     HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE,                //喜闻乐见的创建窗口函数CreateWindow
 48         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
 49         WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
 50 
 51     //Direct3D资源的初始化,成功或者失败都用messagebox予以显示
 52     if (S_OK==Direct3D_Init (hwnd))
 53     {
 54         MessageBox(hwnd, L"Direct3D初始化完成~!", L"浅墨的消息窗口", 0); //使用MessageBox函数,创建一个消息窗口  
 55     }
 56     else
 57     {
 58         MessageBox(hwnd, L"Direct3D初始化失败~!", L"浅墨的消息窗口", 0); //使用MessageBox函数,创建一个消息窗口 
 59     }
 60 
 61     //【4】窗口创建四步曲之四:窗口的移动、显示与更新
 62     MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);        //调整窗口显示时的位置,使窗口左上角位于(250,80)处
 63     ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口
 64     UpdateWindow(hwnd);                        //对窗口进行更新,就像我们买了新房子要装修一样
 65 
 66 
 67     PlaySound(L"NightElf3.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循环播放背景音乐 
 68 
 69     //【5】消息循环过程
 70     MSG msg = { 0 };  //初始化msg
 71     while( msg.message != WM_QUIT )            //使用while循环
 72     {
 73         if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
 74         {
 75             TranslateMessage( &msg );        //将虚拟键消息转换为字符消息
 76             DispatchMessage( &msg );        //该函数分发一个消息给窗口程序。
 77         }
 78         else
 79         {
 80             Direct3D_Render(hwnd);   //进行渲染
 81         }
 82     }
 83     //【6】窗口类的注销
 84     UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
 85     return 0;  
 86 }
 87 
 88 //-----------------------------------【WndProc( )函数】--------------------------------------
 89 //    描述:窗口过程函数WndProc,对窗口消息进行处理
 90 //------------------------------------------------------------------------------------------------
 91 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )      
 92 {
 93     switch( message )                        //switch语句开始
 94     {
 95     case WM_PAINT:                        // 若是客户区重绘消息
 96         Direct3D_Render(hwnd);                 //调用Direct3D渲染函数
 97         ValidateRect(hwnd, NULL);        《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——DirectInput&纹理映射

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——四大变换

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——光照与材质

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D编程基础

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记9——游戏摄像机&三维地形的构建

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记10——三维天空的构建&三维粒子的实现&多游戏模型的载入