一个引擎(2)

一个引擎

上一篇已经成功创建一个窗口,于是我们的工作重心该转回D3D了。

运行状态

假如我们把D3D有关的内容放到一个类D3DApp中,那么为了完成渲染任务,它需要有以下几个阶段:

class D3DApp
{
public:
    void OnInit()
    {
        // 对象初始化时的代码。
    }

    void OnUpdate()
    {
        // 每一帧更新时在CPU上执行的代码,一般是游戏逻辑。
    }

    void OnRender()
    {
        // 每一帧更新时在GPU上执行的代码,与D3D相关的代码大部分放在这里。
    }

    void OnRelease()
    {
        // 对象在释放时执行的代码
    }
}
D3DApp* pD3DApp = new D3DApp();
pD3DApp->OnInit();
while (!exit)
{
    pD3DApp->OnUpdate();
    pD3DApp->OnRender();
}
pD3DApp->OnRelease();

大致就是这么个逻辑,因此我定义了一个抽象基类D3D12AppBase来描述这些行为。

D3D12AppBase

新建头文件DX.h,首先要解决一些头文件引用和静态库的问题。

#include<d3d12.h>
#include"d3dx12.h"
#include<D3Dcompiler.h>
#include<DirectXMath.h>
#include<dxgi1_4.h>
#include<pix.h>
#include<dcomp.h>

#pragma comment(lib, "dcomp.lib")
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
  • d3d12.h:主要的头文件,包括与DX有关的最基本的接口、类型等。
  • d3dx12.h:微软给出的DX辅助用头文件,主要是对DX一些接口、函数和类型的封装。从某一版本开始不再将D3DX作为DX的一部分,需要到GitHub上自行下载
  • D3Dcompiler.h:编译Shader的相关类库。
  • DirectXMath.h:DX程序必备的数学库,到DX12时已经兼备XNA和原数学库的优点。其中大部分函数使用SSE指令集实现,效率很高。
  • dxgi1_4.h:有多个版本,目前最新的为1.6,1.6版本针对Windows 10秋季创意者更新,有许多老版本Win10不兼容的特性,因此暂时为了兼容使用1.4。DXGI(DirectX Graphics Infrastructure)是沟通硬件和操作系统的图形基础架构。
  • pix.h、dcomp.h:由于DX支持Com,所以使用ComPtr对其进行管理。这里不再过多介绍Com。

然后需要链接一些静态库,这些静态库也可以在“项目->属性->链接器->附加依赖项”中添加这些静态库。

另外尽量不要在头文件中using namespace,否则在所有包含头文件的CPP文件中都会using namespace,会带来一些意想不到的重定义、命名冲突等诡异的错误。

class D3D12AppBase
{
    std::wstring assetsPath;
    std::wstring title;
protected:
    bool isUseWarpDevice;
    float aspectRatio;
    HWND hwnd;
    int width;
    int height;
    inline std::wstring GetAssetFullPath(LPCWSTR assetName)
    {
        return assetsPath + std::wstring(assetName);
    }
    void GetHardwareAdapter(_In_ IDXGIFactory2* pFactory, Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter);
public:
    D3D12AppBase(const HWND _hwnd, const uint32_t _width, const uint32_t height);
    D3D12AppBase(const HWND _hwnd, const uint32_t _width, const uint32_t height, const std::wstring& _title);
    virtual ~D3D12AppBase() = default;
    virtual void OnInit() = 0;
    virtual void OnRelease() = 0;
    virtual void OnUpdate() = 0;
    virtual void OnRender() = 0;
    virtual void OnKeyDown(uint8_t key) = 0;
    virtual void OnKeyUp(uint8_t key) = 0;
    void SetHwnd(const HWND _hwnd);
    void ParseCommandLineArgs(_In_reads_(argc) WCHAR* argv[], int argc);
    void SetWindowTitleText(LPCWSTR text);
};
D3D12AppBase::D3D12AppBase(const HWND _hwnd, const UINT _width, const UINT _height) : hwnd(_hwnd), width(_width), height(_height), isUseWarpDevice(false)
{
    WCHAR _assetsPath[512];
    GetAssetsPath(_assetsPath, _countof(_assetsPath));
    assetsPath = _assetsPath;
    aspectRatio = static_cast<float>(width) / static_cast<float>(height);
}

D3D12AppBase::D3D12AppBase(const HWND _hwnd, const UINT _width, const UINT _height, const wstring& _title) : hwnd(_hwnd), width(_width), height(_height), isUseWarpDevice(false), title(_title)
{
    WCHAR _assetsPath[512];
    GetAssetsPath(_assetsPath, _countof(_assetsPath));
    assetsPath = _assetsPath;
    aspectRatio = static_cast<float>(width) / static_cast<float>(height);
}

void D3D12AppBase::GetHardwareAdapter(_In_ IDXGIFactory2* pFactory, _Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter)
{
    ComPtr<IDXGIAdapter1> adapter;
    *ppAdapter = nullptr;

    for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter); ++adapterIndex)
    {
        // 枚举显示适配器
        DXGI_ADAPTER_DESC1 desc;
        adapter->GetDesc1(&desc);

        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
        {
            // 如果有需要,可以选择Warp适配器,既Microsoft基本显示适配器。
            continue;
        }

        if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
        {
            // 否则从枚举到的第一个设备上创建。这里的设备顺序和系统设置有关,比如在笔记本电脑上常见配置为Intel核显+Nvidia独显,在NVidia控制面板里可以选择程序默认显卡,如果是“集成式”此处第一个被枚举的设备是核显。
            break;
        }
    }

    *ppAdapter = adapter.Detach();
}

void D3D12AppBase::ParseCommandLineArgs(_In_reads_(argc) WCHAR* argv[], int argc)
{
    for (int i = 1; i < argc; ++i)
    {
        if (_wcsnicmp(argv[i], L"-warp", wcslen(argv[i])) == 0 || _wcsnicmp(argv[i], L"/warp", wcslen(argv[i])) == 0)
        {
            isUseWarpDevice = true;
        }
    }
}

void D3D12AppBase::SetHwnd(const HWND _hwnd)
{
    hwnd = _hwnd;
}

void D3D12AppBase::SetWindowTitleText(LPCWSTR text)
{
    wstring windowText = title + L": " + text;
    SetWindowText(hwnd, windowText.c_str());
}

如上,一个基本的D3D12应用架构就出来了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值