はじめに
初めて記事を投稿します。ゆってぃと申します。
現在ゲーム系の専門学校で就職作品を作成しています。
そこで、ポストエフェクトを作成したいと考えました。
情報をあさるとまず、オフスクリーンレンダリングをする必要が在るようでした。
しかし、調べてもDirectX11のオフスクリーンレンダリングの情報が全然ありませんでした。
備忘録も兼ねて、誰かの参考になればと思います。
ただ、専門学校で教わったとかではなく完全に独学なので、
この記事を見れば確実に出来るようになるというわけではなく、
このやり方が最善であるということでもありません。
オフスクリーンレンダリングをするメリット
- レンダリング結果をテクスチャとして使用することが出来る。
- シェーダーでの加工が可能になる
- ポストエフェクトを作成できる
- ブラー
- ブルーム
- 被写界深度
- など
処理の流れ
オフスク用SRVやRTV、Textureなどを作成
変数用意
- ID3D11Texture2Dポインタ
- ID3D11SamplerStateポインタ デフォルトとオフスク用
- ID3D11RenderTargetViewポインタ オフスク用
- ID3D11ShaderResourceViewポインタ オフスク用
- あとサンプラー
Renderer.h内
//ディスプレイのバッグバッファのテクスチャ
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()内
// 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を設定する機能があるだけです。
// レンダリング結果のRTVを設定
m_DeviceContext->OMSetRenderTargets(1, &_pRenderingTextureRTV, m_DepthStencilView);
// デフォルトのRTVを設定
m_DeviceContext->OMSetRenderTargets(1, &m_RenderTargetView, m_DepthStencilView);
この後の流れ
切り替え処理の実装
もともと、manager.cppのDrawはこうなっていました
Manager::Draw()
{
// Begin()中ではデフォルトのRTVとDSVのクリアをしていました
Renderer::Begin();
// 2Dも3Dもここで描画
_scene->Draw();
// End()中ではスワップチェーンのPresent(描画)が行われていました
Renderer::End();
}
これをレンダリングテクスチャを描画出来るように↓に変えましたが
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でオフスクリーンレンダリングをする際の「流れ・手順」を部分的にではありますが紹介しました。
この後、ブラーやブルームを実装していきたいので、でき次第また備忘録を書こうかなと思います。