Driect3D初始化演示(第四章內容)


初始化Direct3D演示(第四章內容)

初始化Driect3D類:

#include "Common\d3dApp.h"
#include <DirectXColors.h>

using namespace DirectX;

class InitDirect3DApp : public D3DApp
{
public:
	InitDirect3DApp(HINSTANCE hInstance);
	~InitDirect3DApp();

	virtual bool Initialize()override;

private:
	virtual void OnResize()override;
	virtual void Update(const GameTimer& gt)override;
	virtual void Draw(const GameTimer& gt)override;
};


InitDirect3DApp::InitDirect3DApp(HINSTANCE hInscance) :D3DApp(hInscance)
{

}

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());
	//重置命令列表
	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
	//對資源的狀態進行轉變,將資源從呈現狀態轉變到渲染目標狀態
	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* cmdsList[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdsList), cmdsList);
	//交換前后台緩沖區
	ThrowIfFailed(mSwapChain->Present(0, 0));;
	mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

	//等待此幀的命令執行完畢
	FlushCommandQueue();

}

主函數:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
	//為調試版本開啟運行時內存檢測,方便監督內存泄漏的情況
#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;
	}
}

運行結果

接下來我們將介紹一些在前面沒有提到的方法:

1、ClearRenderTargetView():將指定的渲染目標清理為給定的顏色

2、ClearDepthStencilView():清理指定的深度/模板緩沖區

3、OMSetRenderTargets():設置我們希望在渲染流水線上使用的渲染目標和深度/模板緩沖區

調試Direct3D應用程序

大多數的Direct3D函數會返回HRESULT錯誤碼,我們的示例程序則采用簡單的錯誤處理機制檢測返回的HRESULT值,如果檢測失敗。則拋出異常,顯示調用出錯的錯誤碼,函數名,文件名以及發生錯誤的行號,這些操作都由d3dUtil.h中的代碼實現:

class DxException
{
public:
	DxException() = default;
	DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filName, int lineNumber);

	std::wstring ToString()const;

	HRESULT ErrorCode = S_OK;
	std::wstring FunctionName;
	std::wstring FileName;
	int LineNumber = -1;
};


#ifndef ThrowIfFailed
#define ThrowIfFailed(x)                                              \
{                                                                     \
    HRESULT hr__ = (x);                                               \
    std::wstring wfn = AnsiToWString(__FILE__);                       \
    if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \
}
#endif

由上面的代碼可以看出來,ThrowifFailed是一個宏而不是一個函數,如果ThrowifFailed是一個函數,那么__FILE__和__LINE__將會定位到ThrowifFailed函數所在的文件和行,而不是出錯函數的文件和行。

L#x會將ThrowifFailed的參數轉換為Unicode字符串,這樣一來,我們就可以將函數調用的錯誤信息輸出到消息框中。

第四章小結

  1. Direct3D是一種介於程序員和硬件之間的橋梁,通過這個橋梁,程序員可以通過調用Direct3D函數來實現把資源視圖綁定到硬件渲染流水線中,配置渲染流水線的輸出以及繪制3D幾何體等操作
  2. 組件對象模型(COM)是一種可以使DirectX不依賴任何特定語言且向后兼容的技術
  3. 1D、2D、3D紋理類似於有數據元素構成的1D、2D、3D數組,紋理元素的格式必定是DXGI_FORAMT枚舉類型中的其中一種,紋理除了可以存儲圖像數據之外,還可以存儲想深度信息等其他類型的數據
  4. 前台緩沖區和后台緩沖區構成了交換鏈,交換鏈在代碼中可以通過IDXGISwapChain接口表示,使用兩個緩沖區的情況稱之為雙緩沖,交換鏈的存在可以避免出現動畫中出現閃爍的問題(前台緩沖區和后台緩沖區互換的操作稱之為呈現)
  5. 深度緩沖是一種用於確定物體在場景中離攝像機最近點的技術,通過深度緩沖,我們可以不用考慮物體在場景中繪制的先后順序
  6. 在Driect3D中,資源不可以直接和渲染流水線相互綁定,因此我們需要為繪制調用時所引用的資源指定描述符,描述符可以視為GPU識別以及描述資源的一種輕量級結構體,我們還可以為一種資源創建不同的描述符,這樣我們就可以讓一種資源具有多種用途。應用程序可以通過創建描述符堆來存儲描述符。
  7. ID3DDeviec是Direct3D最重要的接口,我們可以把它看作是圖形硬件設備的軟件控制器,我們可以通過ID3DDevice來創建GPU資源以及其他一些用於控制圖形硬件設備的特定接口
  8. 每一個GPU都有一個命令隊列,CPU可以通過Direct3D API用命令列表來向該隊列提交命令,這些命令將指揮GPU進行各種操作,在命令沒有到達隊列首部之前,該命令是不會被執行的。
  9. GPU是系統中和CPU一起並行工作的第二種處理器,我們需要對CPU和GPU進行同步
  10. 性能計數器是一種高精度的計時器,它是測量微小時間差的一種有效工具,性能計數器使用的時間單位是計數,QueryPerformanceFrequency函數輸出的是性能計數器每秒的計數,可以用它將計數單位轉換為秒,QueryPerformanceCounter函數輸出的是當前的時間值(以計數為單位)
  11. 通過統計時間段t內處理的幀數可以計算出每秒的平均幀數(FPS),不過為了更直觀的對程序的性能進行考量,我們一般使用“處理一幀所花費的時間”這個統計信息。以秒為單位的每幀平均處理時間可以用幀率的倒數來進行計算,即:1/FPS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM