这系列是额外自己写代码的笔记,主要是考虑一开始可能难以下手,所以或许只会写这一篇。
龙书有自己的示例代码,地址是https://github.com/d3dcoder/d3d12book。我大部分也会参考着示例代码写一份DX12项目。
第一至第三章
我们先只做一个工作:新建一个d3dUtil.h头文件,包含需要的数学库,作为我们的工具类。
#pragma once
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
第四章
我们新建一个d3dApp.h:
#pragma once
// Link necessary d3d12 libraries.
#pragma comment(lib,"d3dcompiler.lib")
#pragma comment(lib, "D3D12.lib")
#pragma comment(lib, "dxgi.lib")
#include "d3dUtil.h"
连接上必要的DirecrtX库,对于创建演示应用程序,这将省去打开项目属性页和在链接器设置下指定附加依赖项的额外步骤(当然我们自己也可以在附加依赖项里添加)。
以及我们还要在d3dUtil.h添加几个库:
#pragma once
// COM智能指针
#include <wrl.h>
// DXGI
#include <dxgi1_4.h>
// Direct3D 12
#include <d3d12.h>
// DirectX数学库
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <vector>
#include <string>
代码写完成后运行时会报一个错误:
Callback”: 模板 从属名称的使用必须以“模板”为前缀
这是一个伪错误,是由于WRL是特定于 Microsoft 的编译器扩展,跨平台跨编译器编译时就不会通过。如下,符合模式选否就可以避免这个报错。
再加上异常处理的代码:
inline std::wstring AnsiToWString(const std::string& str)
{
WCHAR buffer[512];
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);
return std::wstring(buffer);
}
class DxException
{
public:
DxException() = default;
DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, 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
新建d3dUtil.cpp,写上上面声明的两个函数:
#include "d3dUtil.h"
#include <comdef.h>
using Microsoft::WRL::ComPtr;
DxException::DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, int lineNumber) :
ErrorCode(hr),
FunctionName(functionName),
Filename(filename),
LineNumber(lineNumber)
{
}
std::wstring DxException::ToString()const
{
// Get the string description of the error code.
_com_error err(ErrorCode);
std::wstring msg = err.ErrorMessage();
return FunctionName + L" failed in " + Filename + L"; line " + std::to_wstring(LineNumber) + L"; error: " + msg;
}
在d3dApp.h新建一个D3DApp的类:
class D3DApp
{
public:
D3DApp(HINSTANCE hInstance);
~D3DApp();
private:
static D3DApp* mApp; // singleton
};
新建一个d3dApp.cpp,准备写具体的方法:
#include "d3dApp.h"
using Microsoft::WRL::ComPtr;
构造和析构函数
D3DApp::D3DApp(HINSTANCE hInstance)
: mhAppInst(hInstance)
{
// Only one D3DApp can be constructed.
assert(mApp == nullptr);
mApp = this;
}
D3DApp::~D3DApp()
{
// todo
}
在构造函数中我们把新建的D3DApp赋值给mApp,作为D3DApp的一个单例,如果在第一个D3DApp实例没有被释放的情况下有第二个D3DApp创建则会报错并终止程序防止引发错误。相似的我们可以用这种方式避免创建和赋值第二个D3DApp:
D3DApp(const D3DApp& rhs) = delete;
D3DApp& operator=(const D3DApp& rh