Microsoft Visual 2017 Community C++
 Direct3D 11.0( SM 5.0 )
 DirectXTex texture processing library
 XMLLite
 DirectXMath

■Direct3D11 Translucent Shadow Maps Prev Top Next
関連ページ:Direct3D11 自作ライブラリ


今回はTranslucent Shadow Mapsというものをやります。半透明シャドウマップです。前回同様、日本語解説しているサイトがなかったので、英語論文を適当に解釈して実装しました。
論文はここです。

Translucent Shadow Maps は半透明メッシュの表面下散乱をシミュレートします。
シャドウマップといいつつなぜか影とは無関係のネタとなってます。

概要について簡単に説明すると、メッシュの表面で屈折した光がメッシュの裏側を照らすことを考えます。このへんはリンク先の論文の図を見てもらったほうがいいでしょう。

次に実装方法について簡単に説明します。

1.まずライトビューからみたメッシュの裏側の深度値を取得します。

2.次にライトビューからみたメッシュの表側をレンダリングしますが、ここでは光がメッシュ裏側のどの座標をどの程度照らすかを調べます。
照らす座標については、メッシュの表面の法線ベクトルによって屈折した平行光源とメッシュの裏面が交差したところとなります。
光度は、メッシュの厚みで減衰した値とします。この過程で作成したマップをここでは半透明マップと命名しておきます。

3.半透明マップを適当にブラー処理します。

4.最終的にハーフランバートによるメッシュ表面の光の拡散反射率と半透明マップを線形合成します。線形合成値にもハーフランバートで計算した内積値を使用します。

そして出来上がったのが上の画像ですが、正しいような正しくないような、よく分からん感じです。


@Direct3D 自作の共通ライブラリ一式をここを参照して作成してください。

Aシェーダー系で使用するソースです。
TranslucentShadowMaps_Pass0.hlsl 背面深度マップを生成するシェーダーソース
TranslucentShadowMaps_Pass1.hlsl 半透明マップを生成するシェーダーソース
TranslucentShadowMaps_Pass2.hlsl 半透明メッシュをレンダリングするシェーダーソース
TranslucentShadowMaps.h TranslucentShadowMapsクラスのヘッダーファイル
TranslucentShadowMaps.cpp TranslucentShadowMapsクラスのソースファイル
BlurFilterRed.hlsl ブラーフィルターするシェーダーソース
BlurFilter.h BlurFilterクラスのヘッダーファイル
BlurFilter.cpp BlurFilterクラスのソースファイル

B個別に使用するソースです。
MonkeyMesh.h Monkeyメッシュクラスのヘッダーファイル
MonkeyMesh.cpp Monkeyメッシュクラスのソースファイル
main.cpp main関数のソースファイル


---TranslucentShadowMaps_Pass0.hlsl---  ↑

// ************************************************************
// Translucent Shadow Maps    背面ポリゴンの深度値
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj  : packoffset( c0 );    // ライトビューのワールドビュー正射影行列
};

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;    // 頂点座標
   float3 normal : NORMAL;      // 法線ベクトル
   float2 texel  : TEXCOORD;    // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos      : SV_POSITION;
};

// 頂点シェーダー
VS_OUT_PS_IN TranslucentShadowMaps_Pass0_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   return Out;
}

// ピクセルシェーダ
float TranslucentShadowMaps_Pass0_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   // 深度マップ
   return In.pos.z;
}

---TranslucentShadowMaps_Pass1.hlsl---  ↑


// ************************************************************
// Translucent Shadow Maps   半透明マップの作成
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj  : packoffset( c0 );    // ライトビューのワールドビュー射影行列
   column_major float4x4 g_matLightWorldView   : packoffset( c4 );    // ライトビューのワールドビュー行列
   float g_Width                    : packoffset( c8.x );
   float g_Height                   : packoffset( c8.y );
};

// テクスチャー
Texture2D<float4> g_DepthMap : register( t1 );

// アンオーダードアクセスビュー
RWTexture2D<float> g_TranslucentMap : register( u2 );

// サンプラーステート
SamplerState g_Sampler : register( s1 );

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;    // 頂点座標
   float3 normal : NORMAL;      // 法線ベクトル
   float2 texel  : TEXCOORD;    // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos      : SV_POSITION;
   float3 normal   : NORMAL;
   float3 posWVP   : TEXCOORD0;
};

// 頂点シェーダー
VS_OUT_PS_IN TranslucentShadowMaps_Pass1_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   
   // 平行移動しない
   Out.normal = mul( In.normal, (float3x3)g_matLightWorldView );
   
   Out.posWVP = Out.pos.xyz;
   
   return Out;
}

float2 GetTexel( float3 pos )
{
   return float2( pos.x * 0.5f + 0.5f, pos.y * -0.5f + 0.5f );
}

// ピクセルシェーダ
void TranslucentShadowMaps_Pass1_PS_Main( VS_OUT_PS_IN In )
{
   // 現在のピクセル位置のテクセル取得
   float2 texel = GetTexel( In.posWVP );
   
   // 現在のピクセル位置の深度マップを所得
   float depth = g_DepthMap.Sample( g_Sampler, texel ).r;
   
   // 視線ベクトル
   float3 vecLook = float3( 0, 0, -1 );
   
   // 入射光の反射ベクトルを作成する
   // 反射係数は 0.0f 〜 1.0f 範囲内で指定する。0.0f のとき反射なし。
   float3 vecInLight = refract( vecLook, normalize(In.normal), 0.9f );

   const float offset = 0.01f;
   float i = 0;
   float3 pos;

   // 背面ポリゴンとの交差点を取得
   [unroll(30)]
   while( 1 )
   {
      i+=offset;
      
      // 入射光方向に移動
      pos = In.posWVP.xyz + vecInLight * i;
      
      // 移動した座標のテクセル座標を計算
      texel = GetTexel( pos );
      
      // サンプリング
      depth = g_DepthMap.Sample( g_Sampler, texel ).r;

      // 深度マップ上の深度値 <= 移動した座標の深度値の場合
      if( depth <= pos.z )
      {
         // 戻す
         i-=offset;
         pos = In.posWVP + vecInLight * i;
         texel = GetTexel( pos );
         
         // メッシュの厚みにより光度を調整。
         float lp = exp( -length( vecInLight * i ) * 2.0f );
         
         // アンオーダードアクセスビューに出力
         g_TranslucentMap[ int2( texel.x * g_Width, texel.y * g_Height ) ] += lp;
         
         return;
      }
   }
}

ラスタライザで選択されたテクセル座標と異なる座標に色を出力するため、レンダーターゲットビューではなくアンオーダードアクセスビューを使用します。

サンプルでは飛ばすレイは平行光源方向に1本のみです。複数方向に飛ばせば、精度が上がるかもしれません。

---TranslucentShadowMaps_Pass2.hlsl---  ↑


// ************************************************************
// Translucent Shadow Map   最終レンダリング
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj  : packoffset( c0 );   // ライトビューのワールドビュー射影行列
   column_major float4x4 g_matCameraWorldViewProj  : packoffset( c4 );   // カメラビューのワールドビュー射影行列
   float4 g_vecLightPos             : packoffset( c8 );   // ローカル座標系での平行光源の位置ベクトル
};

// 半透明マップ
Texture2D g_TranslucentMap : register( t1 );

// サンプラーステート
SamplerState g_Sampler : register( s1 );

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;    // 頂点座標
   float3 normal : NORMAL;      // 法線ベクトル
   float2 texel  : TEXCOORD;    // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos      : SV_POSITION;
   float3 normal   : NORMAL;
   float4 posLWVP  : TEXCOORD0;
   float3 posLocal : TEXCOORD1;
};

// 頂点シェーダー
VS_OUT_PS_IN TranslucentShadowMaps_Pass2_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out = (VS_OUT_PS_IN)0;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matCameraWorldViewProj );
   Out.posLWVP = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   Out.normal = In.normal;
   Out.posLocal = In.pos.xyz;
   
   return Out;
}

// ピクセルシェーダ
float4 TranslucentShadowMaps_Pass2_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   // ライトビューでのピクセル位置のテクセル取得
   float2 texel = float2( In.posLWVP.x * 0.5f + 0.5f, In.posLWVP.y * -0.5f + 0.5f );
   
   // 半透明マップを所得
   float translucent = g_TranslucentMap.Sample( g_Sampler, texel ).r;
   
   // ハーフランバート
   float lambert = dot( g_vecLightPos.xyz, In.normal );
   lambert = lambert * 0.3f + 0.7f;

   return lerp( translucent, lambert, lambert );
//   return lambert;
}

ハーフランバートは全体的に明るくするために変則的な式となっています。

---TranslucentShadowMaps.h---  ↑


#ifndef TRANSLUCENT_SHADOW_MAPS_H
#define TRANSLUCENT_SHADOW_MAPS_H

#include "../Common/UCommon.h"
#include "../Common/UException.h"
#include "../Common/UGraphicsPipeline.h"
#include "../Common/UDirect3D11.h"
#include "BlurFilter.h"

class TranslucentShadowMaps
{
private:
   // 背面ポリゴンの深度マップ作成用
   typedef struct _CBUFFER_PASS0
   {
      // ワールドとビューと正射影行列
      XMMATRIX matLightWorldViewProj;
   }CBUFFER_PASS0;

   // 半透明マップ作成用
   typedef struct _CBUFFER_PASS1
   {
      // ワールドとビューと射影行列
      XMMATRIX matLightWorldViewProj;
      XMMATRIX matLightWorldView;
      float Width;
      float Height;
      float Dummy3;
      float Dummy4;
   }CBUFFER_PASS1;

   // 最終レンダリング
   typedef struct _CBUFFER_PASS2
   {
      // ワールドとビューと射影行列
      XMMATRIX matLightWorldViewProj;
      XMMATRIX matCameraWorldViewProj;
      XMFLOAT4 vecLightDir;
   }CBUFFER_PASS2;

   // 背面ポリゴンの深度値
   ID3D11RenderTargetView* m_pRTViewOfDepthMap;
   ID3D11ShaderResourceView* m_pSRViewOfDepthMap;

   ID3D11DepthStencilView* m_pDSView;

   // 半透明マップ
   // 任意テクセル座標に書き込むためアンオーダードアクセスビューを使用する
   ID3D11UnorderedAccessView* m_pUAViewOfTranslucentMap;
   ID3D11ShaderResourceView* m_pSRViewOfTranslucentMap;

   // レンダーターゲットと深度ステンシルとビューポートのバックアップ
   ID3D11RenderTargetView* m_pOldRTView[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
   ID3D11DepthStencilView* m_pOldDSView;
   D3D11_VIEWPORT m_pOldViewport[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
   UINT m_ViewportCount;

   // シェーダー用定数バッファ
   ID3D11Buffer* m_pConstantBuffers[3];

   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;

   UGraphicsPipeline* m_pGraphicsPipeline[3];

   // ブラーフィルター
   BlurFilter* m_pBlurFilter;

   UINT m_Width, m_Height;

   int m_Pass;

   XMMATRIX m_MatLightView;
   XMMATRIX m_MatLightProj;
   XMMATRIX m_MatCameraView;
   XMMATRIX m_MatCameraProj;
   XMFLOAT4 m_VecLightPos;

public:
   TranslucentShadowMaps();
   virtual ~TranslucentShadowMaps();
   void Invalidate();
   void Create( ID3D11Device* pD3DDevice, UINT Width, UINT Height );
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass,
                   XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj );
   void SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld );
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
   inline UINT GetMaxPass(){ return _countof( m_pGraphicsPipeline ); };
   inline const ID3D11ShaderResourceView* GetDepthMap(){ return m_pSRViewOfDepthMap; };
   inline const ID3D11ShaderResourceView* GetTranslucentMap(){ return m_pSRViewOfTranslucentMap; };
   inline const ID3D11ShaderResourceView* GetBlurMap(){ return m_pBlurFilter->GetBlurMap(); };
};

#endif

---TranslucentShadowMaps.cpp---  ↑


#include "../../Header/Shader/TranslucentShadowMaps.h"
#include "../../HLSL/TranslucentShadowMaps_Pass0_VS_Main.h"
#include "../../HLSL/TranslucentShadowMaps_Pass0_PS_Main.h"
#include "../../HLSL/TranslucentShadowMaps_Pass1_VS_Main.h"
#include "../../HLSL/TranslucentShadowMaps_Pass1_PS_Main.h"
#include "../../HLSL/TranslucentShadowMaps_Pass2_VS_Main.h"
#include "../../HLSL/TranslucentShadowMaps_Pass2_PS_Main.h"

TranslucentShadowMaps::TranslucentShadowMaps()
{
   m_pRTViewOfDepthMap = nullptr;
   m_pSRViewOfDepthMap = nullptr;
   m_pDSView = nullptr;
   m_pUAViewOfTranslucentMap = nullptr;
   m_pSRViewOfTranslucentMap = nullptr;
   m_pBlurFilter = nullptr;
   for( UINT i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      m_pGraphicsPipeline[i] = nullptr;
      m_pConstantBuffers[i] = nullptr;
   }
   m_pSamplerState = nullptr;

   m_Pass = -1;
}

TranslucentShadowMaps::~TranslucentShadowMaps()
{	
   SAFE_RELEASE( m_pSamplerState );
   for( UINT i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      SAFE_DELETE( m_pGraphicsPipeline[i] );
      SAFE_RELEASE( m_pConstantBuffers[i] );
   }
   SAFE_DELETE( m_pBlurFilter );
   SAFE_RELEASE( m_pSRViewOfTranslucentMap );
   SAFE_RELEASE( m_pUAViewOfTranslucentMap );
   SAFE_RELEASE( m_pDSView );
   SAFE_RELEASE( m_pSRViewOfDepthMap );
   SAFE_RELEASE(m_pRTViewOfDepthMap);
}

void TranslucentShadowMaps::Create( ID3D11Device* pD3DDevice, UINT Width, UINT Height )
{
   m_Width = Width;
   m_Height = Height;

   m_Pass = -1;

   // *******************************************************************************************************
   // 背面ポリゴンの深度マップを作成する
   // *******************************************************************************************************

   m_pGraphicsPipeline[0] = NEW UGraphicsPipeline();

   // ラスタライザーステートを作成する
   m_pGraphicsPipeline[0]->CreateRasterizerState( pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_FRONT );

   // 深度ステンシルステートを作成する( 深度ステンシルバッファーの深度値より大きいとき深度テストに合格 )
   m_pGraphicsPipeline[0]->CreateDepthStencilState( pD3DDevice, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL, D3D11_COMPARISON_GREATER );

   // ブレンドステートを作成する
   UGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UGraphicsPipeline::UEBLEND_STATE::NONE };
   m_pGraphicsPipeline[0]->CreateBlendState( pD3DDevice, BlendStateType, 1 );

   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   };

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[0]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass0.hlsl"), "TranslucentShadowMaps_Pass0_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromFile(pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass0.hlsl"), "TranslucentShadowMaps_Pass0_PS_Main");
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass0_VS_Main, sizeof( g_TranslucentShadowMaps_Pass0_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromMemory(pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass0_PS_Main, sizeof(g_TranslucentShadowMaps_Pass0_PS_Main));
#endif

   UMaps::CreateRenderTargetView(pD3DDevice, DXGI_FORMAT_R16_FLOAT, m_Width, m_Height, &m_pRTViewOfDepthMap, &m_pSRViewOfDepthMap);

   UMaps::CreateDepthStencilView(pD3DDevice, m_Width, m_Height, &m_pDSView, nullptr);

   // 定数バッファを作成する
   m_pConstantBuffers[0] = m_pGraphicsPipeline[0]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( TranslucentShadowMaps::CBUFFER_PASS0 ), D3D11_CPU_ACCESS_WRITE );

   // *******************************************************************************************************
   // 半透明マップを作成する
   // *******************************************************************************************************

   m_pGraphicsPipeline[1] = NEW UGraphicsPipeline();

   // ラスタライザーステートを作成する
   m_pGraphicsPipeline[1]->CreateRasterizerState( pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK );

   // 深度ステンシルステートを作成する
   m_pGraphicsPipeline[1]->CreateDepthStencilState( pD3DDevice, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL );

   // ブレンドステートを作成する
   BlendStateType[0] = UGraphicsPipeline::UEBLEND_STATE::NONE;
   m_pGraphicsPipeline[1]->CreateBlendState( pD3DDevice, BlendStateType, 1 );

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[1]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass1.hlsl"), "TranslucentShadowMaps_Pass1_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[1]->CreatePixelShaderFromFile( pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass1.hlsl"), "TranslucentShadowMaps_Pass1_PS_Main" );
#else
   m_pGraphicsPipeline[1]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass1_VS_Main, sizeof( g_TranslucentShadowMaps_Pass1_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[1]->CreatePixelShaderFromMemory( pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass1_PS_Main, sizeof( g_TranslucentShadowMaps_Pass1_PS_Main ) );
#endif

   // アンオーダードアクセスビューを作成する
   // 16ビットでは加算合成されないので32ビットにする
   UMaps::CreateRenderTargetViewOfRWTexture( pD3DDevice, DXGI_FORMAT_R32_FLOAT, m_Width, m_Height, &m_pUAViewOfTranslucentMap, &m_pSRViewOfTranslucentMap );
   
   // 定数バッファを作成する
   m_pConstantBuffers[1] = m_pGraphicsPipeline[1]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( TranslucentShadowMaps::CBUFFER_PASS1 ), D3D11_CPU_ACCESS_WRITE );

   // *******************************************************************************************************
   // ブラーフィルター
   // *******************************************************************************************************

   m_pBlurFilter = NEW BlurFilter();
   m_pBlurFilter->Create( pD3DDevice, m_Width / 2, m_Height / 2, DXGI_FORMAT_R16_FLOAT );

   // *******************************************************************************************************
   // メッシュのレンダリング
   // *******************************************************************************************************

   m_pGraphicsPipeline[2] = NEW UGraphicsPipeline();

   // ラスタライザーステートを作成する
   m_pGraphicsPipeline[2]->CreateRasterizerState( pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK );

   // 深度ステンシルステートを作成する
   m_pGraphicsPipeline[2]->CreateDepthStencilState( pD3DDevice, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL );

   // ブレンドステートを作成する
   BlendStateType[0] = UGraphicsPipeline::UEBLEND_STATE::NONE;
   m_pGraphicsPipeline[2]->CreateBlendState( pD3DDevice, BlendStateType, 1 );

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[2]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass2.hlsl"), "TranslucentShadowMaps_Pass2_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromFile( pD3DDevice, _T("../HLSL/TranslucentShadowMaps_Pass2.hlsl"), "TranslucentShadowMaps_Pass2_PS_Main" );
#else
   m_pGraphicsPipeline[2]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass2_VS_Main, sizeof( g_TranslucentShadowMaps_Pass2_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromMemory( pD3DDevice, (LPBYTE)g_TranslucentShadowMaps_Pass2_PS_Main, sizeof( g_TranslucentShadowMaps_Pass2_PS_Main ) );
#endif
   
   // 定数バッファを作成する
   m_pConstantBuffers[2] = m_pGraphicsPipeline[2]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( TranslucentShadowMaps::CBUFFER_PASS2 ), D3D11_CPU_ACCESS_WRITE );

   // サンプラーステートを作成する
   m_pSamplerState = USamplers::CreateSamplerState( pD3DDevice, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT );
}

void TranslucentShadowMaps::BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass,
                                       XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj )
{
   if (m_Pass != -1)
   {
      throw(UException(-1, _T("TranslucentShadowMaps::BeginPass()はCreate()またはEndPass()実行後に使用してください")));
   }

   m_Pass = (int)Pass;

   switch( m_Pass )
   {
   case 0:
      {
         // レンダーターゲットビューと深度ステンシルビューを切り替える

         pD3DDeviceContext->OMGetRenderTargets(_countof(m_pOldRTView), m_pOldRTView, &m_pOldDSView);
         pD3DDeviceContext->OMSetRenderTargets(1, &m_pRTViewOfDepthMap, m_pDSView);

         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, nullptr );
         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, &m_pOldViewport[0] );

         // ビューポートを切り替える。
         D3D11_VIEWPORT Viewport[1];
         Viewport[0].TopLeftX = 0;
         Viewport[0].TopLeftY = 0;
         Viewport[0].Width    = (FLOAT)m_Width;
         Viewport[0].Height   = (FLOAT)m_Height;
         Viewport[0].MinDepth = 0.0f;
         Viewport[0].MaxDepth = 1.0f;
         pD3DDeviceContext->RSSetViewports( 1, Viewport );

         float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };

         pD3DDeviceContext->ClearRenderTargetView(m_pRTViewOfDepthMap, ClearColor);

         // 深度バッファの初期値は最前面の0
         pD3DDeviceContext->ClearDepthStencilView( m_pDSView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0  );

         m_VecLightPos = *pVecLightPos;

         m_MatLightView = XMMatrixLookAtLH(XMLoadFloat3((XMFLOAT3*)&m_VecLightPos), XMLoadFloat3(&XMFLOAT3(0, 0, 0)), XMLoadFloat3(&XMFLOAT3(0, 1, 0)));
         m_MatLightProj = (*pMatLightProj);

         m_MatCameraView = XMMatrixIdentity();
         m_MatCameraProj = XMMatrixIdentity();
      }
      break;

   case 1:
      {
         // アンオーダードアクセスビューと深度ステンシルビューを切り替える

         pD3DDeviceContext->OMGetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, &m_pOldDSView );
         pD3DDeviceContext->OMSetRenderTargetsAndUnorderedAccessViews( 0, nullptr, m_pDSView, 2, 1, &m_pUAViewOfTranslucentMap, nullptr );

         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, nullptr );
         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, &m_pOldViewport[0] );

         // ビューポートを切り替える。
         D3D11_VIEWPORT Viewport[1];
         Viewport[0].TopLeftX = 0;
         Viewport[0].TopLeftY = 0;
         Viewport[0].Width    = (FLOAT)m_Width;
         Viewport[0].Height   = (FLOAT)m_Height;
         Viewport[0].MinDepth = 0.0f;
         Viewport[0].MaxDepth = 1.0f;
         pD3DDeviceContext->RSSetViewports( 1, Viewport );

         float ClearColor[4] = { 0, 0, 0, 0 };
         pD3DDeviceContext->ClearUnorderedAccessViewFloat( m_pUAViewOfTranslucentMap, ClearColor ); 

         // 最奥面で初期化
         pD3DDeviceContext->ClearDepthStencilView( m_pDSView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0  );

         pD3DDeviceContext->PSSetShaderResources( 1, 1, &m_pSRViewOfDepthMap );
      }
      break;

   case 2:
      {
         ID3D11ShaderResourceView* pSRView = const_cast<ID3D11ShaderResourceView*>(m_pBlurFilter->GetBlurMap());

         pD3DDeviceContext->PSSetShaderResources( 1, 1, &pSRView );
         
         pD3DDeviceContext->PSSetSamplers( 1, 1, &m_pSamplerState );

         m_MatCameraView = (*pMatCameraView);
         m_MatCameraProj = (*pMatCameraProj);
      }
      break;

   default:
      throw(UException(-1, _T("TranslucentShadowMaps::BeginPass()で無効なPassが指定されました")));
   }

   // 各種ステートを設定する
   m_pGraphicsPipeline[m_Pass]->SetRasterizerState( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetDepthStencilState( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetBlendState( pD3DDeviceContext );

   // 各種グラフィックパイプラインを設定
   m_pGraphicsPipeline[m_Pass]->SetVertexShader( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetHullShader( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetDomainShader( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetGeometryShader( pD3DDeviceContext );
   m_pGraphicsPipeline[m_Pass]->SetPixelShader( pD3DDeviceContext );
}

void TranslucentShadowMaps::SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld )
{
   HRESULT hr = E_FAIL;

   switch( m_Pass )
   {
   case 0:
      {
         // ライトビューでのワールド行列とビュー行列と射影行列
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatLightView * m_MatLightProj );

         // 定数バッファをロックする
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("TranslucentShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         TranslucentShadowMaps::CBUFFER_PASS0* cbuffer = (TranslucentShadowMaps::CBUFFER_PASS0*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof( XMMATRIX ) );
         pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
      }
      break;

   case 1:
      {
         // ライトビューでのワールド行列とビュー行列と射影行列
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatLightView * m_MatLightProj );

         // ライトビューのワールド行列とビュー行列( ローカル座標系の法線ベクトルの座標変換のため逆転置行列 )
         XMMATRIX matLightWorldView = XMMatrixInverse( nullptr, *pMatWorld * m_MatLightView );

         // 定数バッファをロックする
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("TranslucentShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         TranslucentShadowMaps::CBUFFER_PASS1* cbuffer = (TranslucentShadowMaps::CBUFFER_PASS1*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof( XMMATRIX ) );
         ::CopyMemory( &cbuffer->matLightWorldView, &matLightWorldView, sizeof( XMMATRIX ) );
         cbuffer->Width = (float)m_Width;
         cbuffer->Height = (float)m_Height;
         pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
         pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
      }
      break;

   case 2:
      {
         // ライトビューのワールド行列とビュー行列と射影行列
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatLightView * m_MatLightProj );

         // カメラビューのワールド行列とビュー行列と射影行列
         XMMATRIX matCameraWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatCameraView * m_MatCameraProj );
         XMMATRIX matInv = XMMatrixInverse( nullptr, *pMatWorld );
         XMVECTOR v = XMVector4Transform( XMLoadFloat4( &m_VecLightPos ), matInv );
         XMVECTOR nv = XMVector3Normalize( v );
         XMFLOAT4 localLightPos;
         XMStoreFloat4( &localLightPos, nv );

         // 定数バッファをロックする
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("TranslucentShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         TranslucentShadowMaps::CBUFFER_PASS2* cbuffer = (TranslucentShadowMaps::CBUFFER_PASS2*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof( XMMATRIX ) );
         ::CopyMemory( &cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof( XMMATRIX ) );
         ::CopyMemory( &cbuffer->vecLightDir, &localLightPos, sizeof( XMFLOAT4 ) );
         pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
         pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
      }
      break;
   }
}

void TranslucentShadowMaps::EndPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   switch( m_Pass )
   {
   case 0:
      {
         // レンダーターゲットビューと深度ステンシルビューとビューポートを戻す

         pD3DDeviceContext->OMSetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, m_pOldDSView );
         for( UINT i=0; i<_countof( m_pOldRTView ); i++ )
            SAFE_RELEASE( m_pOldRTView[i] );
         SAFE_RELEASE( m_pOldDSView );

         pD3DDeviceContext->RSSetViewports( m_ViewportCount, m_pOldViewport );
      }
      break;

   case 1:
      {
         // レンダーターゲットビューと深度ステンシルビューとビューポートを戻す
         pD3DDeviceContext->OMSetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, m_pOldDSView );
         for( UINT i=0; i<_countof( m_pOldRTView ); i++ )
            SAFE_RELEASE( m_pOldRTView[i] );
         SAFE_RELEASE( m_pOldDSView );

         pD3DDeviceContext->RSSetViewports( m_ViewportCount, m_pOldViewport );

         // ブラーフィルター
         m_pBlurFilter->BeginPass( pD3DDeviceContext, m_pSRViewOfTranslucentMap );
         m_pBlurFilter->Render( pD3DDeviceContext );
         m_pBlurFilter->EndPass( pD3DDeviceContext );
      }
      break;

   case 2:
      {
         ID3D11ShaderResourceView* pSRViewNull[] = { nullptr, nullptr };
         pD3DDeviceContext->PSSetShaderResources( 0, _countof( pSRViewNull ), pSRViewNull );
      }
      break;
   }

   m_Pass = -1;
}

アンオーダードアクセスビューは32ビットフォーマットで作成してください。でないと加算されないので。

---BlurFilterRed.hlsl---  ↑


// ************************************************************
// Blur Filter( 赤成分のみ )
// ************************************************************

// 定数バッファ
cbuffer cbBuffer0 : register( b0 )
{
   float  g_Width  : packoffset( c0.x );
   float  g_Height : packoffset( c0.y );
};

// テクスチャー
Texture2D g_Tex : register( t0 );

// サンプラーステート
SamplerState g_Sampler
{
    Filter = MIN_MAG_LINEAR_MIP_POINT;
    AddressU = Clamp;
    AddressV = Clamp;
};

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;   // 頂点座標
   float2 texel  : TEXCOORD;
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos    : SV_POSITION;
   float2 texel  : TEXCOORD0;
};

VS_OUT_PS_IN BlurFilterRed_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = float4( In.pos, 1.0f );
   Out.texel = In.texel;
   
   return Out;
}

float4 BlurFilterRed_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   float4 Out = 0.0f;
   
   for( int i=-4; i<=4; i+=2 )
   {
      for( int j=-4; j<=4; j+=2 )
      {
         // 4テクセル位置のr成分のみを取得し、xyzw成分に格納するらしい。MSDNが不親切すぎてよくわからんが。
         Out += g_Tex.GatherRed( g_Sampler, In.texel, int2( i, j ) );
      }
   }
   Out.r = ( Out.r + Out.g + Out.b + Out.w ) * 0.01f;
   
   return Out.r;
}

---BlurFilter.h---  ↑


#ifndef BLUR_FILTER_H
#define BLUR_FILTER_H

#include "../Common/UCommon.h"
#include "../Common/UException.h"
#include "../Common/UGraphicsPipeline.h"
#include "../Common/UDirect3D11.h"

class BlurFilter
{
private:
   typedef struct _VERTEX
   {
      XMFLOAT3 Position;
      XMFLOAT2 Texcoord;
   }VERTEX;

   typedef struct _CBUFFER
   {
      float Width;
      float Height;
      float Dummy3;
      float Dummy4;
   }CBUFFER;

   // 頂点バッファ
   ID3D11Buffer* m_pVertexBuffer;

   ID3D11RenderTargetView* m_pRTView;
   ID3D11ShaderResourceView* m_pSRView;

   ID3D11ShaderResourceView* m_pSrcSRView;


   ID3D11RenderTargetView* m_pOldRTView[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
   ID3D11DepthStencilView* m_pOldDSView;
   D3D11_VIEWPORT m_pOldViewport[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
   UINT m_ViewportCount;

   // シェーダー用定数バッファ
   ID3D11Buffer* m_pConstantBuffers;

   UGraphicsPipeline* m_pGraphicsPipeline;

   UINT m_Width, m_Height;

public:
   BlurFilter();
   virtual ~BlurFilter();
   void Invalidate();
   void Create( ID3D11Device* pD3DDevice, DWORD Width, DWORD Height, DXGI_FORMAT Format );
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView );
   void Render( ID3D11DeviceContext* pD3DDeviceContext );
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
   inline const ID3D11ShaderResourceView* GetBlurMap(){ return m_pSRView; };

};

#endif

---BlurFilter.cpp---  ↑


#include "../../Header/Shader/BlurFilter.h"
#include "../../HLSL/BlurFilterRed_VS_Main.h"
#include "../../HLSL/BlurFilterRed_PS_Main.h"

BlurFilter::BlurFilter()
{
   m_pVertexBuffer = nullptr;
   m_pRTView = nullptr;
   m_pSRView = nullptr;
   m_pConstantBuffers = nullptr;
   m_pGraphicsPipeline = nullptr;
}

BlurFilter::~BlurFilter()
{
   SAFE_DELETE( m_pGraphicsPipeline );
   SAFE_RELEASE( m_pConstantBuffers );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pRTView );
   SAFE_RELEASE( m_pVertexBuffer );
}

void BlurFilter::Create( ID3D11Device* pD3DDevice, DWORD Width, DWORD Height, DXGI_FORMAT Format )
{
   m_Width = Width;
   m_Height = Height;

   m_pGraphicsPipeline = NEW UGraphicsPipeline();

   // ラスタライザーステートを作成する
   m_pGraphicsPipeline->CreateRasterizerState( pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK );

   // 深度ステンシルステートを無効にする
   m_pGraphicsPipeline->CreateDepthStencilState( pD3DDevice, FALSE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ZERO );

   // ブレンドステートを作成する
   UGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UGraphicsPipeline::UEBLEND_STATE::NONE };
   m_pGraphicsPipeline->CreateBlendState( pD3DDevice, BlendStateType, 1 );

   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   };

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   switch( Format )
   {
   case DXGI_FORMAT_R16_FLOAT:
   case DXGI_FORMAT_R32_FLOAT:
      m_pGraphicsPipeline->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/BlurFilterRed.hlsl"),
         "BlurFilterRed_VS_Main", layout, _countof( layout ) );

      m_pGraphicsPipeline->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/BlurFilterRed.hlsl"),
         "BlurFilterRed_PS_Main" );
      break;
   default:
      throw( UException( -1, _T("BlurFilter::Create()でエラーが発生しました。未対応のフォーマットです。") ) );
   }
#else
   switch( Format )
   {
   case DXGI_FORMAT_R16_FLOAT:
   case DXGI_FORMAT_R32_FLOAT:
      m_pGraphicsPipeline->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_BlurFilterRed_VS_Main,
         sizeof( g_BlurFilterRed_VS_Main ), layout, _countof( layout ) );

      m_pGraphicsPipeline->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_BlurFilterRed_PS_Main,
         sizeof( g_BlurFilterRed_PS_Main ) );
      break;
   default:
      throw( UException( -1, _T("BlurFilter::Create()でエラーが発生しました。未対応のフォーマットです。") ) );
   }
#endif

   // レンダーターゲットビューを作成する
   UMaps::CreateRenderTargetView( pD3DDevice, Format, m_Width, m_Height, &m_pRTView, &m_pSRView );

   // *******************************************************************************************************
   // メッシュ作成
   // *******************************************************************************************************

   // 頂点のデータ
   VERTEX v[] = {
      XMFLOAT3(   1,  1, 0 ), XMFLOAT2( 1, 0 ),
      XMFLOAT3(  -1,  1, 0 ), XMFLOAT2( 0, 0 ),
      XMFLOAT3(   1, -1, 0 ), XMFLOAT2( 1, 1 ),
      XMFLOAT3(  -1, -1, 0 ), XMFLOAT2( 0, 1 )
   };
   // 頂点バッファを作成する
   m_pVertexBuffer = UBuffers::CreateVertexBuffer( pD3DDevice, v, sizeof( v ), 0 );

   BlurFilter::CBUFFER cbuffer;
   cbuffer.Width = 1.0f / (float)m_Width;
   cbuffer.Height = 1.0f / (float)m_Height;
   // 定数バッファを作成する
   m_pConstantBuffers = m_pGraphicsPipeline->CreateConstantBuffer( pD3DDevice, (void*)&cbuffer, sizeof( BlurFilter::CBUFFER ), 0 );
}

void BlurFilter::BeginPass( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView )
{
   m_pSrcSRView = pSRView;

   // レンダーターゲットを退避
   pD3DDeviceContext->OMGetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, &m_pOldDSView );

   pD3DDeviceContext->RSGetViewports( &m_ViewportCount, nullptr );
   pD3DDeviceContext->RSGetViewports( &m_ViewportCount, &m_pOldViewport[0] );

   // ビューポートの退避
   pD3DDeviceContext->RSGetViewports( &m_ViewportCount, nullptr );
   pD3DDeviceContext->RSGetViewports( &m_ViewportCount, &m_pOldViewport[0] );   

   D3D11_VIEWPORT Viewport[1];   
   Viewport[0].TopLeftX = 0;
   Viewport[0].TopLeftY = 0;
   Viewport[0].Width    = (FLOAT)m_Width;
   Viewport[0].Height   = (FLOAT)m_Height;
   Viewport[0].MinDepth = 0.0f;
   Viewport[0].MaxDepth = 1.0f;
   // ビューポートの切り替え
   pD3DDeviceContext->RSSetViewports( 1, Viewport );
}

void BlurFilter::Render( ID3D11DeviceContext* pD3DDeviceContext )
{
   // 各種グラフィックパイプラインを設定
   m_pGraphicsPipeline->SetRasterizerState( pD3DDeviceContext );
   m_pGraphicsPipeline->SetDepthStencilState( pD3DDeviceContext );
   m_pGraphicsPipeline->SetBlendState( pD3DDeviceContext );

   // 頂点バッファ設定
   UINT stride = sizeof( BlurFilter::VERTEX );
   UINT offset = 0;
   pD3DDeviceContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );

   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // 定数バッファを設定
   pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers );

   pD3DDeviceContext->OMSetRenderTargets( 1, &m_pRTView, nullptr );

   // バックバッファをクリアする。( 上書きのため必要なし )

   // シェーダーを設定する
   m_pGraphicsPipeline->SetVertexShader( pD3DDeviceContext );
   m_pGraphicsPipeline->SetHullShader( pD3DDeviceContext );
   m_pGraphicsPipeline->SetDomainShader( pD3DDeviceContext );
   m_pGraphicsPipeline->SetGeometryShader( pD3DDeviceContext );
   m_pGraphicsPipeline->SetPixelShader( pD3DDeviceContext );

   // マップを設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &m_pSrcSRView );

   // 描画
   pD3DDeviceContext->Draw( 4, 0 );
}

void BlurFilter::EndPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   pD3DDeviceContext->OMSetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, m_pOldDSView );
   for( UINT i=0; i<_countof( m_pOldRTView ); i++ )
      SAFE_RELEASE( m_pOldRTView[i] );
   SAFE_RELEASE( m_pOldDSView );

   pD3DDeviceContext->RSSetViewports( m_ViewportCount, m_pOldViewport );
}

---MonkeyMesh.h---  ↑


#ifndef MONKEYMESH_H
#define MONKEYMESH_H

#include "../../Header/Common/UCommon.h"
#include "../../Header/Common/UDirect3D11.h"
#include "../../Header/Common/UException.h"
#include "../../Header/Common/UD3DMeshDataCreater.h"

#include "../../Header/Common/XNAMath/xnamath.h"

class MonkeyMesh
{
private:
   // 頂点バッファ
   ID3D11Buffer* m_pVertexBuffer;

   // インデックスバッファ
   // 未使用

   // シェーダーリソースビュー
   ID3D11ShaderResourceView* m_pSRView;

   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;

   UD3DMeshDataCreater m_MeshDataCreater;

   XMMATRIX m_MatWorld;

   float m_RotationX;

   UD3DMeshDataCreater::VERTEX* m_pVertex;
   ULONG m_VertexCount;

public:
   MonkeyMesh();
   virtual ~MonkeyMesh();
   void Invalidate();
   void CreateMesh( ID3D11Device* pD3DDevice );
   void NextFrame();
   inline XMMATRIX* GetMatWorld(){ return &m_MatWorld; };
   void Render( ID3D11DeviceContext* pD3DDeviceContext );
};

#endif

---MonkeyMesh.cpp---  ↑


#include "../../Header/Mesh/MonkeyMesh.h"

MonkeyMesh::MonkeyMesh()
{
   m_pVertexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
   m_pVertex = nullptr;
   m_VertexCount = 0;
   m_RotationX = 0.0f;
}

MonkeyMesh::~MonkeyMesh()
{
   Invalidate();
}

void MonkeyMesh::Invalidate()
{
   m_VertexCount = 0;
   SAFE_DELETE_ARRAY( m_pVertex );
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pVertexBuffer );
}

void MonkeyMesh::CreateMesh( ID3D11Device* pD3DDevice )
{
   // COLLADAデータを取得
   m_MeshDataCreater.LoadMesh( _T("../Resource/Monkey.dae") );

   UINT MonkeyMeshIndex = 0;

   m_RotationX = 0.0f;

   m_MeshDataCreater.GetVertexes( MonkeyMeshIndex, &m_pVertex, &m_VertexCount );

   // 頂点バッファを作成する
   m_pVertexBuffer = UBuffers::CreateVertexBuffer( pD3DDevice, m_pVertex, sizeof( UD3DMeshDataCreater::VERTEX ) * m_VertexCount, 0 );
  
   // サンプラーステートを作成する
   m_pSamplerState = USamplers::CreateSamplerState( pD3DDevice, D3D11_TEXTURE_ADDRESS_WRAP );

   UMaps::CreateSRViewFromDDSFile(pD3DDevice, _T("../Resource/Monkey.dds"), &m_pSRView);

   SAFE_DELETE_ARRAY( m_pVertex );
}

void MonkeyMesh::NextFrame()
{
   XMMATRIX matScaling, matXRotation, matTranslate;

   matScaling = XMMatrixScaling(20, 20, 20);
   m_RotationX += 0.0005f;
   if (m_RotationX > 2 * XM_PI)
      m_RotationX -= 2 * XM_PI;
   matXRotation = XMMatrixRotationX(m_RotationX);
   matTranslate = XMMatrixTranslation(0, 0.0f, 70.0f);
   m_MatWorld = matScaling * matXRotation * matTranslate;

}

void MonkeyMesh::Render( ID3D11DeviceContext* pD3DDeviceContext )
{
   // 頂点バッファ設定
   UINT stride = sizeof( UD3DMeshDataCreater::VERTEX );
   UINT offset = 0;
   pD3DDeviceContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );

   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

   // ピクセルシェーダーのサンプラーステートを設定する
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

   // デカールマップを設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &m_pSRView );

   // インデックスバッファを使用しない描画
   pD3DDeviceContext->Draw( m_VertexCount, 0 );
}

メッシュは Blender というモデラーでプリミティブとして作成したものを使用しています。

---main.cpp---  ↑


#include "../Header/Common/UCommon.h"
#include "../Header/Common/UException.h"
#include "../Header/Common/UDirect3D11.h"
#include "../Header/Common/UDebugFont.h"
#if defined(DEBUG) || defined(_DEBUG)
#include "../Header/Common/USRViewRenderer.h"
#endif
#include "../Header/Shader/TranslucentShadowMaps.h"

#include "../Header/Mesh/MonkeyMesh.h"

// アプリケーション名
TCHAR* AppName = _T("Direct3D11 Translucent Shadow Maps");

// Direct3D関連の自作クラス
UDirect3D11* g_pDirect3D11 = nullptr;

TranslucentShadowMaps* g_pTranslucentShadowMaps = nullptr;

MonkeyMesh* g_pMonkeyMesh = nullptr;

UDebugFont* g_pDebugFont = nullptr;
UFPS* g_pFPS = nullptr;

#if defined(DEBUG) || defined(_DEBUG)
USRViewRenderer* g_pSRViewRenderer = nullptr;
#endif

DWORD g_Width = 640, g_Height = 480;
float g_LightZFar = 300.0f, g_LightZNear = 200.0f;

// カメラビュー行列
XMMATRIX g_MatCameraView = XMMatrixIdentity();

// カメラービュー射影行列
XMMATRIX g_MatCameraProj = XMMatrixPerspectiveFovLH( XM_PI / 5.0f, (float)g_Width / (float)g_Height, 10.0f, 500.0f );

// ライトビューは距離計算が正しくできるように正射影行列にする
XMMATRIX g_MatLightProj = XMMatrixOrthographicLH( 150.0f, 150.0f, g_LightZNear, g_LightZFar );

// 平行光源の位置ベクトル
XMFLOAT4 g_VecLightPos = XMFLOAT4( 100.0f, 30.0f, 300.0f, 0 );

UINT g_Mode = 0;

// メモリ解放
void Invalidate()
{
#if defined(DEBUG) || defined(_DEBUG)
   SAFE_DELETE( g_pSRViewRenderer );
#endif
   SAFE_DELETE( g_pTranslucentShadowMaps );
   SAFE_DELETE( g_pFPS );
   SAFE_DELETE( g_pDebugFont );
   SAFE_DELETE( g_pMonkeyMesh );
   SAFE_DELETE( g_pDirect3D11 );
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch( msg )
   {
   case WM_KEYUP:
      // アプリ終了
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );
      else if( wParam == 'M' )
      {
         switch( g_Mode )
         {
         case 0:
            g_Mode = 1;
            break;
         case 1:
            g_Mode = 2;
            break;
         case 2:
            g_Mode = 0;
            break;
         }
      }
      break;

   case WM_DESTROY:
      ::PostQuitMessage(0);
      break;

   default:
      return ::DefWindowProc( hWnd, msg, wParam, lParam );
   }

   return 0L;
}

// Direct3Dの作成
void CreateDirect3D( HINSTANCE hInstance )
{
   DXGI_MODE_DESC* pModeDescArray = nullptr;

   __try
   {
      DXGI_MODE_DESC  ModeDesc;
      UINT num;

      // ディスプレイモード一覧の数を取得する
      g_pDirect3D11->GetDisplayMode( nullptr, &num );

      pModeDescArray = NEW DXGI_MODE_DESC[num];
      // ディスプレイモード一覧を取得する
      g_pDirect3D11->GetDisplayMode( pModeDescArray, &num );

      bool find = false;
      for( UINT i=0; i<num; i++ )
      {
         // 適切な解像度のディスプレイモードを検索する
         if( pModeDescArray[i].Width == g_Width && pModeDescArray[i].Height == g_Height )
         {
            find = true;
            ::CopyMemory( &ModeDesc, &pModeDescArray[i], sizeof( DXGI_MODE_DESC ) );
            break;
         }
      }

      if( find == false )
         throw( UException( -1, _T("InitDirect3D()でエラーが発生しました。適切なディスプレイモードの解像度を取得できません。") ) );

      // ウィンドウの作成およびDirect3D の作成
      g_pDirect3D11->CreateDirect3D11( AppName, hInstance, WndProc, &ModeDesc, TRUE, TRUE );

      g_pDebugFont->CreateMesh( g_pDirect3D11->m_pD3DDevice, 0.03f, 0.08f );

      // FPS描画クラス
      g_pFPS->CreateMesh( g_pDirect3D11->m_pD3DDevice );

#if defined(DEBUG) || defined(_DEBUG)
      g_pSRViewRenderer->Create( g_pDirect3D11->m_pD3DDevice, 1.0f - 400.0f / (float)g_Width, 1.0f, 1.0f, 1.0f - 400.0f / (float)g_Height );
#endif
   }
   __finally
   {
      SAFE_DELETE_ARRAY( pModeDescArray );
   }
}

void CreateGraphicePipeline()
{
   DWORD Width = 256, Height = 256;
   g_pTranslucentShadowMaps->Create( g_pDirect3D11->m_pD3DDevice, Width, Height );
}

// メッシュを作成する
void CreateMesh()
{
   g_pMonkeyMesh = NEW MonkeyMesh();
   g_pMonkeyMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice );
}

void CreateResource( HINSTANCE hInstance )
{
   // Direct3D 関連自作クラスのインスタンスを作成
   // CreateDirect3D()関数内でインスタンスの作成を行うと、C2712 エラーが発生するのでここで行う。
   g_pDirect3D11 = NEW UDirect3D11();

   g_pTranslucentShadowMaps = NEW TranslucentShadowMaps();

   g_pDebugFont = NEW UDebugFont();
   g_pFPS = NEW UFPS();

#if defined(DEBUG) || defined(_DEBUG)
   g_pSRViewRenderer = NEW USRViewRenderer();
#endif

   // Direct3Dの作成
   CreateDirect3D( hInstance );

   // グラフィックパイプラインリソースの作成
   CreateGraphicePipeline();

   // リソースの作成
   CreateMesh();
}

void NextFrame()
{
   // ビュー行列
   if( GetKeyState( VK_UP ) & 0x8000 )
      g_MatCameraView *= XMMatrixTranslation( 0, 0, -0.2f );
   if( GetKeyState( VK_DOWN ) & 0x8000 )
      g_MatCameraView *= XMMatrixTranslation( 0, 0, 0.2f );
   if( GetKeyState( VK_RIGHT ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationY( -0.002f );
   if( GetKeyState( VK_LEFT ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationY( 0.002f );
   if( GetKeyState( 'Q' ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationX( 0.002f );
   if( GetKeyState( 'A' ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationX( -0.002f );

#if defined(DEBUG) || defined(_DEBUG)
   switch( g_Mode )
   {
   case 0:
      g_pDebugFont->NextFrame( _T("M:Change Map Mode\nDepth Map Mode"), &XMFLOAT2( -0.97f, 0.86f ), &XMFLOAT4( 1, 1, 1, 1 ) );
      break;
   case 1:
      g_pDebugFont->NextFrame( _T("M:Change Map Mode\nTranslucent Map Mode"), &XMFLOAT2( -0.97f, 0.86f ), &XMFLOAT4( 1, 1, 1, 1 ) );
      break;
   case 2:
      g_pDebugFont->NextFrame( _T("M:Change Map Mode\nBlur Map Mode"), &XMFLOAT2( -0.97f, 0.86f ), &XMFLOAT4( 1, 1, 1, 1 ) );
      break;
   }
#endif

   g_pFPS->NextFrame();

   g_pMonkeyMesh->NextFrame();
}

// 描画処理
HRESULT Render()
{
   HRESULT hr = E_FAIL;
   
   static float ClearColor[4] = { 0.3f, 0.3f, 1.0f, 1.0f };

   // バックバッファをクリアする。
   g_pDirect3D11->ClearBackBuffer( ClearColor ); 

   // 深度バッファをクリアする。
   g_pDirect3D11->ClearDepthStencilView( D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

   for( UINT i=0; i<g_pTranslucentShadowMaps->GetMaxPass(); i++ )
   {
      g_pTranslucentShadowMaps->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, i, &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj );

      g_pTranslucentShadowMaps->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pMonkeyMesh->GetMatWorld() );
      g_pMonkeyMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );

      g_pTranslucentShadowMaps->EndPass( g_pDirect3D11->m_pD3DDeviceContext );
   }

#if defined(DEBUG) || defined(_DEBUG)
   int SrvRGB[] = { 0, 0, 0, 0 };
   
   switch( g_Mode )
   {
   case 0:
      g_pSRViewRenderer->SetSRView( g_pTranslucentShadowMaps->GetDepthMap(), SrvRGB );
      break;
   case 1:
      g_pSRViewRenderer->SetSRView( g_pTranslucentShadowMaps->GetTranslucentMap(), SrvRGB );
      break;
   case 2:
      g_pSRViewRenderer->SetSRView( g_pTranslucentShadowMaps->GetBlurMap(), SrvRGB );
      break;
   }
   g_pSRViewRenderer->Render( g_pDirect3D11->m_pD3DDeviceContext );

   g_pDebugFont->Render( g_pDirect3D11->m_pD3DDeviceContext );
#endif

   g_pFPS->Render( g_pDirect3D11->m_pD3DDeviceContext );

   // レンダリングされたイメージをユーザーに表示。
   if( FAILED( hr = g_pDirect3D11->Present( 0, 0 ) ) )
      throw( UException( hr, _T("IDXGISwapChain::Present()が失敗しました") ) );

   return hr;
}
 
// メイン関数
int APIENTRY _tWinMain( HINSTANCE hInstance,
                        HINSTANCE,
                        LPTSTR,
                        INT )
{
   // メモリリーク検出
//   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | CRTDBG_CHECK_ALWAYS_DF );
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF );

   MSG msg = {0};

   try
   {
      CreateResource( hInstance );

      ::ShowWindow( g_pDirect3D11->m_hWnd, SW_SHOW );
      ::UpdateWindow( g_pDirect3D11->m_hWnd );

      // メッセージループ
      do
      { 
         if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
         {
            ::TranslateMessage(&msg); 
            ::DispatchMessage(&msg); 
         }
         else
         {
            NextFrame();
            Render();
         }
      }while( msg.message != WM_QUIT );
   }
   catch( UException ex )
   {
      ::MessageBox( nullptr, ex.m_pErrorStr, _T("エラー"), MB_OK );
   }

   Invalidate();

   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

今回メッシュを差し替えようかと思ったのですが、うまく動きませんでした。
xmlファイルの解析が間違っているのですが、修正するのはつらいな。


web拍手 by FC2

Prev Top Next

inserted by FC2 system