在《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(); // 等待此幀的命令執行完畢。
}
本書爲英文原版的中文翻本,不得不說書中的翻譯十分詳細,而且也有及其詳細的註釋(其中包含有作者自己的心得體會在內),建議對遊戲引擎構建有興趣的人購買學習。