DirectX11 でオフスクリーンレンダリング備忘録

# はじめに
初めて記事を投稿します。ゆってぃと申します。
現在ゲーム系の専門学校で就職作品を作成しています。
そこで、ポストエフェクトを作成したいと考えました。

情報をあさるとまず、オフスクリーンレンダリングをする必要が在るようでした。
しかし、調べてもDirectX11のオフスクリーンレンダリングの情報が全然ありませんでした。
備忘録も兼ねて、誰かの参考になればと思います。

ただ、専門学校で教わったとかではなく完全に独学なので、
この記事を見れば確実に出来るようになるというわけではなく、
このやり方が最善であるということでもありません。

# オフスクリーンレンダリングをするメリット
- レンダリング結果をテクスチャとして使用することが出来る。
    - シェーダーでの加工が可能になる
    - ポストエフェクトを作成できる
        - ブラー
        - ブルーム
        - 被写界深度
        - など
# 処理の流れ
```mermaid
graph TD
オフスク用SRVやRTV,TextureなどをRenderer.hで作成-->
オフスク用RTV切り替え処理を新たに作成--> 
 デフォルトのRTVに切り替える処理をBeginに作成-->
	レンダリング結果を一枚の2Dポリゴンに貼り付けて描画するためにSRVをセットする関数を作成
	-->懸念点など
```
# オフスク用SRVやRTV、Textureなどを作成
## 変数用意

- ID3D11Texture2Dポインタ
- ID3D11SamplerStateポインタ　デフォルトとオフスク用
- ID3D11RenderTargetViewポインタ オフスク用
- ID3D11ShaderResourceViewポインタ オフスク用
- あとサンプラー

### Renderer.h内
```c++
//ディスプレイのバッグバッファのテクスチャ	
	inline static ComPtr<ID3D11Texture2D> _pTexture;
	// ↑はID3D11Texture2Dの普通のポインタで大丈夫です。

	// サンプラー
	inline static ID3D11SamplerState* _pDefaultSampler = nullptr;
	inline static ID3D11SamplerState* _pRenderTextureSampler;

	// もともと在るやつ
	static ID3D11RenderTargetView* m_RenderTargetView;
	static ID3D11DepthStencilView* m_DepthStencilView;

	// オフスク用 RTV
	inline static ID3D11RenderTargetView* _pRenderingTextureRTV  = nullptr	;	

	// オフスク用 SRV
	inline static ID3D11ShaderResourceView* _pRenderingTextureSRV = nullptr;
```
## 変数初期化

### Renderer.cppのInit()内
```c++

// D3D11CreateDeviceAndSwapChain()の下辺りに書く

// テクスチャ設定 オフスク用
	D3D11_TEXTURE2D_DESC rtDesc;
	memset(&rtDesc, 0, sizeof(rtDesc));
	rtDesc.Width = SCREEN_WIDTH;
	rtDesc.Height = SCREEN_HEIGHT;
	rtDesc.MipLevels = 1;
	rtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	rtDesc.SampleDesc.Count = 1;
	rtDesc.Usage = D3D11_USAGE_DEFAULT;
	rtDesc.ArraySize = 1;
	rtDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	rtDesc.CPUAccessFlags = 0;	
	
	m_Device->CreateTexture2D(&rtDesc, 0, &_pTexture);


	//	SRV設定 オフスク用
	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(srvDesc));
	srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MostDetailedMip = 0;
	srvDesc.Texture2D.MipLevels = rtDesc.MipLevels;
	m_Device->CreateShaderResourceView(_pTexture.Get(), &srvDesc, &_pRenderingTextureSRV);
	

	// レンダーターゲットビュー作成 (デフォルト)
	ID3D11Texture2D* renderTarget = NULL;
	m_SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&renderTarget );	
	m_Device->CreateRenderTargetView(renderTarget, NULL, &m_RenderTargetView );	
	renderTarget->Release();

	// RTV 作成 オフスク用
	m_Device->CreateRenderTargetView(_pTexture.Get(), NULL, &_pRenderingTextureRTV);
```

# オフスク用RTV切り替え処理を作成
これをRendererなどのクラスで関数として切り替えを出来るようにする
↓の関数はRTVを設定する機能があるだけです。
```c++
// レンダリング結果のRTVを設定
m_DeviceContext->OMSetRenderTargets(1, &_pRenderingTextureRTV, m_DepthStencilView);
```
```c++
// デフォルトのRTVを設定
m_DeviceContext->OMSetRenderTargets(1, &m_RenderTargetView, m_DepthStencilView);
```

## この後の流れ
```mermaid

graph TD
dr>デフォルトレンダリング<br>1枚の2Dポリゴンにレンダリングしたテクスチャを貼り付けて描画]
switch(オフスク用RTVからデフォルトRTVに切り替える)
ofscr[オフスクリーンレンダリング用のRTVをセット]

Draw==>ofscr--3Dオブジェクトの描画-->switch-.->dr--2Dオブジェクトの描画==>End
```

## 切り替え処理の実装
もともと、manager.cppのDrawはこうなっていました
```c++
Manager::Draw()
{
    // Begin()中ではデフォルトのRTVとDSVのクリアをしていました
    Renderer::Begin();

    // 2Dも3Dもここで描画
    _scene->Draw();

    // End()中ではスワップチェーンのPresent（描画)が行われていました
    Renderer::End();
}
```
これをレンダリングテクスチャを描画出来るように↓に変えましたが
```c++
Manger::Draw()
{
    // レンダリング結果のRTVを設定
    Renderer::BeginRenderingTexture();
    
    // 全オブジェクト描画
    _scene->Draw();

    
    Renderer::EndRenderingTexture();

    // デフォルトのRTVをセット
    Renderer::Begin();

    // ※ここで一枚のスプライトにレンダリングテクスチャを貼り付けて描画

    Renderer::End();
}
```
これだと、2D描画がうまくできなかったため順序を変える必要がありました
```
    3D描画 --> レンダリングテクスチャ2Dポリゴン描画 --> 2D描画
```
この問題を解決するために、GameObjectをイテレーションしている部分でLayerを設け
そこで順番を変更、RTV切り替え処理をしました。

レンダリングテクスチャ2Dポリゴン描画はDeviceContext->PSSetShaderResources()にレンダリングしたSRVを送ってあげればOKです。

# 終わり
DirectX11でオフスクリーンレンダリングをする際の「流れ・手順」を部分的にではありますが紹介しました。
この後、ブラーやブルームを実装していきたいので、でき次第また備忘録を書こうかなと思います。