VC++游戏开发随记之二十八.docx
- 文档编号:3275319
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:20
- 大小:36.55KB
VC++游戏开发随记之二十八.docx
《VC++游戏开发随记之二十八.docx》由会员分享,可在线阅读,更多相关《VC++游戏开发随记之二十八.docx(20页珍藏版)》请在冰点文库上搜索。
VC++游戏开发随记之二十八
【VisualC++】游戏开发笔记二十八最精简的Direct3D11Demo筋骨脉络全攻略
本篇文章将讲解如何通过我们在之前的文章里面已掌握的DirectX11的知识,来一步一步创建一个基于Direct3D11的BlankWindowsDemo,而我们在这节里面完成的这个demo,将在后面的文章里面作为一个模板,用于演示之后的各种新奇DirectX11的功能。
首先呢,为了代码的重用性着想,我们会写一个DirectX11DemoBase,并借鉴在笔记二十六中的Win32风格的BlankWin32WindowDemo中的代码,然后通过派生的方式,以及重载一些必要的虚函数,进行整合,来创建我们的demo。
一、 关于代码书写风格的讨论
首先,我们提出一个问题,采用自问自答的形式来讨论:
在这个demo的设计过程中,我们是采用C语言式的全局变量与全局函数的搭档模式来完成,还是采用C++式的面向对象风格的类Class来编写呢?
答案是后者,采用面向对象的思想来完成。
至于这个问题的解释,答案就仁者见仁智者见智了。
浅墨之前看过一本C++界的名著《C++沉思录》,作者在文章的开篇举了一个例子,然后通过例子对比出来的效果,折射出了对C与C++的一个中肯的评价,是这样的一段话:
“C++鼓励采用类来表示类似于输出流的事物,而类就提供了一个理想的位置来存放状态信息。
而C语言倾向于不存储状态信息,除非事先已经规划妥当。
因此C程序员趋向于假设有这样一个“环境”:
存在一个位置集合,他们可以在其中找到系统的当前状态。
如果只有一个环境和一个系统,这样考虑毫无问题,但是,系统在不断增长的过程中往往需要引入某些独一无二的东西,并且创建更多这类东西。
”
对这段话的解释,浅墨还是用自己的话来叙述吧:
通常我们采用一般的变量作为传递数据的容器,但是随着程序的复杂会导致数据量的加大,有太多的数据需要被传递,而且这些数据基本上都是需要传递到近乎是每一个函数当中的,这样我们就要创建很多的全局变量作为“容器”,如此下去我们的设计的程序只会越来越臃肿,越来越乱。
别怕别怕,有绝招呢——我们可以创建一个类或者结构体来收容这些对象,使之显得不是那么乱,取而代之的是井井有条。
绕了这么大一圈子,一言以蔽之,就是运用全局变量是不太好的编程习惯,我们应当少用甚至不用,转而使用“类”来完成这些任务。
二、 Dx11DemoBase类的设计
作为目前来说,我们要求本节的demo做到以下几点功能:
▲初始化D3D
▲释放在启动过程中创建的Direct3D对象
▲为我们的D3D对象存储成员变量
▲提供一个装载demo的具体内容的方式
▲提供一个卸载demo的具体内容的方式
▲能够显示demo每帧的更新的具体内容
▲demo渲染内容的具体代码
由我们上面的清单来看,创建一个公共的初始化和卸载函数,用于装载和卸载内容功能的虚函数,以及渲染和更新游戏循环步骤的虚函数的基类是很有必要的。
通过将这些函数设为虚函数,由基类派生出来的demo类能够实现他们自定义的逻辑和行为。
根据上面的这些叙述,我们可以写出下面的这段为Dx11DemoBase量身打造的代码:
代码段一 Dx11DemoBases类的头文件
[cpp] viewplaincopyprint?
1.#ifndef _DEMO_BASE_H_
2.#define _DEMO_BASE_H_
3.#include
4.#include
5.#include
6.class Dx11DemoBase
7.{
8.public:
9. Dx11DemoBase();
10. virtual ~Dx11DemoBase();
11. bool Initialize( HINSTANCE hInstance, HWND hwnd );
12. void Shutdown( );
13. virtual bool LoadContent( );
14. virtual void UnloadContent( );
15. virtual void Update( float dt ) = 0;
16. virtual void Render( ) = 0;
17. protected:
18. HINSTANCE hInstance_;
19. HWND hwnd_;
20. D3D_DRIVER_TYPE driverType_;
21. D3D_FEATURE_LEVEL featureLevel_;
22. ID3D11Device* d3dDevice_;
23. ID3D11DeviceContext* d3dContext_;
24. IDXGISwapChain* swapChain_;
25. ID3D11RenderTargetView* backBufferTarget_;
26.};
27.#endif
上面这段代码中我们可以看到最精简的D3D对象,以protected类成员的形式存在于类之中。
在类体外初始化变量是比较好的编程习惯,而且效率比让先调用拷贝构造函数,再调用默认构造函数要高得多。
Dx11DemoBase类构造函数,析构函数,装载内容,卸载内容,shutdown函数定义如下:
代码段二一些Dx11DemoBase组成代码
[cpp] viewplaincopyprint?
1.#include"Dx11DemoBase.h"
2.
3.Dx11DemoBase:
:
Dx11DemoBase( ) :
driverType_( D3D_DRIVER_TYPE_NULL),
4.featureLevel_( D3D_FEATURE_LEVEL_11_0 ), d3dDevice_( 0 ),d3dContext_( 0 ),
5.swapChain_( 0 ), backBufferTarget_( 0 )
6.{
7.
8.}
9.
10.void Dx11DemoBase:
:
UnloadContent( )
11.{
12.//可以在此处进行重载,加入代码实现相关功能
13.
14.
15.
16.void Dx11DemoBase:
:
Shutdown( )
17.{
18. UnloadContent( );
19. if( backBufferTarget_ ) backBufferTarget_->Release( );
20. if( swapChain_ ) swapChain_->Release( );
21. if( d3dContext_ ) d3dContext_->Release( );
22. if( d3dDevice_ ) d3dDevice_->Release( );
23. d3dDevice_ = 0;
24. d3dContext_ = 0;
25. swapChain_ = 0;
26. backBufferTarget_ = 0;
27.}
Dx11DemoBase类中的最后一个函数是Initialize函数。
Initialize函数执行我们在这章中讲到的D3D初始化工作。
这个函数开始声明我们的硬件,WARP或者软件的驱动类型,和我们的D3D11.0,10.1或者10.0的特征等级。
代码的设定即尝试在D3D11中创建一个硬件设备。
如果创建失败,我们会尝试其他的驱动类型和特征等级直到我们找到一个合适的类型。
这也意味着如果我们采用D3D10硬件我们可以也可以在硬件中运行这个demo,因为我们可以选择10.1或者10.0的特征等级。
下一步便是创建交换链的描述,以及使用这些信息来试着找到支持的设备类型和特征等级。
如果成功的搜索到了我们需要的这些信息。
接下来就是行云流水地创建渲染目标,创建视口,以及调用LoadContent方法加载特定的内容了。
需要指出的是,LoadContent方法最好留着最后进行调用,以免出现不必要的错误。
下面便是DirectX11初始化的全过程:
代码段三 Dx11DemoBase类的初始化函数
[cpp] viewplaincopyprint?
1.bool Dx11DemoBase:
:
Initialize( HINSTANCE hInstance, HWND hwnd )
2.{
3. hInstance_ =hInstance;
4. hwnd_ = hwnd;
5.
6. RECT dimensions;
7. GetClientRect( hwnd,&dimensions );
8.
9. unsigned int width =dimensions.right - dimensions.left;
10. unsigned int height =dimensions.bottom - dimensions.top;
11.
12. D3D_DRIVER_TYPEdriverTypes[] =
13. {
14. D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,
15. D3D_DRIVER_TYPE_REFERENCE, D3D_DRIVER_TYPE_SOFTWARE
16. };
17.
18. unsigned inttotalDriverTypes = ARRAYSIZE( driverTypes );
19.
20. D3D_FEATURE_LEVELfeatureLevels[] =
21. {
22. D3D_FEATURE_LEVEL_11_0,
23. D3D_FEATURE_LEVEL_10_1,
24. D3D_FEATURE_LEVEL_10_0
25. };
26.
27. unsigned inttotalFeatureLevels = ARRAYSIZE( featureLevels );
28.
29. DXGI_SWAP_CHAIN_DESCswapChainDesc;
30. ZeroMemory(&swapChainDesc, sizeof( swapChainDesc ) );
31. swapChainDesc.BufferCount = 1;
32. swapChainDesc.BufferDesc.Width = width;
33. swapChainDesc.BufferDesc.Height = height;
34. swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
35. swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
36. swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
37. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
38. swapChainDesc.OutputWindow = hwnd;
39. swapChainDesc.Windowed= true;
40. swapChainDesc.SampleDesc.Count = 1;
41. swapChainDesc.SampleDesc.Quality= 0;
42.
43. unsigned intcreationFlags = 0;
44.
45.#ifdef _DEBUG
46. creationFlags |=D3D11_CREATE_DEVICE_DEBUG;
47.#endif
48.
49. HRESULT result;
50. unsigned int driver =0;
51.
52. for( driver = 0;driver < totalDriverTypes; ++driver )
53. {
54. result =D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver], 0, creationFlags,
55. featureLevels, totalFeatureLevels,
56. D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
57. &d3dDevice_, &featureLevel_, &d3dContext_ );
58.
59. if( SUCCEEDED(result ) )
60. {
61. driverType_ =driverTypes[driver];
62. break;
63. }
64. }
65.
66. if( FAILED( result ) )
67. {
68. DXTRACE_MSG("创建 Direct3D 设备失败!
" );
69. return false;
70. }
71.
72. ID3D11Texture2D*backBufferTexture;
73.
74. result =swapChain_->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID*)&backBufferTexture );
75.
76. if( FAILED( result ) )
77. {
78. DXTRACE_MSG("获取交换链后台缓存失败!
" );
79. return false;
80. }
81.
82. result =d3dDevice_->CreateRenderTargetView( backBufferTexture, 0,&backBufferTarget_ );
83.
84. if( backBufferTexture)
85. backBufferTexture->Release( );
86.
87. if( FAILED( result ) )
88. {
89. DXTRACE_MSG("创建渲染目标视图失败!
" );
90. return false;
91. }
92.
93. d3dContext_->OMSetRenderTargets( 1, &backBufferTarget_, 0 );
94.
95. D3D11_VIEWPORTviewport;
96. viewport.Width =static_cast
97. viewport.Height =static_cast
98. viewport.MinDepth =0.0f;
99. viewport.MaxDepth =1.0f;
100. viewport.TopLeftX =0.0f;
101. viewport.TopLeftY =0.0f;
102.
103. d3dContext_->RSSetViewports( 1, &viewport );
104.
105. return LoadContent( );
106.}
107.
108.
109.bool Dx11DemoBase:
:
LoadContent( )
110.{
111. //可以进行重载来丰富相关功能
112. return true;
113.}
114.
115.
116.void Dx11DemoBase:
:
UnloadContent( )
117.{
118. //可以进行重载来丰富相关功能
119.}
120.
121.
122.void Dx11DemoBase:
:
Shutdown( )
123.{
124. UnloadContent( );
125.
126. if( backBufferTarget_) backBufferTarget_->Release( );
127. if( swapChain_ )swapChain_->Release( );
128. if( d3dContext_ )d3dContext_->Release( );
129. if( d3dDevice_ )d3dDevice_->Release( );
130.
131. backBufferTarget_ = 0;
132. swapChain_ = 0;
133. d3dContext_ = 0;
134. d3dDevice_ = 0;
135.}
三、BlankDx11Demo类的设计
万事具备,只欠东风。
下面我们便从上面写的Dx11DemoBase类里派生出一个叫BlankDx11Demo的类。
以下就是 BlankDx11Demo类头文件的代码:
代码段四 BlankDx11Demo类的头文件
[cpp] viewplaincopyprint?
1.#ifndef _BLANK_DEMO_H_
2.#define _BLANK_DEMO_H_
3.#include"Dx11DemoBase.h"
4.
5.class BlankDx11Demo :
public Dx11DemoBase
6.{
7.public:
8. BlankDx11Demo( );
9. virtual ~BlankDx11Demo( );
10. bool LoadContent( );
11. void UnloadContent( );
12. void Update( float dt );
13. void Render( );
14.};
15.#endif
这段代码中可以看到。
叫做Update的函数中取了一个叫做dt的变量,后面将更详细地剖析这个变量,目前我们按这样理解就好了:
在游戏程序中我们经常需要进行实时的游戏逻辑更新,而dt用于代表最后一帧的时间到当前时间的时间差,这个时间差记录我们用dt记录了下来,便于我们的基于时间的更新操作。
由于这个只是一个骨架式的空DirectXDemo,以尽量精简易懂作为此Demo的宗旨,以便于大家更容易地理解一个DirectX11Demo的筋骨脉络,所以在这里只是只进行了一个清屏的操作,且所有的函数重载都是空的。
Render函数中我们也就调用了两个Direct3D的函数:
ClearRenderTargetView函数用于清除屏幕上指定的颜色,Present函数用于显示新渲染的场景。
代码段五BlankDx11Demo类的源文件
[cpp] viewplaincopyprint?
1.#include"BlankDx11Demo.h"
2.
3.BlankDx11Demo:
:
BlankDx11Demo( )
4.{
5.}
6.
7.BlankDx11Demo:
:
~BlankDx11Demo( )
8.{
9.}
10.
11.bool BlankDx11Demo:
:
LoadContent( )
12.{
13. return true;
14.}
15.
16.void BlankDx11Demo:
:
UnloadContent( )
17.{
18.}
19.
20.void BlankDx11Demo:
:
Update( float dt )
21.{
22.}
23.
24.void BlankDx11Demo:
:
Render( )
25.{
26.if( d3dContext_ == 0 )
27.return;
28.float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
29.d3dContext_->ClearRenderTargetView( backBufferTarget_,clearColor );
30.swapChain_->Present( 0, 0 );
31.}
四、 赋予程序生命——wWinMain函数的书写
之前我
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 游戏 开发 随记 十八