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

■Direct3D11 Percentage-Closer Soft Shadows Prev Top Next
関連ページ:Direct3D11 自作ライブラリ


今回はPercentage-Closer Soft Shadowsというものをやりますが、品質、パフォーマンスともに微妙です。
ぶっちゃけもんしょさんのところで既に公開されているので、そちらを参考にしたほうがいいでしょう。
もんしょさんのところと微妙に違いますが、基本的に同じことをやっているはずです。ソースちゃんと見てないですが。

また例によって、参考にした英語論文のURLはこことかこことかです。

Percentage-Closer Soft Shadowsとはソフトシャドウの一種です。
当サイトで既出のソフトシャドウの場合、一様にぼかしがかかりますが、本来光を遮るメッシュと影が落ちるメッシュの距離によりぼけ具合や影濃度は変わるはず、
というのが基本的な考え方です。

次にアルゴリズムについて簡単に説明します。

1.ライトビューで深度マップ作成
 いつものやつです。

2.カメラビューでBlockerの平均値計算
 ここでは Blocker つまり深度マップの平均値を計算します。  Receiver つまり描画地点までの距離が遠いほど、またパラメータであるライトサイズが大きくなるほど強くぼけるようにします。
 平均値を計算するのは影となる領域( Receiver > Blocker となる領域 )を拡張するためです。
 ここで出力したマップは後の処理で必要となるサンプリング回数の計算で必要となります。

 また何度もカメラビューでのジオメトリ処理を行わないようにするために、レンダリングで必要となるカラーマップ、法線マップそしてシャドウマップもあわせて出力しておきます。
 シャドウマップは、 Receiver - Blocker の距離を出力します。これにより影の濃度を調整します。

3.半影マップ作成
 半影マップとは要するにサンプリング回数を書き込んだマップです。若干変形してますが計算式はリンク先PDFの通りです。

4.最終レンダリング
 2で作成したマップを使用して、ライティングを行います。いわゆる Deferred Rendering です。
 また半影マップによりぼかし処理のサンプリング範囲を決定し、シャドウマップをぼかしてソフトシャドウを生成します。

以上です。Blockerの平均値計算とシャドウマップのぼかし処理でループ処理を行うため、非常に重い処理となります。これ本当にあってるんだろうか?


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

Aシェーダー系で使用するソースです。
PercentageCloserSoftShadows_Pass0.hlsl ライトビューで深度マップ作成するシェーダーソース
PercentageCloserSoftShadows_Pass1.hlsl カメラビューでBlockerの平均値計算するシェーダーソース
PercentageCloserSoftShadows_Pass2.hlsl 半影マップ作成するシェーダーソース
PercentageCloserSoftShadows_Pass3.hlsl 最終レンダリングするシェーダーソース
PercentageCloserSoftShadows.h PercentageCloserSoftShadowsクラスのヘッダーファイル
PercentageCloserSoftShadows.cpp PercentageCloserSoftShadowsクラスのソースファイル

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


---PercentageCloserSoftShadows_Pass0.hlsl---  ↑

// ************************************************************
// Percentage Closer Soft Shadows    深度マップ作成
// ************************************************************

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

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

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

// 頂点シェーダー
VS_OUT_PS_IN PercentageCloserSoftShadows_Pass0_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;
   Out.pos = mul( float4( In.pos, 1 ), g_matLightWorldViewProj );
   Out.posWVP = Out.pos;
   
   return Out;
}

// ピクセルシェーダ
float PercentageCloserSoftShadows_Pass0_PS_Main( VS_OUT_PS_IN In ) : SV_DEPTH
{
   return In.posWVP.z / g_LightZFar;
}

---PercentageCloserSoftShadows_Pass1.hlsl---  ↑


// ************************************************************************************************************************
// Percentage Closer Soft Shadows   Pass1   カメラビューでカラーマップ出力、法線マップ出力、シャドウマップ生成、および blocker 平均値計算
// ************************************************************************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj  : packoffset( c0 );    // ライトビューのワールドビュー射影行列
   column_major float4x4 g_matCameraWorldViewProj  : packoffset( c4 );    // カメラビューのワールドビュー射影行列
   column_major float4x4 g_matCameraWorld    : packoffset( c8 );    // カメラビューのワールド行列
   float g_LightZFar                    : packoffset( c12.x );
   float g_LightSize                : packoffset( c12.y );
   float2 g_TexelSize               : packoffset( c12.z );
};

Texture2D g_DecalMap : register( t0 );
Texture2D g_DepthMap : register( t1 );

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

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

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

// ピクセルシェーダーの出力パラメータ
struct VS_IN_PS_OUT
{
   float4 ColorMap    : SV_TARGET0;
   float4 NormalMap   : SV_TARGET1;
   float2 DistanceMap : SV_TARGET2;
};

// 頂点シェーダー
VS_OUT_PS_IN PercentageCloserSoftShadows_Pass1_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;
   Out.pos = mul( float4( In.pos, 1 ), g_matCameraWorldViewProj );
   Out.posLWVP = mul( float4( In.pos, 1 ), g_matLightWorldViewProj );
   Out.normal = mul( In.normal, (float3x3)g_matCameraWorld );
   Out.texel = In.texel;
   
   return Out;
}

// ピクセルシェーダ
VS_IN_PS_OUT PercentageCloserSoftShadows_Pass1_PS_Main( VS_OUT_PS_IN In )
{
   VS_IN_PS_OUT Out = (VS_IN_PS_OUT)0;
      
   float2 texel = In.posLWVP.xy / In.posLWVP.w * float2( 0.5f, -0.5f ) + 0.5f;

   // 深度マップから深度値を取得
   float dBlocker = g_DepthMap.Sample( g_SamplerDepthMap, texel ).r;
   
   float bias = 0.0001f;
   
   float z = In.posLWVP.z / g_LightZFar - bias;
   
   // receiverまでの距離とライトサイズをもとにループ回数を計算
   int region = z * g_LightSize;
   float avsBlocker = 0;
   float count = 0;

   [unroll(7)] for( int i=-region; i<=region; i+=2 )
   {
      [unroll(7)] for( int j=-region; j<=region; j+=2 )
      {
         // 描画地点の周辺位置のblockerの深度値を取得
         float b = g_DepthMap.Sample( g_SamplerDepthMap, texel + float2( i, j ) * g_TexelSize ).r;
         
         // 描画地点よりライトの手前方向にblockerがある場合、blockerの深度値の合計値を計算する
         if( z > b )
         {
            avsBlocker += b;
            count++;
         }
      }
   }
   
   // blockerの深度値の平均値を計算する
   if( count > 0 )
      avsBlocker /= count;
   else
      avsBlocker = 1;
   
   // シャドウマップ作成
   float shadowMap = z - dBlocker;
   if( shadowMap < 0 )
      shadowMap = 1;
      
   Out.ColorMap = g_DecalMap.Sample( g_SamplerDecalMap, In.texel );
   Out.NormalMap = float4( normalize( In.normal ), shadowMap );
   Out.DistanceMap = float2( z, avsBlocker );
      
   return Out;
}

---PercentageCloserSoftShadows_Pass2.hlsl---  ↑


// ************************************************************
// Percentage Closer Soft Shadows   Pass2    半影マップ出力
// ************************************************************

// 距離マップ
Texture2D g_DistanceMap : register( t0 );

// サンプラーステート
SamplerState g_DistanceMapSampler : register( s0 );

// 頂点シェーダーの入力パラメータ
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 PercentageCloserSoftShadows_Pass2_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;
   Out.pos = float4( In.pos, 1 );
   Out.texel = In.texel;
   return Out;
}

// ピクセルシェーダ
float PercentageCloserSoftShadows_Pass2_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   // r : receiverの深度値、g : 平均化されたblockerの深度値
   float2 col = g_DistanceMap.Sample( g_DistanceMapSampler, In.texel ).rg;

   // 後で処理するPCFのループ数を出力
   // 論文と異なり Light Size は無視
   return clamp( ( col.r - col.g ) / col.g, 0, 1 );
}

---PercentageCloserSoftShadows_Pass3.hlsl---  ↑


// ************************************************************
// Percentage Closer Soft Shadows   Pass3   最終レンダリング
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   float4 g_vecLightPos         : packoffset( c0 );    // ローカル座標系での平行光源の位置ベクトル
   float2 g_TexelSize           : packoffset( c1 );
};

// カラーマップ
Texture2D g_ColorMap : register( t0 );

// 法線マップ( アルファチャンネルはシャドウマップとする )
Texture2D g_NormalMap : register( t1 );

// 半影マップ
Texture2D g_PenumbraMap : register( t2 );

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

// 頂点シェーダーの入力パラメータ
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 PercentageCloserSoftShadows_Pass3_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;
   Out.pos = float4( In.pos, 1 );
   Out.texel = In.texel;
   return Out;
}

// ピクセルシェーダ
float4 PercentageCloserSoftShadows_Pass3_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   // 各種マップ値取得
   float4 ColorMap = g_ColorMap.Sample( g_Sampler, In.texel );
   float3 NormalMap = g_NormalMap.Sample( g_Sampler, In.texel ).rgb;

   // 強くぼかすためにあえて Light Size 無視してとりあえず定数値
   float region = g_PenumbraMap.Sample( g_Sampler, In.texel ).r * 16.0f;
   
   // ハーフランバート
   float lambert = dot( normalize( g_vecLightPos.xyz ), NormalMap );
   lambert = lambert * 0.5f + 0.5f;
   
   float count = 0;
   float shadowMap = 0;

   [unroll(17)]
   for( int i=-region; i<=region; i+=2 )
   {
      [unroll(17)]
      for( int j=-region; j<=region; j+=2 )
      {
         // シャドウマップ値取得
         shadowMap += g_NormalMap.Sample( g_Sampler, In.texel + float2( i, j ) * g_TexelSize ).a;
         count++;
      }
   }

   // 平均値計算
   shadowMap /= count;
   
   // 色計算
   ColorMap *= max( lambert * shadowMap, 0.3f );
         
   return ColorMap.bgra;
}

---PercentageCloserSoftShadows.h---  ↑

#ifndef PERCENTAGE_CLOSER_SOFT_SHADOWS_H
#define PERCENTAGE_CLOSER_SOFT_SHADOWS_H

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

class PercentageCloserSoftShadows
{
private:
   // Deferred Rendering するときに使用する頂点定義
   typedef struct _VERTEX
   {
      XMFLOAT3 pos;     // 頂点の座標
      XMFLOAT2 texel;   // テクセル座標
   }VERTEX;

   // Deferred Rendering で使用する頂点バッファ
   ID3D11Buffer* m_pVertexBuffer;

   // ライトビューで深度マップ作成
   typedef struct _CBUFFER_PASS0
   {
      XMMATRIX matLightWorldViewProj;
      float LightZFar;
      float Dummy1;
      float Dummy2;
      float Dummy3;
   }CBUFFER_PASS0;

   // カメラビューでカラーマップ出力、法線マップ出力、シャドウマップ生成、および blocker 平均値計算
   typedef struct _CBUFFER_PASS1
   {
      XMMATRIX matLightWorldViewProj;
      XMMATRIX matCameraWorldViewProj;
      XMMATRIX matWorld;
      float LightZFar;
      float LightSize;
      XMFLOAT2 TexelSize;
   }CBUFFER_PASS1;

   // 半影マップ作成( ここでは定数バッファなし )

   // 最終レンダリング
   typedef struct _CBUFFER_PASS3
   {
      XMFLOAT4 vecLightDir;
      XMFLOAT2 TexelSize;
      float Dummy3;
      float Dummy4;
   }CBUFFER_PASS3;

   // ライトビュー空間上の深度マップ
   ID3D11DepthStencilView* m_pDSViewOfLightViewDepthMap;
   ID3D11ShaderResourceView* m_pSRViewOfLightViewDepthMap;

   // カラーマップ
   ID3D11RenderTargetView* m_pRTViewOfColorMap;
   ID3D11ShaderResourceView* m_pSRViewOfColorMap;

   // カメラビュー空間上の深度マップ、深度テストのみで参照しない
   ID3D11DepthStencilView* m_pDSViewOfCameraViewDepthMap;

   // 法線マップ、アルファチャンネルはシャドウマップ
   ID3D11RenderTargetView* m_pRTViewOfNormalMap;
   ID3D11ShaderResourceView* m_pSRViewOfNormalMap;

   // 距離マップ
   ID3D11RenderTargetView* m_pRTViewOfDistanceMap;
   ID3D11ShaderResourceView* m_pSRViewOfDistanceMap;

   // 半影マップ
   ID3D11RenderTargetView* m_pRTViewOfPenumbraMap;
   ID3D11ShaderResourceView* m_pSRViewOfPenumbraMap;

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

   // レンダーターゲットと深度ステンシルとビューポートのバックアップ
   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[4];

   UGraphicsPipeline* m_pGraphicsPipeline[4];

   float m_LightZFar;
   float m_LightSize;
   DWORD m_LightViewWidth, m_LightViewHeight, m_CameraViewWidth, m_CameraViewHeight;

   XMMATRIX m_MatCameraView;
   XMMATRIX m_MatCameraProj;
   XMMATRIX m_MatLightProj;
   XMFLOAT4 m_VecLightPos;
   int m_Pass;

public:
   PercentageCloserSoftShadows();
   virtual ~PercentageCloserSoftShadows();
   void Invalidate();
   void Create( ID3D11Device* pD3DDevice, DWORD LightViewWidth, DWORD LightViewHeight, DWORD CameraViewWidth, DWORD CameraViewHeight );
   inline UINT GetMaxPass(){ return 2; };
   void Begin( XMFLOAT4* pVecLightPos, XMMATRIX* pMatCameraProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatLightProj, float LightZFar, float m_LightSize );
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass );
   void SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld );
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
   void End();
   inline const ID3D11ShaderResourceView* GetLightViewDepthMap(){ return m_pSRViewOfLightViewDepthMap; };
   inline const ID3D11ShaderResourceView* GetColorMap(){ return m_pSRViewOfColorMap; };
   inline const ID3D11ShaderResourceView* GetNormalMap(){ return m_pSRViewOfNormalMap; };
   inline const ID3D11ShaderResourceView* GetDistanceMap(){ return m_pSRViewOfDistanceMap; };
   inline const ID3D11ShaderResourceView* GetPenumbraMap(){ return m_pSRViewOfPenumbraMap; };
};
#endif

---PercentageCloserSoftShadows.cpp---  ↑


#include "../../Header/Shader/PercentageCloserSoftShadows.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass0_VS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass0_PS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass1_VS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass1_PS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass2_VS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass2_PS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass3_VS_Main.h"
#include "../../HLSL/PercentageCloserSoftShadows_Pass3_PS_Main.h"

PercentageCloserSoftShadows::PercentageCloserSoftShadows()
{
   m_pVertexBuffer = nullptr;

   m_pDSViewOfLightViewDepthMap = nullptr;
   m_pSRViewOfLightViewDepthMap = nullptr;

   m_pRTViewOfColorMap = nullptr;
   m_pSRViewOfColorMap = nullptr;
   m_pRTViewOfNormalMap = nullptr;
   m_pSRViewOfNormalMap = nullptr;
   m_pDSViewOfCameraViewDepthMap = nullptr;
   m_pRTViewOfDistanceMap = nullptr;
   m_pSRViewOfDistanceMap = nullptr;

   m_pRTViewOfPenumbraMap = nullptr;
   m_pSRViewOfPenumbraMap = nullptr;

   for( int i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      m_pGraphicsPipeline[i] = nullptr;
      m_pConstantBuffers[i] = nullptr;
   }
   m_pSamplerState = nullptr;

   m_Pass = -2;
}

PercentageCloserSoftShadows::~PercentageCloserSoftShadows()
{
   SAFE_RELEASE( m_pSamplerState );
   for( int i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      SAFE_DELETE( m_pGraphicsPipeline[i] );
      SAFE_RELEASE( m_pConstantBuffers[i] );
   }

   SAFE_RELEASE( m_pSRViewOfPenumbraMap );
   SAFE_RELEASE( m_pRTViewOfPenumbraMap );

   SAFE_RELEASE( m_pSRViewOfDistanceMap );
   SAFE_RELEASE( m_pRTViewOfDistanceMap );
   SAFE_RELEASE( m_pSRViewOfNormalMap );
   SAFE_RELEASE( m_pRTViewOfNormalMap );
   SAFE_RELEASE( m_pDSViewOfCameraViewDepthMap );
   SAFE_RELEASE( m_pSRViewOfColorMap );
   SAFE_RELEASE( m_pRTViewOfColorMap );

   SAFE_RELEASE( m_pSRViewOfLightViewDepthMap );
   SAFE_RELEASE( m_pDSViewOfLightViewDepthMap );

   SAFE_RELEASE( m_pVertexBuffer );
}

void PercentageCloserSoftShadows::Create( ID3D11Device* pD3DDevice, DWORD LightViewWidth, DWORD LightViewHeight, DWORD CameraViewWidth, DWORD CameraViewHeight )
{
   m_LightViewWidth = LightViewWidth;
   m_LightViewHeight = LightViewHeight;
   m_CameraViewWidth = CameraViewWidth;
   m_CameraViewHeight = CameraViewHeight;

   m_Pass = -2;

   // *******************************************************************************************************
   // ライトビューで深度マップ作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[0] = NEW UGraphicsPipeline();

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

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

   // ブレンドステートを作成する
   UGraphicsPipeline::UEBLEND_STATE BlendStateType0123[1] = { UGraphicsPipeline::UEBLEND_STATE::NONE };
   m_pGraphicsPipeline[0]->CreateBlendState( pD3DDevice, BlendStateType0123, 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/PercentageCloserSoftShadows_Pass0.hlsl"), "PercentageCloserSoftShadows_Pass0_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/PercentageCloserSoftShadows_Pass0.hlsl"), "PercentageCloserSoftShadows_Pass0_PS_Main" );
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass0_VS_Main, sizeof( g_PercentageCloserSoftShadows_Pass0_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass0_PS_Main, sizeof( g_PercentageCloserSoftShadows_Pass0_PS_Main ) );
#endif
 
   // 深度ステンシルバッファを作成する
   UMaps::CreateDepthStencilView( pD3DDevice, m_LightViewWidth, m_LightViewHeight, &m_pDSViewOfLightViewDepthMap, &m_pSRViewOfLightViewDepthMap );

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

   // *******************************************************************************************************
   // カメラビューでカラーマップ出力、法線マップ出力、シャドウマップ生成、および blocker 平均値計算
   // *******************************************************************************************************

   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 );

   // ブレンドステートを作成する
   m_pGraphicsPipeline[1]->CreateBlendState( pD3DDevice, BlendStateType0123, 1 );

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

   // カラーマップを作成する
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R8G8B8A8_UNORM, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfColorMap, &m_pSRViewOfColorMap );

   // 深度ステンシルバッファを作成する
   UMaps::CreateDepthStencilView( pD3DDevice, m_CameraViewWidth, m_CameraViewHeight, &m_pDSViewOfCameraViewDepthMap, nullptr );

   // 法線マップを作成する( アルファチャンネルはシャドウマップとする )
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R16G16B16A16_FLOAT, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfNormalMap, &m_pSRViewOfNormalMap );

   // 距離マップを作成する
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R32G32_FLOAT, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfDistanceMap, &m_pSRViewOfDistanceMap );

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

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

   // *******************************************************************************************************
   // 半影マップ作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[2] = NEW UGraphicsPipeline();

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

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

   // ブレンドステートを作成する
   m_pGraphicsPipeline[2]->CreateBlendState( pD3DDevice, BlendStateType0123, 1 );

   D3D11_INPUT_ELEMENT_DESC layout23[] = {
         { "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 },
   };

   // 頂点のデータ
   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 );

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[2]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/PercentageCloserSoftShadows_Pass2.hlsl"), "PercentageCloserSoftShadows_Pass2_VS_Main", layout23, _countof( layout23 ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/PercentageCloserSoftShadows_Pass2.hlsl"), "PercentageCloserSoftShadows_Pass2_PS_Main" );
#else
   m_pGraphicsPipeline[2]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass2_VS_Main, sizeof( g_PercentageCloserSoftShadows_Pass2_VS_Main ), layout23, _countof( layout23 ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass2_PS_Main, sizeof( g_PercentageCloserSoftShadows_Pass2_PS_Main ) );
#endif

   // 半影マップを作成する
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R32_FLOAT, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfPenumbraMap, &m_pSRViewOfPenumbraMap );

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

   // *******************************************************************************************************
   // 最終レンダリング
   // *******************************************************************************************************

   m_pGraphicsPipeline[3] = NEW UGraphicsPipeline();

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

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

   // ブレンドステートを作成する
   m_pGraphicsPipeline[3]->CreateBlendState( pD3DDevice, BlendStateType0123, 1 );

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[3]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/PercentageCloserSoftShadows_Pass3.hlsl"), "PercentageCloserSoftShadows_Pass3_VS_Main", layout23, _countof( layout23 ) );
   m_pGraphicsPipeline[3]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/PercentageCloserSoftShadows_Pass3.hlsl"), "PercentageCloserSoftShadows_Pass3_PS_Main" );
#else
   m_pGraphicsPipeline[3]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass3_VS_Main, sizeof( g_PercentageCloserSoftShadows_Pass3_VS_Main ), layout23, _countof( layout23 ) );
   m_pGraphicsPipeline[3]->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_PercentageCloserSoftShadows_Pass3_PS_Main, sizeof( g_PercentageCloserSoftShadows_Pass3_PS_Main ) );
#endif

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

void PercentageCloserSoftShadows::Begin( XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj, float LightZFar, float LightSize )
{
   if (m_Pass != -2)
   {
      throw(UException(-1, _T("PercentageCloserSoftShadows::Begin()はCreate()またはEnd()実行後に使用してください")));
   }

   if( LightSize < 0.0f )
      throw( UException( -1, _T("PercentageCloserSoftShadows;;Begin()でエラーが発生しました。LightSizeが不正値です。") ) );

   m_MatCameraView = *pMatCameraView;
   m_MatCameraProj = *pMatCameraProj;
   m_MatLightProj = *pMatLightProj;
   m_VecLightPos = *pVecLightPos;
   m_LightZFar = LightZFar;
   m_LightSize = LightSize;

   m_Pass = -1;
}

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

   m_Pass = (int)Pass;

   switch( m_Pass )
   {
   // *******************************************************************************************************
   // ライトビューで深度マップ作成
   // *******************************************************************************************************
   case 0:
      {
         // 現在デバイスに設定されているレンダーターゲットビューと深度ステンシルビューとビューポートを退避
         pD3DDeviceContext->OMGetRenderTargets( _countof( m_pOldRTView ), m_pOldRTView, &m_pOldDSView );
         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, nullptr );
         pD3DDeviceContext->RSGetViewports( &m_ViewportCount, &m_pOldViewport[0] );

         pD3DDeviceContext->OMSetRenderTargets( 0, nullptr, m_pDSViewOfLightViewDepthMap );

         D3D11_VIEWPORT Viewport[1];
         Viewport[0].TopLeftX = 0;
         Viewport[0].TopLeftY = 0;
         Viewport[0].Width    = (FLOAT)m_LightViewWidth;
         Viewport[0].Height   = (FLOAT)m_LightViewHeight;
         Viewport[0].MinDepth = 0.0f;
         Viewport[0].MaxDepth = 1.0f;
         pD3DDeviceContext->RSSetViewports( 1, Viewport );

         pD3DDeviceContext->ClearDepthStencilView( m_pDSViewOfLightViewDepthMap, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
      }
      break;

   // *******************************************************************************************************
   // カメラビューでカラーマップ出力、法線マップ出力、シャドウマップ生成、および blocker 平均値計算
   // *******************************************************************************************************
   case 1:
      {
         ID3D11RenderTargetView* pRTView[] = { m_pRTViewOfColorMap, m_pRTViewOfNormalMap, m_pRTViewOfDistanceMap };
         pD3DDeviceContext->OMSetRenderTargets( _countof( pRTView ), pRTView, m_pDSViewOfCameraViewDepthMap );

         float ClearWhite[] = { 1, 1, 1, 1 };
         float ClearBlack[] = { 0, 0, 0, 0 };

         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfColorMap, ClearBlack );
         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfNormalMap, ClearBlack );
         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfDistanceMap, ClearWhite );
         pD3DDeviceContext->ClearDepthStencilView( m_pDSViewOfCameraViewDepthMap, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

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

         // ビューポートを戻す
         pD3DDeviceContext->RSSetViewports( m_ViewportCount, m_pOldViewport );
      }
      break;
   default:
      throw(UException(-1, _T("PercentageCloserSoftShadows::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 PercentageCloserSoftShadows::SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld )
{
   HRESULT hr = E_FAIL;

   switch( m_Pass )
   {
   // *******************************************************************************************************
   // ライトビューで深度マップ作成
   // *******************************************************************************************************
   case 0:
      {
         // ライトビューのビュー行列を作成
         XMMATRIX matLView = XMMatrixLookAtLH( XMLoadFloat3( (XMFLOAT3*)&m_VecLightPos ), XMLoadFloat3( &XMFLOAT3( 0, 0, 0 ) ), XMLoadFloat3( &XMFLOAT3( 0, 1, 0 ) ) );

         // ライトビューのワールド行列とビュー行列と射影行列
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose( *pMatWorld * matLView * 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("PercentageCloserSoftShadows::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         PercentageCloserSoftShadows::CBUFFER_PASS0* cbuffer = (PercentageCloserSoftShadows::CBUFFER_PASS0*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof( XMMATRIX ));
         cbuffer->LightZFar = m_LightZFar;
         pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
         pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );
      }
      break;

   // *******************************************************************************************************
   // カメラビューでカラーマップ出力、法線マップ出力、シャドウマップ生成、および blocker 平均値計算
   // *******************************************************************************************************
   case 1:
      {
         // ライトビューのビュー行列を作成
         XMMATRIX matLView = XMMatrixLookAtLH( XMLoadFloat3( (XMFLOAT3*)&m_VecLightPos ), XMLoadFloat3( &XMFLOAT3( 0, 0, 0 ) ), XMLoadFloat3( &XMFLOAT3( 0, 1, 0 ) ) );

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

         // カメラビューのワールド行列とビュー行列と射影行列
         XMMATRIX matCameraWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatCameraView * m_MatCameraProj );

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

         // 定数バッファを設定する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("PercentageCloserSoftShadows::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         PercentageCloserSoftShadows::CBUFFER_PASS1* cbuffer = (PercentageCloserSoftShadows::CBUFFER_PASS1*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof( XMMATRIX ));
         ::CopyMemory( &cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof( XMMATRIX ));
         ::CopyMemory( &cbuffer->matWorld, &matWorld, sizeof( XMMATRIX ));
         cbuffer->LightZFar = m_LightZFar;
         cbuffer->LightSize = m_LightSize;
         cbuffer->TexelSize = XMFLOAT2( 1.0f / (float)m_LightViewWidth, 1.0f / (float)m_LightViewHeight );
         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 PercentageCloserSoftShadows::EndPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   HRESULT hr = E_FAIL;

   switch( m_Pass )
   {
   case 0:
      {
      }
      break;

   case 1:
      {
         D3D11_MAPPED_SUBRESOURCE mappedResource;

         m_Pass++;

         // *******************************************************************************************************
         // 半影マップ作成
         // *******************************************************************************************************

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

         float ClearColor[] = { 0, 0, 0, 0 };
         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfPenumbraMap, ClearColor );

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

         // 各種ステートを設定する
         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 );

         //// 定数バッファを設定する
         //if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
         //   throw( UException( -1, _T("PercentageCloserSoftShadows::EndPass()でエラーが発生しました。Map()が失敗しました。") ) );
         //PercentageCloserSoftShadows::CBUFFER_PASS2* cbuffer2 = (PercentageCloserSoftShadows::CBUFFER_PASS2*)mappedResource.pData;
         //cbuffer2->LightSize = m_LightSize;
         //pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         //pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );

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

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

         // 描画
         pD3DDeviceContext->Draw( 4, 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 ); 

         m_Pass++;

         // *******************************************************************************************************
         // 最終レンダリング
         // *******************************************************************************************************

         // 各種シェーダーリソースをセット
         ID3D11ShaderResourceView* pSRView[] = { m_pSRViewOfColorMap, m_pSRViewOfNormalMap, m_pSRViewOfPenumbraMap };
         pD3DDeviceContext->PSSetShaderResources( 0, _countof( pSRView ), pSRView );

         pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

         // 各種ステートを設定する
         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 );

         // 定数バッファを設定する
//         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("PercentageCloserSoftShadows::EndPass()でエラーが発生しました。Map()が失敗しました。") ) );
         PercentageCloserSoftShadows::CBUFFER_PASS3* cbuffer3 = (PercentageCloserSoftShadows::CBUFFER_PASS3*)mappedResource.pData;
         ::CopyMemory( &cbuffer3->vecLightDir, &m_VecLightPos, sizeof( XMFLOAT4 ));
         cbuffer3->TexelSize = XMFLOAT2( 1.0f / (float)m_CameraViewWidth, 1.0f / (float)m_CameraViewHeight );
         pD3DDeviceContext->Unmap( m_pConstantBuffers[m_Pass], 0 );

         pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[m_Pass] );

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

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

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

         ID3D11ShaderResourceView* pNull[] = { nullptr, nullptr, nullptr };
         pD3DDeviceContext->PSSetShaderResources( 0, _countof( pNull ), pNull );
      }
      break;
   }

   m_Pass = -1;
}

void PercentageCloserSoftShadows::End()
{
   m_Pass = -2;
}

---BackGroundMesh.h---  ↑


#ifndef BACKGROUNDMESH_H
#define BACKGROUNDMESH_H

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

class BackGroundMesh
{
private:
   ID3D11Buffer* m_pVertexBuffer;

   ID3D11ShaderResourceView* m_pSRView;

   ID3D11SamplerState* m_pSamplerState;

   UD3DMeshDataCreater m_MeshDataCreater;

   XMMATRIX m_MatWorld;

   float m_RotationY;

   UD3DMeshDataCreater::VERTEX* m_pVertex;
   ULONG m_VertexCount;

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

#endif

---BackGroundMesh.cpp---  ↑


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

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

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

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

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

   UINT MeshIndex = 0;

   m_RotationY = 0.0f;

   m_MeshDataCreater.GetVertexes(MeshIndex, &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, m_MeshDataCreater.GetTextureFileName(MeshIndex).data(), &m_pSRView);

   SAFE_DELETE_ARRAY(m_pVertex);
}

void BackGroundMesh::NextFrame()
{
   m_RotationY += 0.001f;
   if (m_RotationY > XM_2PI)
      m_RotationY -= XM_2PI;

   m_MatWorld = XMMatrixRotationY(m_RotationY) * XMMatrixTranslation(0, -20.0f, 0);
}

void BackGroundMesh::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);
}

---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/PercentageCloserSoftShadows.h"
#include "../Header/Mesh/BackGroundMesh.h"

// アプリケーション名
TCHAR* AppName = _T("Direct3D11 Percentage Closer Soft Shadows");

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

PercentageCloserSoftShadows* g_pPercentageCloserSoftShadows = nullptr;

BackGroundMesh* g_pBackGroundMesh = nullptr;

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

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

DWORD g_Width = 640, g_Height = 480;
DWORD g_LightViewWidth = 512, g_LightViewHeight = 512;
float g_CameraZFar = 2500.0f, g_CameraZNear = 10.0f;
float g_LightZFar = 2800.0f, g_LZNear = 1300.0f;

float g_LightSize = 6;

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

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

// ライトビュー射影行列
XMMATRIX g_MatLightProj = XMMatrixPerspectiveFovLH( XM_PI / 5.0f, (float)g_LightViewWidth / (float)g_LightViewHeight, g_LZNear, g_LightZFar );

// 平行光源の位置ベクトル
XMFLOAT4 g_VecLightPos = XMFLOAT4(-900.0f, 1500.0f, 1200.0f, 0);

// メモリ解放
void Invalidate()
{
#if defined(DEBUG) || defined(_DEBUG)
   SAFE_DELETE( g_pSRViewRenderer );
#endif

   SAFE_DELETE( g_pDebugFont );
   SAFE_DELETE( g_pFPS );
   SAFE_DELETE( g_pPercentageCloserSoftShadows );
   SAFE_DELETE( g_pBackGroundMesh );
   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 );
      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 );

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

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

#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()
{
   g_pPercentageCloserSoftShadows->Create( g_pDirect3D11->m_pD3DDevice, g_LightViewWidth, g_LightViewHeight, g_Width, g_Height );
}

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

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

   g_pPercentageCloserSoftShadows = NEW PercentageCloserSoftShadows();

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

#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, -1.5f );
   if( GetKeyState( VK_DOWN ) & 0x8000 )
      g_MatCameraView *= XMMatrixTranslation( 0, 0, 1.5f );
   if( GetKeyState( VK_RIGHT ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationY( -0.014f );
   if( GetKeyState( VK_LEFT ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationY( 0.014f );
   if( GetKeyState( 'Q' ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationX( 0.014f );
   if( GetKeyState( 'A' ) & 0x8000 )
      g_MatCameraView *= XMMatrixRotationX( -0.014f );

   if( GetKeyState( 'V' ) & 0x8000 )
   {
      g_LightSize -= 0.1f;
      if( g_LightSize < 0.0f )
         g_LightSize = 0.0f;
   }
   else if( GetKeyState( 'B' ) & 0x8000 )
   {
      g_LightSize += 0.1f;
   }

   g_pFPS->NextFrame();

   TCHAR str[100];
   _stprintf_s(str, _T("%f\nV:LightSize Up\nB:Light Down"), g_LightSize);
   g_pDebugFont->NextFrame( str, &XMFLOAT2( -0.97f, 0.86f ), &XMFLOAT4( 1, 1, 1, 1 ) );

   g_pBackGroundMesh->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 );

   // PCSS開始
   g_pPercentageCloserSoftShadows->Begin( &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj, g_LightZFar, g_LightSize );
   {
      for( UINT i=0; i<g_pPercentageCloserSoftShadows->GetMaxPass(); i++ )
      {
         // ライトビューでシーンの深度値取得
         g_pPercentageCloserSoftShadows->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, i );
         {
            g_pPercentageCloserSoftShadows->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pBackGroundMesh->GetMatWorld() );
            g_pBackGroundMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
         }g_pPercentageCloserSoftShadows->EndPass( g_pDirect3D11->m_pD3DDeviceContext );
      }
   }g_pPercentageCloserSoftShadows->End();

#if defined(DEBUG) || defined(_DEBUG)
   int SrcRGB[4] = { 0, 1, 2, 0 };
   g_pSRViewRenderer->SetSRView( g_pPercentageCloserSoftShadows->GetPenumbraMap(), SrcRGB );
   g_pSRViewRenderer->Render( g_pDirect3D11->m_pD3DDeviceContext );
#endif

   g_pFPS->Render( g_pDirect3D11->m_pD3DDeviceContext );

   g_pDebugFont->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;
}

今回でシャドウマップを使用したシェーダーサンプル作成はいったん終了です。
ですが、シャドウマップ系エフェクトは非常に多くのアルゴリズムが提案されている奥の深いエフェクトでして、当サイトで紹介したものはほんの一部でしかありません。
比較的簡単に実装できるもの、シャドウマップを使用したエフェクトを選択して紹介していきましたが、
本当はシャドウマップそのものをシーンに合わせて適応的に作成する処理を実装することのほうが品質に大きく影響するため重要だったりします。
この辺は非常に面倒なのであえて避けましたが、その気になったらやっていきたいなと思ってます。できるかわからないけど。

さて、次回からというか来年からは PlayStation Mobile SDK やってしばらくお茶を濁そうかいこうかと思います。はあ長かった。

P.S
本当は先週アップできたんです。Bilateral Filtered Shadow Maps というものをやって。
ところが記事作成の段階になって以前は無料でDLできたPDFがDLできなくなってしまいました。
サンプル作成してる最中に有償に変更したか、心無い人がネット上にPDFを勝手にアップしたかはわかりませんが、まあそんなわけで記事をアップできなくなってしまいました。
Bilateral Filtered Shadow Maps は置いといて、Bilateral Filter 自体は重要そうなのでやっておく価値があると思います。
t-potさんのところで解説されているので詳しくはそちらを参考にしてほしいですが、
簡単に説明すると、テクセルの距離で重みづけしてぼかすガウスフィルターを拡張し、テクセルの距離だけでなくマップの色の差も重みづけとして考慮するというものです。
今すぐには使えるエフェクトは思いつかないのですが...


Prev Top Next
inserted by FC2 system