DirectX12 3Dゲーム開発や戦闘章の内容(下)

Direct3Dの初期化(下部)

学習目標

  1. ハードウェアの役割に関してDirect3Dの3Dプログラミングを学びます
  2. COMコンポーネントオブジェクトモデルは、Direct3Dのの役割を理解します
  3. このような記憶2D画像、ページフリッピング、デプスバッファ、CPUとGPUとマルチサンプリングとの間の相互作用などの図像の基本概念を習得
  4. 高精度のタイマーの値は、パフォーマンスカウンタ機能を順次読み込み学びます
  5. 理解のDirect3Dの初期化プロセス
  6. その後のデモ・プログラムでは、本の全体の構造に精通したアプリケーションフレームワークは、多くの場合、アプリケーションフレームワークの全体的な構造を見ることができます

4.3のDirect3Dを初期化します

Direct3Dのは、次のステップに分割されるように初期化されます

  1. D3D12CreateDevice機能をID3D12Deviceインタフェースのインスタンスを作成します
  2. ID3D12Fenceオブジェクトおよび照会の記述のサイズを作成します
  3. 品質4X MSAAのレベルを検出するために、ユーザ機器のサポート
  4. コマンドキュー、コマンド分配器のリスト、メインコマンドリストを作成するために
  5. 説明とスワップチェーンを作成します
  6. アプリケーションを作成すると、記述子ヒープを必要とします
  7. ターゲットビューをレンダリングするバックバッファのサイズを変更して、作成
  8. 深さ/ステンシルバッファおよび関連する深さ/ステンシルバッファのビューを作成します
  9. 提供されるビューポート(ビューポート)、およびクロップ矩形(シザー矩形)

4.3.1機器

Direct3Dの初期化をするには、まずDirect3D12機器を作成する必要があります。ディスプレイアダプタに対応Direct3D12装置は、一般に、ディスプレイアダプタの3Dグラフィックスハードウェア(ビデオなど)の一種であるが、システム環境をサポートすることができる装置の機能が検出され、機能をシミュレートするために、ディスプレイアダプタのハードウェア3Dグラフィックスソフトウェアであってもよく、そして他のすべてのDirect3Dインターフェイスオブジェクト(例えば、リソース、コマンドのリスト、ビュー(記述子)、等)を作成するために使用することができます。私たちは、機能でDirect3D12デバイスを作成することができます。

//@param:指定在创建设备的时候所用的显示适配器,如果把该指针设为空,则默认使用主显示适配器
//@param:应用程序需要硬件所支持的最低功能级别
//@parma:该ID3DDevice接口的COM ID
//@parma:返回所创建的Direct3D12设备
HRESULT WINAPI mD3D12CreateDevice(
    IUnknown* pAdapter,
    D3D_FEATURE_LEVEL MinimumFeatureLevel,
    REFIID riid,
    void** ppDevice
);

4.3.2フェンスを作成し、記述のサイズを取得

機器を作成した後、私たちはフェンス同期CPUとGPUを作成することができるだろう。仕事は記述子を使用する必要がある場合にも、我々はまた、その大きさを理解する必要があります。しかし、異なるGPUサイズの記述子が異なっているので、我々は必要なときに、直接参照用フェンスに関連する情報の作成で仕方、その後、記述子キャッシュサイズアップを照会する必要があります。

ThrowIfFailed(md3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)));
//渲染目标视图(描述符)大小
mRtvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
//深度/模板视图(描述符)大小
mDsvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
//常量缓冲区/着色器资源/无序访问视图(描述符)大小
mCbvSrvUavDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

4X MSAA品質レベル4.3.3の検出をサポート

Direct3D11ハードウェアをサポートしていた者は、複数のサンプリング技術を有効にサポートすることができます。だから我々は、しかし、品質レベルの検出が不可欠であり、これを検出することはできません。私たちは、検出するために、以下の方法を使用することができます。

D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
msQualityLevels.Format = mBackBufferFormat;
msQualityLevels.SampleCount = 4;
msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
msQualityLevels.NumQualityLevels = 0;
ThrowIfFailed(md3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msQualityLevels,
    sizeof(msQualityLevels)));

コマンドキューとコマンドリストの作成4.3.4

前節ショーでは、ID3D12CommandQueueインタフェースはコマンドキューを表し、ID3D12CommandAllocatorインタフェースは、コマンド分配を表し、我々は、オブジェクトのこれらのタイプを作成するプロセスを示すであろう下に、ID3D12CommandListインタフェースは、それぞれ、コマンドのリストを表します。

ComPtr<ID3D12CommandQueue> mCommandQueue;
ComPtr<ID3D12CommandAllocator> mDirectCmdListAlloc;
ComPtr<ID3D12CommandList> mCommandList;

void D3DApp::CreateCommandObjects()
{
    //创建命令队列对象
    D3D12_COMMAND_QUEUE_DESC queueDesc = {};
    queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    ThrowIfFailed(md3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
    //创建命令分配器
    ThrowIfFailed(md3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, 
        IID_PPV_ARGS(mDirectCmdListAlloc.GetAddressOf())));
    //创建命令列表
    ThrowIfFailed(md3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mDirectCmdListAlloc.Get(),
        nullptr, IID_PPV_ARGS(mCommandList.GetAddressOf())));

    //首先要把命令列表关闭,因为第一次使用命令列表时我们要把命令列表重置,重置之前必须确保命令列表
    //已经关闭
    mCommandList->Close();
    }

4.3.5説明およびスワップ・チェーンを作成します

あなたはスワップチェーンを作成する前に、我々は最初のDXGI_SWAP_CHAIN_DESC構造のインスタンスに必要事項を記入しなければならない、作成されるスワップチェーンの特性を記述するためにそれを使用。次のようにこの構造体が定義されています。

typedef struct DXGI_SWAP_CHAIN_DESC {
    DXGI_MODE_DESC BufferDesc;
    DXGI_SAMPLE_DESC SampleDesc;
    DXGI_USAGE BufferUsage;
    UINT BufferCount;
    HWND OutputWindow;
    BOOL Windowed;
    DXGI_SWAP_EFFECT SwapEffect;
    UINT Flags;
}DXGI_SWAP_CHAIN_DESC;

DXGI_MODE_DESCは別の構造であることを特徴とする請求次のように、構造が定義されます。

typedef struct DXGI_MODE_DESC {
    UINT Width;
    UINT Height;
    DXGI_RATIONAL refreshRate;
    DXGI_FORMAT Format;
    DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
    DXGI_MODE_SCALING scaling;
}DXGI_MODE_DESC;

次のコードは、どのように簡単に書籍のプレゼンテーションの枠組みの中でスワップチェーンを作成する方法を紹介します。

void D3DApp::CreateSwapChain()
{

    //释放之前创建的交换链,然后进行重建
    mSwapChain.Reset();

    DXGI_SWAP_CHAIN_DESC sd;
    sd.BufferDesc.Width = mClientWidth;
    sd.BufferDesc.Height = mClientHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = mBackBufferFormat;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    sd.SampleDesc.Count = m4xMsaaState ? 4 : 1;
    sd.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = SwapChainBufferCount;
    sd.OutputWindow = mhMainWnd;
    sd.Windowed = true;
    sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    //注意,交换链需要通过命令队列才能刷新
    ThrowIfFailed(mdxgiFactory->CreateSwapChain(mCommandQueue.Get(),
        &sd, mSwapChain.GetAddressOf()));

}

4.3.6ヒープ記述子を作成します

プロセスでは、我々はDirect12でプログラムを保存する必要がありますヒープ記述子記述子(ビュー)を作成する必要があり、ID3D12DescriptorHeap記述子スタックは、インターフェイスを表し、ID3D12Device :: CreateDescriptorHeap方法で、次のようにヒープ記述子を作成しますデモコード、我々は2つの記述子スタック、ターゲットビュー(ターゲット・ビューをレンダリング)、深さ/ステンシルビュー(深さ/ステンシルビュー)を保存するためにも使用をレンダリングSwapChainBufferCountストレージのための1つを作成します。

ComPtr<ID3D12DescriptorHeap> mRtvHeap;
ComPtr<ID3D12DescriptorHeap> mDsvHeap;

void D3DApp::CreateRtvAndDsvDescriptorHeaps()
{
    D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc;
    rtvHeapDesc.NumDescriptors = SwapChainBufferCount;
    rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    rtvHeapDesc.NodeMask = 0;
    ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(mRtvHeap.GetAddressOf())));

    D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc;
    dsvHeapDesc.NumDescriptors = 1;
    dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
    dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    dsvHeapDesc.NodeMask = 0;
    ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(mDsvHeap.GetAddressOf())));
}

4.3.7ターゲット・ビューをレンダリングの作成

リソースは直接直接レンダリングパイプライン結合することができないので、私たちは、リソースのビュー(記述子)を作成し、レンダリングパイプラインにバインドする必要があります。バックバッファにレンダーターゲットビューを作成するために、我々はバッファリソース交換チェーンを取得する必要があります。

私たちは、私たちができるので、各使用後に解放され、為替IDXGISwapChain :: GetBuffer()メソッドバッファリソースチェーン、メソッドが呼び出されるたびに後、それが関連する背景バッファ参照の数を増加させる通過することができますこの機能を自動化Comptr。

次に、我々は、バックバッファの資源獲得のためのターゲット・ビューをレンダリングするために作成ID3D12Device :: CreateRenderTargetView()メソッドを使用することができます。

以下の例は、これらの2つのメソッドを呼び出すことにより、各バッファの交換のためのRTVのチェーンを作成する必要があります。

ComPtr<ID3D12Resource> mSwapChainBuffer[SwapChainBufferCount];
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(
    mRtvHeap->GetCPUDescriptorHandleForHeapStart()
);
for (UINT i = 0; i < SwapChainBufferCount; i++)
{
    //获取交换链中第i个缓冲区
    ThrowIfFailed(mSwapChain->GetBuffer(i,
        IID_PPV_ARGS(&mSwapChainBuffer[i])));

    //为此缓冲区创建一个RTV
    md3dDevice->CreateDepthStencilView(mSwapChainBuffer[i].Get(), nullptr, rtvHeapHandle);

    //偏移到描述符的下一个缓冲区
    rtvHeapHandle.Offset(1, mRtvDescriptorSize);
}

4.3.8作成深さ/ステンシルバッファとそのビュー(記述)

テクスチャデプスバッファは、最近のビジュアルオブジェクトの観測から(あなたは、だけでなく、テンプレート情報とテンプレートを使用している場合)奥行き情報を格納する資源、です。テクスチャがリソースであるため、私たちはそれを作成するためにID3D12DeveiceCreateCommittedResourceメソッドを使用して、D3D12_RESOURCE_DESC構造を充填することにより、リソースの質感を記述する必要があります。次のコードは、D3D12_RESOURCE_DESC構造を定義します。

typedef struct D3D12_RESOURCE_DESC
{
    D3D12_RESOURCE_DIMENSION Dimension;
    UINT64 Alignment;
    UINT64 Width;
    UINT Height;
    UINT16 DepthOrArraySize;
    DXGI_FORMAT Format;
    DXGI_SAMPLE_DESC SampleDesc;
    D3D12_TEXTURE_LAYOUT Layout;
    D3D12_RESOURCE_FLAGS Flags;
}D3D12_RESOURCE_DESC;

GPUリソ​​ースがID3D12Deviceは、基本的には、特定の属性を持つGPUのメモリブロックである、ヒープ(ヒープ)に格納されている:: CreateCommittedResourceは、提供するリソースとヒープを作成するために、リソースヒープにこれを提出し、我々が持っている性質に基づいて行われます。

    HRESULT ID3D12Device::CreateCommittedResource(
        const D3D12_HEAP_PROPERTIES * pHeapProperties,
        D3D12_HEAP_FLAGS HeapFlags,
        const D3D12_RESOURCE_DESC * pDesc,
        D3D12_RESOURCE_STATES InitialResourceState,
        const D3D12_CLEAR_VALUE * pOptimizedClearValue,
        REFIID riidResource,
        void ** ppvResource
        );

    typedef struct D3D12_HEAP_PROPERTIES {
        D3D12_HEAP_TYPE Type;
        D3D12_CPU_PAGE_PROPERTY CPUPageProperty;
        D3D12_MEMORY_POOL MemoryPoolPreference;
        UINT CreationNodeMask;
        UINT VisibleNodeMask;
    }D3D12_HEAP_PROPERTIES;

深さ/ステンシルバッファを使用する前に、まず、関連する深さ/ステンシルバッファのビュー(記述子)を作成しなければならない、とレンダリングパイプラインにバインドします。次のコードは、(記述子)に相当する深さ/ステンシルテクスチャリソースと深さ/ステンシルバッファのビューを作成する方法を紹介します

//创建深度/模板缓冲区视图
D3D12_RESOURCE_DESC depthStencilDesc;
//资源的维度
depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
depthStencilDesc.Alignment = 0;
//以纹素为单位来表示纹理宽度(如果是缓冲区资源,此项表示缓冲区占用的字节数)
depthStencilDesc.Width = mClientWidth;
//以纹素为单位来表示纹理高度
depthStencilDesc.Height = mClientHeight;
//以纹素为单位来表示纹理深度
depthStencilDesc.DepthOrArraySize = 1;
//mipmap层级的数量(后续讲纹理时会介绍mipmap)
depthStencilDesc.MipLevels = 1;
//DXGI_FORMAT枚举类型中的成员之一,用于指定纹素的格式
depthStencilDesc.Format = mDepthStencilFormat;
//多重采样的质量级别以及对每一个像素的采样次数
depthStencilDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
depthStencilDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
//D3D12_TEXTURE_LAYOUT枚举类型的成员之一,用来指定纹理的布局
depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
//与资源有关的杂项标志
depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

//创建一个指向一个D3D12_CLEAR_VALUE对象的指针,该指针描述了一个用于清除资源的优化值,
//选择适当的优化值可以提高清除操作的效率,如果不希望指定优化值,也可以不创建。
D3D12_CLEAR_VALUE optClear;
optClear.Format = mDepthStencilFormat;
optClear.DepthStencil.Depth = 1.0f;
optClear.DepthStencil.Stencil = 0;

//创建深度/模板缓冲区
ThrowIfFailed(md3dDevice->CreateCommittedResource(
    &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
    D3D12_HEAP_FLAG_NONE,
    &depthStencilDesc,
    D3D12_RESOURCE_STATE_COMMON,
    &optClear,
    IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf())
));

//利用此资源的格式,为整个资源的第0层mip创建描述符
md3dDevice->CreateDepthStencilView(
    mDepthStencilBuffer.Get(),
    nullptr,
    DepthStencilView()
);

//将资源从初始状态转换到深度缓冲区
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mDepthStencilBuffer.Get(),
        D3D12_RESOURCE_STATE_COMMON,D3D12_RESOURCE_STATE_DEPTH_WRITE));

4.3.9は、ビューポートを設定します

ビューポート:我々は通常、画面全体、ウィンドウまたはバックバッファにおける同等の大きさの全体の作業領域に3Dシーンを描画しますが、時には私たちは長方形のサブ領域におけるバックバッファに3Dシーンを描きたいです長方形のサブ領域にビューポートと呼ばれています

次のようにビューポート構造が定義されています。

typedef struct D3D12_VIEWPORT {
    FLOAT TopLeftX;
    FLOAT TopLeftY;
    FLOAT Width;
    FLOAT Height;
    FLOAT MinDepth;
    FLOAT MaxDepth;
};

フィルD3D12_VIEWPORT構造の後、我々はID3D12GraphicsComandList :: RSSetViewPort()メソッドにより、Direct3Dのビューポートを設定することができます。以下は、作成及び全体のバックバッファを描画する場面を設定することで、ビューポートに表示されます

D3D12_VIEWPORT vp;
vp.TopLeftX = 0.0f;
vp.TopLeftY = 0.0f;
vp.Width = static_cast<float>(mClientWidth);
vp.Height = static_cast<float>(, mClientHeight);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;

//@param:绑定的视口数量
//@param:指向视口数组的指针
mCommandList->RSSetViewports(1, &vp);

4.3.10設定クリップ矩形
我々は矩形外クロッピング矩形画素に対してバックグラウンドでバッファを定義することができるが(削除する)、バックバッファに展開されることはありません、この方法は、プログラムのパフォーマンスを最適化することができます。例えば、我々は、ゲームインタフェースUIに配置され、我々は、3D空間におけるクロップ矩形によって提供されるプログラムは、閉塞処理されたそれらのピクセルのために必要ではない行うことができます。クロップ矩形を設定し、構造のタイプによって定義される第一の充填D3D12_RECT構造は、D3D12 RECT構造で形成されているようにビューポートが設けられています。

typedef struct tagRECT {
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
}RECT;

Direct3Dの、使用ID3D12GraphicsCommandList ::クロップ矩形を設定するRSSetScisorRects方法では、次の例では、バックバッファ領域の左上隅の四分の一をカバーするクリッピング矩形を作成して設定する方法を示しています

mScissorRect = { 0,0,mClientWidth / 2,mClientHeight / 2 };
mCommandList->RSSetScissorRects(1, &mScissorRect);

おすすめ

転載: www.cnblogs.com/yaya12138/p/11546351.html