DirectX12 事始め レンダーターゲットの生成

今回は、レンダーターゲットの作成を行っていこうと思います。
レンダーターゲットとは、レンダリング対象バッファを指定する役割を持つものです。
これのおかげで、きちんと描画ができるようになります。

それでは作っていく前に、今後出てくる深度ステンシルや、定数バッファが
同じような処理をするのでこれらの基底クラスを先に作ります。

```c++:Descriptor.h
#include “Obj.h”
class Device;
class List;
class Descriptor :
   public Obj
{
public:
   // コンストラクタ
   Descriptor();
   // デストラクタ
   virtual ~Descriptor();

   // ヒープの取得
   ID3D12Descriptor* GetHeap(void) const {
      return heap;
   }
protected:
   // ヒープの生成
   HRESULT CreateHeap(const D3D12_DESCRIPTOR_HEAP_TYPE& type, const D3D12_DESCRIPTOR_HEAP_FLAGS& flag, UINT num = 1);

   // デバイス
   Device* dev;
   // コマンドリスト
   List* list;
   // ヒープ
   ID3D12DescriptorHeap* heap;
   // ヒープサイズ
   UINT size;
};
```

```c++:Descriptor.cpp
#include “Descriptor”
#include “Device”

// コンストラクタ
Descriptor::Descriptor() :
   heap(nullptr), size(0)
{
}
// デストラクタ
Descriptor::~Descriptor()
{
}
// ヒープの生成
HRESULT Descriptor::CreateHeap(const D3D12_DESCRIPTOR_HEAP_TYPE& type, const D3D12_DESCRIPTOR_HEAP_FLAGS& flag, UINT num)
{
   //ヒープ設定用構造体
   D3D12_DESCRIPTOR_HEAP_DESC desc = {};
   desc.Flags          = flag;
   desc.NodeMask       = 0;
   desc.NumDescriptors = num;
   desc.Type           = type;
   //ヒープの生成
   result = dev->Get()->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&heap));
   //ヒープサイズの取得
   size = dev->Get()->GetDescriptorHandleIncrementSize(type);
   return result;
}
```

これが、レンダーターゲットや、深度ステンシル、定数バッファの`基底クラス`になります。
それではレンダーターゲット作っています。

```c++:Render.h
#include “Descriptor.h”
#include <vector>
class Swap;
class Render :
   public Descriptor
{
   // コンストラクタ
   Render(Device* dev, List* list, Swap* swap);
   // デストラクタ
   ~Render();
   // レンダーターゲットのセット
   void SetRender(ID3D12DescriptorHeap* depth);
   // リソースの取得
   ID3D12Resource* GetResource(UINT index) const {
      return respurce[index];
   }
private:
   // リソースの生成
   HRESULT CreateResource(void);

   // スワップチェイン
   Swap* swap;
   // リソース
   std::vector<ID3D12Resource*>resource;
};
```

```c++:Render.cpp
#include “Render.h”
#include “Device.h”
#include “List.h”
#include “Swap.h”

//クリアカラー
const FLOAT color[] = {
   1.0f,
   0.0f,
   0.0f,
   0.0f
};

// コンストラクタ
Render::Render(Device* dev, List* list, Swap* swap) :
   dev(dev), list(list), swap(swap)
{
   resource.clear();

   CreateResource();
}
// デストラクタ
Render::~Render()
{
   for(auto& i : resource)
   {
      Release(i);
   }
   Release(heap);
   delete swap;
   delete list;
   delete dev;
}
// リソースの生成
HRESULT Render::CreateResource(void)
{
   result = CreateHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, Swap->GetBack());
   //配列のメモリ確保
   resource.resize(swap->GetBack());
   //レンダーターゲット設定用構造体
   D3D12_RENDER_TARGET_VIEW_DESC desc = {};
   desc.Format               = DXGI_FORMAT_R8G8B8A8_UNORM;
   desc.ViewDimension        = D3D12_RTV_DIMENSION_TEXTURE2D;
   desc.Texture2D.MipSlice   = 0;
   desc.Texture2D.PlaneSlice = 0;

   //先頭ハンドル
   D3D12_CPU_DESCRIPTOR_HANDLE handle = heap->GetCPUDescriptorHandleForHeapStart();
   for(UINT i = 0; i < render.size(); ++i)
   {
      result = swap->Get()->GetBuffer(i, IID_PPV_ARGS(&resource[i]));
      //レンダーターゲットの生成
      dev->Get()->CreateRenderTargetView(resource[i], &desc, handle);
      //ハンドル位置の更新
      handle.ptr += size;
   }
}
// レンダーターゲットのセット
void Render::SetRender(ID3D12DescriptorHeap* depth)
{
   D3D12_CPU_DESCRIPTOR_HANDLE handle = heap->GetCPUDescriptorHandleForHeapStart();
   handle.ptr += size * swap->Get()->GetCurrentBackBufferIndex();
   //レンダーターゲットのセット
   list->GetList()->OMSetRenderTargets(1, &handle, false, &depth->GetCPUDescriptorHandleForHeapStart());
   //レンダーターゲットのクリア
   list->GetList()->ClearRenderTargetView(handle, color, 0, nullptr);
}
```

これでレンダーターゲットの生成は終了です。
なかなか多いですね。
レンダーターゲットのリソースはスワップチェインのバックバッファの数分作っておく必要があるので注意です。
次回は深度ステンシルをやっていこうと思います。