在《DirectX 12 3D 游戏开发实战》此书的第四章中详细介绍了基础的D3D的初始化操作该如何操作,具体的步骤如下:
1、创建DirectX3D设备
2、创建围栏(Fence)为了保证GPU和CPU的处理不发生不必要的冲突、扫描描述符的大小
3、检测用户设备是否支持多重采样4X MSAA
4、必须依次创建命令队列、命令列表分配器和命令列表(在完成对命令列表的输入后必须关闭对命令列表的输入操作才能将命令由分配器放入进命令队列中)
5、描述并创建交换链(backbuffer与frontbuffer之间的关系必须理清,在前台缓冲区中存的是当前的呈现在屏幕面前的像素
,而在后台缓冲区中存的是下一帧将呈现的你面前的像素信息,即提前画好,这样就不会有闪烁的现象出现——来不及画)
6、创建应用程序所需要的描述器堆(描述器堆用于存放程序中要用到的描述器/视图:RTV、DSV)
7、调整后台缓冲区的大小,并为它创建渲染目标视图
8、创建深度/模板缓冲区及与之相关的深度/模板视图
9、设置视口和裁剪矩形(显示设置)
以下是书中的源代码:其中需要借用到已经写好的d3dApp源代码以及DXColor的头文件,用颜色的头文件是因为代码中有要用到有关颜色的设置,即背景的设置。
#include"../../Common/d3dApp.h"
#include"DirectXColors.h"
using namespace DirectX;
class InitDirect3DApp:public D3DApp
{
public:
InitDirect3DApp(HINSTANCE hInstance);
~InitDirect3DApp();
virtual bool Initialize()override; // 编写初始化代码:分配资源、初始化对象、建立3D场景等
private:
virtual void OnResize()override; // 调整后台缓冲区和深度/模板缓冲区的尺寸
virtual void Update(const GameTimer& gt)override; // 在绘制每一帧时都会调用该抽象方法,可用它来更新3D应用程序(呈现动画、移动摄像机等等)
virtual void Draw(const GameTimer& gt)override; // 在绘制每一帧时都会调用该抽象方法
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, // 为调试版本开启运行时的内存检测,方便监督内存泄漏的情况
PSTR cmdLine, int showCmd)
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
try
{
InitDirect3DApp theApp(hInstance);
if (!theApp.Initialize())
return 0;
return theApp.Run();
}
catch (DxException& e)
{
MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
return 0;
}
}
InitDirect3DApp::InitDirect3DApp(HINSTANCE hInstance) // 不做操作,默任D3DApp中的加载操作
:D3DApp(hInstance)
{
}
InitDirect3DApp::~InitDirect3DApp()
{
}
bool InitDirect3DApp::Initialize() // 检测基类中场景是否加载
{
if (!D3DApp::Initialize())
return false;
return true;
}
void InitDirect3DApp::OnResize()
{
D3DApp::OnResize();
}
void InitDirect3DApp::Update(const GameTimer& gt)
{
}
void InitDirect3DApp::Draw(const GameTimer& gt)
{
ThrowIfFailed(mDirectCmdListAlloc->Reset()); // 在确保完成GPU的操作后对命令列表分配器进行重置
// 重复使用记录命令的相关内存
ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr)); // 在通过ExecuteCommandList方法将某个命令列表加入命令
// 队列后,我们便可以重置该命令列表。以此来复用命令列表及其内存
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(
CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); // 对资源的状态进行转换,将资源从呈现状态转换为渲染目标状态
mCommandList->RSSetViewports(1, &mScreenViewport); // 设置视口和裁剪矩形。它们需要随着命令列表的重置而重置
mCommandList->RSSetScissorRects(1, &mScissorRect);
mCommandList->ClearRenderTargetView(
CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr
); // 清楚后台缓冲区和深度缓冲区
mCommandList->ClearDepthStencilView(
DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH |
D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr
);
mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
// 指定将要渲染的缓冲区
mCommandList->ResourceBarrier(
1, &CD3DX12_RESOURCE_BARRIER::Transition(
CurrentBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT
)); // 在对资源状态进行转换,将资源从渲染目标转换回呈现状态
ThrowIfFailed(mCommandList->Close()); // 完成命令的记录
ID3D12CommandList* cmdLists[] = { mCommandList.Get() }; // 将待执行的命令列表加入命令队列
mCommandQueue->ExecuteCommandLists(_countof(cmdLists), cmdLists);
ThrowIfFailed(mSwapChain->Present(0, 0)); // 交换后台缓冲区和前台缓冲区
mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
FlushCommandQueue(); // 等待此帧的命令执行完毕。
}
本书为英文原版的中文翻本,不得不说书中的翻译十分详细,而且也有及其详细的注释(其中包含有作者自己的心得体会在内),建议对游戏引擎构建有兴趣的人购买学习。
文章评论