Microsoft Visual Express 2013 for Desktop C++
 Direct3D 11.0( SM 5.0 )
 DirectXTex texture processing library
 XMLLite

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


今回はVolumetric Shadow Mappingというものをやります。
理論は単純なので論文読むまでもないですが、一応リンク先をアップしておきます。

リンク先の論文の図を見れば何をしようとしているのかはわかると思いますので説明は省略です。


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

Aシェーダー系で使用するソースです。
VolumetricShadowMapping_Pass0.hlsl ライトビューでシーンの深度マップを生成するシェーダーソース
VolumetricShadowMapping_Pass1.hlsl カメラビューでスポットライトの表面の深度、およびアルファチャンネルのマップを生成するシェーダーソース
VolumetricShadowMapping_Pass2.hlsl 実はVolumetricShadowMapping_Pass1.hlslと全く同じ。これ1パスにまとめられないかなあ。
VolumetricShadowMapping_Pass3.hlsl スポットライトを合成しつつカメラビューでシーンのレンダリング。
VolumetricShadowMapping.h VolumetricShadowMappingクラスのヘッダーファイル
VolumetricShadowMapping.cpp VolumetricShadowMappingクラスのソースファイル

B個別に使用するソースです。
MonkeyMesh.h さるメッシュクラスのヘッダーファイル
MonkeyMesh.cpp さるメッシュクラスのソースファイル
PlaneMesh.h 地面メッシュクラスのヘッダーファイル
PlaneMesh.cpp 地面メッシュクラスのソースファイル
SkyDomeMesh.h 天球メッシュクラスのヘッダーファイル
SkyDomeMesh.cpp 天球メッシュクラスのソースファイル
SpotlightMesh.h スポットライトメッシュクラスのヘッダーファイル
SpotlightMesh.cpp スポットライトメッシュクラスのソースファイル
main.cpp main関数のソースファイル


---VolumetricShadowMapping_Pass0.hlsl---  ↑

// ************************************************************
// Volumetric Shadow Mapping    ライトビューでシーンの深度値を出力
// ************************************************************

// 定数バッファ
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 VolumetricShadowMapping_Pass0_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;
   Out.pos = mul( float4( In.pos, 1 ), g_matLightWorldViewProj );
   
   return Out;
}

---VolumetricShadowMapping_Pass1.hlsl---  ↑


// ************************************************************
// Volumetric Shadow Mapping  カメラビューでスポットライトの表面の深度値とアルファチャンネルを出力
// ************************************************************

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

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

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

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

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

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

   Out.pos = mul( float4( In.pos, 1.0f ), g_matCameraWorldViewProj );
   Out.texel = In.texel;
   Out.posWVP = Out.pos;

   return Out;
}

// ピクセルシェーダ
float2 VolumetricShadowMapping_Pass1_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   return float2( In.posWVP.z / g_CameraZFar, g_DecalMap.Sample( g_DecalSampler, In.texel ).a );
}

---VolumetricShadowMapping_Pass2.hlsl---  ↑


// ************************************************************
// Volumetric Shadow Mapping  カメラビューでスポットライトの裏面の深度値とアルファチャンネルを出力
// ************************************************************

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

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

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

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

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

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

   Out.pos = mul( float4( In.pos, 1.0f ), g_matCameraWorldViewProj );
   Out.texel = In.texel;
   Out.posWVP = Out.pos;

   return Out;
}

// ピクセルシェーダ
float2 VolumetricShadowMapping_Pass2_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   return float2( In.posWVP.z / g_CameraZFar, g_DecalMap.Sample( g_DecalSampler, In.texel ).a );
}

---VolumetricShadowMapping_Pass3.hlsl---  ↑


// ************************************************************
// Volumetric Shadow Mapping  スポットライトを合成しつつカメラビューでシーンのレンダリング
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   column_major float4x4 g_matCameraWorldViewProj     : packoffset( c0 );    // カメラビューのワールドビュー射影行列
   column_major float4x4 g_matCameraInvViewProj_LightViewProj : packoffset( c4 );    // カメラビューの逆ビュー射影行列とライトビューのビュー射影行列
   float4 g_vecLightPos                : packoffset( c8 );    // ローカル座標系での平行光源の位置ベクトル
   float g_CameraZNear                      : packoffset( c9.x );  // 前方クリップ面
   float g_CameraZFar                       : packoffset( c9.y );  // 後方クリップ面
};

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

// ライトビューでシーンの深度マップ
Texture2D g_DepthMap : register( t1 );

// スポットライトの深度およびアルファチャンネル
Texture2D g_SpotlightFrontFaceDepthMap : register( t2 );
Texture2D g_SpotlightBackFaceDepthMap : register( t3 );

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

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

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

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

   Out.pos = mul( float4( In.pos, 1.0f ), g_matCameraWorldViewProj );
   Out.texel = In.texel;
   Out.normal = In.normal;
   Out.posCWVP = Out.pos;

   return Out;
}

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

float GetW( float z )
{
   return ( z + g_CameraZNear * g_CameraZFar / ( g_CameraZFar - g_CameraZNear ) ) * ( g_CameraZFar - g_CameraZNear ) / g_CameraZFar;
}
   
// ピクセルシェーダ
float4 VolumetricShadowMapping_Pass3_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   float4 col = g_DecalMap.Sample( g_DecalSampler, In.texel );
 
   float2 texel = GetTexel( In.posCWVP );
 
   // スポットライトの深度値とアルファチャンネル
   float2 spotlightBackFace = g_SpotlightBackFaceDepthMap.Sample( g_SpotlightSampler, texel ).rg;
   float2 spotlightFrontFace = g_SpotlightFrontFaceDepthMap.Sample( g_SpotlightSampler, texel ).rg;
   
   float spotlight = 0;

   // スポットライトが当たっている場合
   if( spotlightFrontFace.r * g_CameraZFar < In.posCWVP.z )
   {
      float w;
   
      // w除算していない射影空間上のスポットライトの表面の座標を計算
      w = GetW( spotlightFrontFace.r * g_CameraZFar );
      float3 spos = float3( In.posCWVP.x / In.posCWVP.w * w, In.posCWVP.y / In.posCWVP.w * w, spotlightFrontFace.r * g_CameraZFar );

      // w除算していない射影空間上のスポットライトの裏面の座標を計算
      w = GetW( spotlightBackFace.r * g_CameraZFar );
      float3 epos = float3( In.posCWVP.x / In.posCWVP.w * w, In.posCWVP.y / In.posCWVP.w * w, spotlightBackFace.r * g_CameraZFar );
   
      // 方向ベクトル
      float3 offset = normalize( epos - spos ) * 10.0f;
   
      // シーンの深度値とスポットライトの背面の深度値で手前のほうにある深度値
      float z = min( In.posCWVP.z, spotlightBackFace.r * g_CameraZFar );

      // スポットライトの厚みを光度として計算
      spotlight = ( z / g_CameraZFar - spotlightFrontFace.r ) * 8.0f;
      
      // スポットライトの輪郭付近の透明度を上げる
      //      spotlight = pow( spotlight, 3 );
      
      // アルファチャンネルによる半透明処理
      spotlight *= ( spotlightBackFace.g + spotlightFrontFace.g ) * 0.5f;

      [unroll(40)]
      // 移動した座標がスポットライトの裏面を超えていない
      while( spos.z <= z )
      {
         // 移動先のw成分を計算
         w = GetW( spos.z );
         
         // z方向に移動したカメラビューの射影空間上の座標をライトビューの射影空間上の座標に変換
         float4 LightViewLightPos = mul( float4( spos.xyz, w ), g_matCameraInvViewProj_LightViewProj );

         // テクセル取得
         texel = GetTexel( LightViewLightPos );

         // ライトビュー空間上でのシーンの深度値取得
         float LightViewScenePos = g_DepthMap.Sample( g_SpotlightSampler, texel ).r;

         // z方向に移動した座標がシーンの深度値より奥にあるとき( スポットライトが当たっていないとき )
         if( LightViewLightPos.z > LightViewScenePos * LightViewLightPos.w )
         {
            spotlight *= 0.9f;
         }
         
         spos += offset;
      }
   }

   // ハーフランバート
   float lambert = dot( g_vecLightPos.xyz, In.normal );
   lambert = lambert * 0.5f + 0.5f;

   return ( col * lambert + max( spotlight, 0 ) ).bgra;
}

---VolumetricShadowMapping.h---  ↑

#ifndef VOLUMETRIC_SHADOW_MAPPING_H
#define VOLUMETRIC_SHADOW_MAPPING_H

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

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

class VolumetricShadowMapping
{
private:
   // Direct3D用定数バッファ設定用構造体

   // ライトビューでシーンの深度値を出力
   typedef struct _CBUFFER_PASS0
   {
      XMMATRIX matLightWorldViewProj;
   }CBUFFER_PASS0;

   // カメラビューでスポットライトの表面の深度値とアルファチャンネルを出力
   typedef struct _CBUFFER_PASS1
   {
      XMMATRIX matCameraWorldViewProj;
      float CameraZFar;
      float Dummy1;
      float Dummy2;
      float Dummy3;
   }CBUFFER_PASS1;

   // カメラビューでスポットライトの裏面の深度値とアルファチャンネルを出力
   typedef struct _CBUFFER_PASS2
   {
      XMMATRIX matCameraWorldViewProj;
      float CameraZFar;
      float Dummy1;
      float Dummy2;
      float Dummy3;
   }CBUFFER_PASS2;

   // スポットライトを合成しつつカメラビューでシーンのレンダリング
   typedef struct _CBUFFER_PASS3
   {
      XMMATRIX matCameraWorldViewProj;
      XMMATRIX matCameraInvViewProj_LightViewProj;
      XMFLOAT4 vecLightDir;
      float CameraZNear;
      float CameraZFar;
      float Dummy2;
      float Dummy3;
   }CBUFFER_PASS3;

   // 深度マップ
   ID3D11DepthStencilView* m_pDSViewOfDepthMap;
   ID3D11ShaderResourceView* m_pSRViewOfDepthMap;

   // スポットライトの深度およびアルファチャンネルマップ
   ID3D11RenderTargetView* m_pRTViewOfSpotlightDepthMap[2];
   ID3D11ShaderResourceView* m_pSRViewOfSpotlightDepthMap[2];
   ID3D11DepthStencilView* m_pDSViewOfSpotlightDepthMap;

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

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

   UGraphicsPipeline* m_pGraphicsPipeline[4];

   float m_CameraZNear, m_CameraZFar;

   DWORD m_LightViewWidth, m_LightViewHeight, m_CameraViewWidth, m_CameraViewHeight;
   XMMATRIX m_MatCView;
   XMMATRIX m_MatCProj;
   XMMATRIX m_MatLProj;
   XMFLOAT4 m_VecLightPos;
   int m_Pass;

public:
   VolumetricShadowMapping();
   virtual ~VolumetricShadowMapping();
   void Invalidate();
   void Create( ID3D11Device* pD3DDevice, DWORD LightViewWidth, DWORD LightViewHeight, DWORD CameraViewWidth, DWORD CameraViewHeight, float CameraZNear, float CameraZFar );
   void Begin( XMFLOAT4* pVecLightPos, XMMATRIX* pMatLProj, XMMATRIX* pMatCView, XMMATRIX* pMatCProj );
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass );
   void SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld );
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
   void End();
   inline const ID3D11ShaderResourceView* GetDepthMap(){ return m_pSRViewOfDepthMap; };
   inline const ID3D11ShaderResourceView* GetSpotlightDepthMap( UINT index ){ return m_pSRViewOfSpotlightDepthMap[index]; };
};
#endif

---VolumetricShadowMapping.cpp---  ↑


#include "../../Header/Shader/VolumetricShadowMapping.h"
#include "../../HLSL/VolumetricShadowMapping_Pass0_VS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass1_VS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass1_PS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass2_VS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass2_PS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass3_VS_Main.h"
#include "../../HLSL/VolumetricShadowMapping_Pass3_PS_Main.h"

VolumetricShadowMapping::VolumetricShadowMapping()
{
   m_pDSViewOfDepthMap = nullptr;
   m_pSRViewOfDepthMap = nullptr;
   for( int i=0; i<_countof( m_pRTViewOfSpotlightDepthMap ); i++ )
   {
      m_pRTViewOfSpotlightDepthMap[i] = nullptr;
      m_pSRViewOfSpotlightDepthMap[i] = nullptr;
   }
   m_pDSViewOfSpotlightDepthMap = nullptr;
   for( int i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      m_pGraphicsPipeline[i] = nullptr;
      m_pConstantBuffers[i] = nullptr;
   }
   m_pSamplerState = nullptr;
   m_Pass = -2;
}

VolumetricShadowMapping::~VolumetricShadowMapping()
{
   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_pDSViewOfSpotlightDepthMap );
   for( int i=0; i<_countof( m_pRTViewOfSpotlightDepthMap ); i++ )
   {
      SAFE_RELEASE( m_pSRViewOfSpotlightDepthMap[i] );
      SAFE_RELEASE( m_pRTViewOfSpotlightDepthMap[i] );
   }
   SAFE_RELEASE( m_pSRViewOfDepthMap );
   SAFE_RELEASE( m_pDSViewOfDepthMap );
}

void VolumetricShadowMapping::Create( ID3D11Device* pD3DDevice, DWORD LightViewWidth, DWORD LightViewHeight, DWORD CameraViewWidth, DWORD CameraViewHeight, float CameraZNear, float CameraZFar )
{
   m_LightViewWidth = LightViewWidth;
   m_LightViewHeight = LightViewHeight;
   m_CameraViewWidth = CameraViewWidth;
   m_CameraViewHeight = CameraViewHeight;
   m_CameraZNear = CameraZNear;
   m_CameraZFar = CameraZFar;

   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 BlendStateType_None[1] = { UGraphicsPipeline::UEBLEND_STATE::NONE };
   m_pGraphicsPipeline[0]->CreateBlendState( pD3DDevice, BlendStateType_None, 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/VolumetricShadowMapping_Pass0.hlsl"), "VolumetricShadowMapping_Pass0_VS_Main", layout, _countof( layout ) );
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_VolumetricShadowMapping_Pass0_VS_Main, sizeof( g_VolumetricShadowMapping_Pass0_VS_Main ), layout, _countof( layout ) );
#endif
 
   // 深度ステンシルバッファを作成する
   UMaps::CreateDepthStencilView( pD3DDevice, m_LightViewWidth, m_LightViewHeight, &m_pDSViewOfDepthMap, &m_pSRViewOfDepthMap );

   // 定数バッファを作成する
   m_pConstantBuffers[0] = m_pGraphicsPipeline[0]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( VolumetricShadowMapping::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 );

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

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

   // スポットライトの深度およびアルファチャンネルマップ
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R32G32_FLOAT, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfSpotlightDepthMap[0], &m_pSRViewOfSpotlightDepthMap[0] );

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

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

   // *******************************************************************************************************
   // カメラビューでスポットライトの裏面の深度値とアルファチャンネルを出力
   // *******************************************************************************************************

   m_pGraphicsPipeline[2] = NEW UGraphicsPipeline();

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

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

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

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[2]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/VolumetricShadowMapping_Pass2.hlsl"), "VolumetricShadowMapping_Pass2_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/VolumetricShadowMapping_Pass2.hlsl"), "VolumetricShadowMapping_Pass2_PS_Main" );
#else
   m_pGraphicsPipeline[2]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_VolumetricShadowMapping_Pass2_VS_Main, sizeof( g_VolumetricShadowMapping_Pass2_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_VolumetricShadowMapping_Pass2_PS_Main, sizeof( g_VolumetricShadowMapping_Pass2_PS_Main ) );
#endif

   // スポットライトの深度およびアルファチャンネルマップ
   UMaps::CreateRenderTargetView( pD3DDevice, DXGI_FORMAT_R32G32_FLOAT, m_CameraViewWidth, m_CameraViewHeight, &m_pRTViewOfSpotlightDepthMap[1], &m_pSRViewOfSpotlightDepthMap[1] );

   // 定数バッファを作成する
   m_pConstantBuffers[2] = m_pGraphicsPipeline[1]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( VolumetricShadowMapping::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, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL );

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

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[3]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/VolumetricShadowMapping_Pass3.hlsl"), "VolumetricShadowMapping_Pass3_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[3]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/VolumetricShadowMapping_Pass3.hlsl"), "VolumetricShadowMapping_Pass3_PS_Main" );
#else
   m_pGraphicsPipeline[3]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_VolumetricShadowMapping_Pass3_VS_Main, sizeof( g_VolumetricShadowMapping_Pass3_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[3]->CreatePixelShaderFromMemory(  pD3DDevice, (LPBYTE)g_VolumetricShadowMapping_Pass3_PS_Main, sizeof( g_VolumetricShadowMapping_Pass3_PS_Main ) );
#endif
 
   // 定数バッファを作成する
   m_pConstantBuffers[3] = m_pGraphicsPipeline[3]->CreateConstantBuffer( pD3DDevice, nullptr, sizeof( VolumetricShadowMapping::CBUFFER_PASS3 ), D3D11_CPU_ACCESS_WRITE );

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

void VolumetricShadowMapping::Begin( XMFLOAT4* pVecLightPos, XMMATRIX* pMatLProj, XMMATRIX* pMatCView, XMMATRIX* pMatCProj )
{
   if (m_Pass != -2)
   {
      throw(UException(-1, _T("VolumetricShadowMapping::Begin()はCreate()またはEnd()実行後に使用してください")));
   }
   
   m_VecLightPos = *pVecLightPos;
   m_MatLProj = *pMatLProj;
   m_MatCView = *pMatCView;
   m_MatCProj = *pMatCProj;

   m_Pass = -1;
}

void VolumetricShadowMapping::BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass )
{
   if (m_Pass != -1)
   {
      throw(UException(-1, _T("VolumetricShadowMapping::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_pDSViewOfDepthMap );

         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_pDSViewOfDepthMap, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
      }
      break;

   // *******************************************************************************************************
   // カメラビューでスポットライトの表面の深度値とアルファチャンネルを出力
   // *******************************************************************************************************
   case 1:
      {
         pD3DDeviceContext->OMSetRenderTargets( 1, &m_pRTViewOfSpotlightDepthMap[0], m_pDSViewOfSpotlightDepthMap );

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

         float ClearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfSpotlightDepthMap[0], ClearColor ); 

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

   // *******************************************************************************************************
   // カメラビューでスポットライトの裏面の深度値とアルファチャンネルを出力
   // *******************************************************************************************************
   case 2:
      {
         pD3DDeviceContext->OMSetRenderTargets( 1, &m_pRTViewOfSpotlightDepthMap[1], m_pDSViewOfSpotlightDepthMap );

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

         float ClearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
         pD3DDeviceContext->ClearRenderTargetView( m_pRTViewOfSpotlightDepthMap[1], ClearColor ); 

         pD3DDeviceContext->ClearDepthStencilView( m_pDSViewOfSpotlightDepthMap, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0 );
      }
      break;

   // *******************************************************************************************************
   // スポットライトを合成しつつカメラビューでシーンのレンダリング
   // *******************************************************************************************************
   case 3:
      {
         pD3DDeviceContext->PSSetShaderResources( 1, 1, &m_pSRViewOfDepthMap );
         pD3DDeviceContext->PSSetShaderResources( 2, _countof( m_pSRViewOfSpotlightDepthMap ), m_pSRViewOfSpotlightDepthMap );

         ID3D11SamplerState* pSampler[3] = { m_pSamplerState, m_pSamplerState, m_pSamplerState };
         pD3DDeviceContext->PSSetSamplers( 1, _countof( pSampler ), pSampler );
      }
      break;

   default:
      throw(UException(-1, _T("VolumetricShadowMapping::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 VolumetricShadowMapping::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, 0, 1 ) ) );

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

         // 定数バッファを設定する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("VolumetricShadowMapping::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         VolumetricShadowMapping::CBUFFER_PASS0* cbuffer = (VolumetricShadowMapping::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 matCameraWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatCView * m_MatCProj );

         // 定数バッファを設定する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("VolumetricShadowMapping::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         VolumetricShadowMapping::CBUFFER_PASS1* cbuffer = (VolumetricShadowMapping::CBUFFER_PASS1*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof( XMMATRIX ) );
         cbuffer->CameraZFar = m_CameraZFar;
         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 matCameraWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatCView * m_MatCProj );

         // 定数バッファを設定する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("VolumetricShadowMapping::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         VolumetricShadowMapping::CBUFFER_PASS2* cbuffer = (VolumetricShadowMapping::CBUFFER_PASS2*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof( XMMATRIX ) );
         cbuffer->CameraZFar = m_CameraZFar;
         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 3:
      {
         // カメラビューのワールド行列とビュー行列と射影行列
         XMMATRIX matCameraWorldViewProj = XMMatrixTranspose( *pMatWorld * m_MatCView * m_MatCProj );

         // カメラビューのビュー射影行列の逆行列を作成
         XMMATRIX matInv = XMMatrixInverse( nullptr, m_MatCView * m_MatCProj );

         // ライトビューのビュー行列を作成
         XMMATRIX matLView = XMMatrixLookAtLH( XMLoadFloat3( (XMFLOAT3*)&m_VecLightPos ), XMLoadFloat3( &XMFLOAT3( 0, 0, 0 ) ), XMLoadFloat3( &XMFLOAT3( 0, 0, 1 ) ) );

         XMMATRIX matCameraInvViewProj_LightViewProj = XMMatrixTranspose( matInv * matLView * m_MatLProj );

         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("VolumetricShadowMapping::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         VolumetricShadowMapping::CBUFFER_PASS3* cbuffer = (VolumetricShadowMapping::CBUFFER_PASS3*)mappedResource.pData;
         ::CopyMemory( &cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof( XMMATRIX ) );
         ::CopyMemory( &cbuffer->matCameraInvViewProj_LightViewProj, &matCameraInvViewProj_LightViewProj, sizeof( XMMATRIX ) );
         ::CopyMemory( &cbuffer->vecLightDir, &localLightPos, sizeof( XMFLOAT4 ) );
         cbuffer->CameraZNear = m_CameraZNear;
         cbuffer->CameraZFar = m_CameraZFar;
         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 VolumetricShadowMapping::EndPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   switch( m_Pass )
   {
   case 0:
      {
      }
      break;

   case 1:
      {
      }
      break;

   case 2:
      {
         // レンダーターゲットビューと深度ステンシルビューとビューポートを戻す
         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 3:
      {
         ID3D11ShaderResourceView* pSRViewNull[] = { nullptr, nullptr, nullptr, nullptr };
         pD3DDeviceContext->PSSetShaderResources( 0, _countof( pSRViewNull ), pSRViewNull );
      }
      break;
   }

   m_Pass = -1;
}

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

---SkyDomeMesh.h---  ↑


#ifndef SKYDOMEMESH_H
#define SKYDOMEMESH_H

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

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

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

   // インデックスバッファ
   ID3D11Buffer* m_pIndexBuffer;

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

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

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

   XMMATRIX m_MatWorld;

   ULONG m_VertexCount;
   ULONG m_IndexCountOfTraiangleStrips;
   ULONG m_TraiangleStripsCount;
   ULONG m_IndexCountOfTraiangleLists;    // DirectX9にあったFANはなくなったっぽいので

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

#endif

---SkyDomeMesh.cpp---  ↑


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

SkydomeMesh::SkydomeMesh()
{
   m_pVertexBuffer = nullptr;
   m_pIndexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
   m_VertexCount = 0;
   m_IndexCountOfTraiangleStrips = 0;
   m_TraiangleStripsCount = 0;
   m_IndexCountOfTraiangleLists = 0;
}

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

void SkydomeMesh::Invalidate()
{
   m_IndexCountOfTraiangleLists = 0;
   m_TraiangleStripsCount = 0;
   m_IndexCountOfTraiangleStrips = 0;
   m_VertexCount = 0;
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pIndexBuffer );
   SAFE_RELEASE( m_pVertexBuffer );
}

void SkydomeMesh::CreateMesh( ID3D11Device* pD3DDevice )
{
   float Radius = 1000.0f;
   UINT CircleVertexCount = 10;
   UINT SplitHeight = 5;

   if( CircleVertexCount < 3 )
      throw( UException( -1, _T("SkydomeMesh::CreateMesh()でエラーが発生しました。円の頂点数の最小値は3個です。") ) );

   if( SplitHeight < 3 )
      throw( UException( -1, _T("SkydomeMesh::CreateMesh()でエラーが発生しました。高さ方向の分割数の最小値は3です。") ) );

   m_VertexCount = CircleVertexCount * ( SplitHeight - 1 ) + 1;

   m_IndexCountOfTraiangleStrips = ( CircleVertexCount + 1 ) * ( SplitHeight - 2 ) * 2;
   m_TraiangleStripsCount = SplitHeight - 2;
   m_IndexCountOfTraiangleLists = CircleVertexCount * 3;

   UD3DMeshDataCreater::VERTEX* vertex = NEW UD3DMeshDataCreater::VERTEX[m_VertexCount];

   ULONG index = 0;
   float r = XM_PI * 0.5f / (float)( SplitHeight - 1 );

   for( ULONG i=0; i<SplitHeight - 1; i++ )
   {
      for( ULONG j=0; j<CircleVertexCount; j++ )
      {
         vertex[index].Position = XMFLOAT3( sinf( (float)j / (float)CircleVertexCount * XM_2PI ) * cosf( r * (float)i ) * Radius,
                                            sinf( r * (float)i ) * Radius,
                                            cosf( (float)j / (float)CircleVertexCount * XM_2PI ) * cosf( r * (float)i ) * Radius );

         vertex[index].Normal = XMFLOAT3( 0, 1, 0 );
         vertex[index].Texcoord = XMFLOAT2( (float)j / (float)CircleVertexCount, 1.0f - (float)i / (float)SplitHeight );
         index++;
      }
   }
   vertex[index].Position = XMFLOAT3( 0, Radius, 0 );
   vertex[index].Normal = XMFLOAT3( 0, 1, 0 );
   vertex[index].Texcoord = XMFLOAT2( 0, 0 );
   index++;

   // 頂点バッファを作成する
   m_pVertexBuffer = UBuffers::CreateVertexBuffer( pD3DDevice, vertex, sizeof( UD3DMeshDataCreater::VERTEX ) * m_VertexCount, 0 );
  
   UINT* indexes = NEW UINT[m_IndexCountOfTraiangleStrips + m_IndexCountOfTraiangleLists];

   index = 0;
   for( ULONG i=0; i<SplitHeight - 2; i++ )
   {
      for( ULONG j=0; j<CircleVertexCount; j++ )
      {
         indexes[index++] = CircleVertexCount * ( i + 1 ) + j;
         indexes[index++] = CircleVertexCount * i + j;
      }
      indexes[index++] = CircleVertexCount * ( i + 1 );
      indexes[index++] = CircleVertexCount * i;
   }
   for( ULONG j=0; j<CircleVertexCount - 1; j++ )
   {
      indexes[index++] = ( SplitHeight - 1 ) * CircleVertexCount;
      indexes[index++] = ( SplitHeight - 2 ) * CircleVertexCount + j;
      indexes[index++] = ( SplitHeight - 2 ) * CircleVertexCount + j + 1;
   }
   indexes[index++] = ( SplitHeight - 1 ) * CircleVertexCount;
   indexes[index++] = ( SplitHeight - 2 ) * CircleVertexCount + CircleVertexCount - 1;
   indexes[index++] = ( SplitHeight - 2 ) * CircleVertexCount;
   
   // インデックスバッファを作成する
   m_pIndexBuffer = UBuffers::CreateIndexBuffer( pD3DDevice, indexes, sizeof( UINT ) * ( m_IndexCountOfTraiangleStrips + m_IndexCountOfTraiangleLists ), 0 );

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

   // テクスチャーを作成する
   UMaps::CreateSRViewFromDDSFile( pD3DDevice, _T("../Resource/sky.dds"), &m_pSRView );

   SAFE_DELETE_ARRAY( indexes );
   SAFE_DELETE_ARRAY( vertex );
}

void SkydomeMesh::NextFrame()
{
   XMMATRIX matTranslate;

   matTranslate = XMMatrixTranslation( 0.0f, -50.0f, 0.0f );
   m_MatWorld = matTranslate;
}

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

   // インデックスバッファ設定
   pD3DDeviceContext->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

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

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

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

   // 描画
   for( ULONG i=0; i<m_TraiangleStripsCount; i++ )
      pD3DDeviceContext->DrawIndexed( m_IndexCountOfTraiangleStrips / m_TraiangleStripsCount, m_IndexCountOfTraiangleStrips / m_TraiangleStripsCount * i, 0 );

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

   // 描画
   pD3DDeviceContext->DrawIndexed( m_IndexCountOfTraiangleLists, m_IndexCountOfTraiangleStrips, 0 );
}

---SpotlightMesh.h---  ↑


#ifndef SPOTLIGHTMESH_H
#define SPOTLIGHTMESH_H

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

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

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

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

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

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

   XMMATRIX m_MatWorld;

   ULONG m_VertexCount;

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

#endif

---SpotlightMesh.cpp---  ↑


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

SpotlightMesh::SpotlightMesh()
{
   m_pVertexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
   m_VertexCount = 0;
}

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

void SpotlightMesh::Invalidate()
{
   m_VertexCount = 0;
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pVertexBuffer );
}

void SpotlightMesh::CreateMesh( ID3D11Device* pD3DDevice )
{
   float topRadius = 80.0f;
   float bottomRadius = 130.0f;
   float height = 1200.0f;

   m_VertexCount = 30;

   if( m_VertexCount <= 6 )
      throw( UException( -1, _T("SpotlightMesh::CreateMesh()でエラーが発生しました。頂点数の最小値は三角柱となる8個です。") ) );

   if( m_VertexCount % 2 != 0 )
      throw( UException( -1, _T("SpotlightMesh::CreateMesh()でエラーが発生しました。頂点数は偶数で設定してください。") ) );

   UD3DMeshDataCreater::VERTEX* vertex = NEW UD3DMeshDataCreater::VERTEX[m_VertexCount];

   UINT h = m_VertexCount / 2 - 1;
   for( ULONG i=0; i<h; i++ )
   {
      vertex[i*2].Position = XMFLOAT3( sinf( (float)i / (float)h * XM_2PI ) * topRadius, 0, -cosf( (float)i / (float)h * XM_2PI ) * topRadius );
      XMStoreFloat3( &vertex[i*2].Normal, XMVector3Normalize( XMLoadFloat3( &vertex[i*2].Position ) ) );
      vertex[i*2].Texcoord = XMFLOAT2( (float)i / (float)h, 0 );

      vertex[i*2+1].Position = XMFLOAT3( sinf( (float)i / (float)h * XM_2PI ) * bottomRadius, -height, -cosf( (float)i / (float)h * XM_2PI ) * bottomRadius );
      ::CopyMemory( &vertex[i*2+1].Normal, &vertex[i*2].Normal, sizeof( XMFLOAT3 ) );
      vertex[i*2+1].Texcoord = XMFLOAT2( (float)i / (float)h, 1 );
   }
   ::CopyMemory( &vertex[m_VertexCount - 2], &vertex[0], sizeof( UD3DMeshDataCreater::VERTEX ) );
   ::CopyMemory( &vertex[m_VertexCount - 1], &vertex[1], sizeof( UD3DMeshDataCreater::VERTEX ) );

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

   // テクスチャーを作成する
   UMaps::CreateSRViewFromDDSFile( pD3DDevice, _T("../Resource/Spotlight.dds"), &m_pSRView );

   SAFE_DELETE_ARRAY( vertex );
}

void SpotlightMesh::NextFrame()
{
   XMMATRIX matTranslate;

   matTranslate = XMMatrixTranslation( 0.0f, 1000.0f, 0.0f );
   m_MatWorld = matTranslate;
}

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

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

   // ピクセルシェーダーのサンプラーステートを設定する
   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/VolumetricShadowMapping.h"
#include "../Header/Mesh/PlaneMesh.h"
#include "../Header/Mesh/MonkeyMesh.h"
#include "../Header/Mesh/SkyDomeMesh.h"
#include "../Header/Mesh/SpotlightMesh.h"

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

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

VolumetricShadowMapping* g_pVolumetricShadowMapping = nullptr;

PlaneMesh* g_pPlaneMesh = nullptr;
MonkeyMesh* g_pMonkeyMesh = nullptr;
SkydomeMesh* g_pSkydomeMesh = nullptr;
SpotlightMesh* g_pSpotlightMesh = nullptr;

UFPS* g_pFPS = 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 = 2000.0f, g_LightZNear = 700.0f;

// カメラビュー行列
XMMATRIX g_MatCameraView = XMMatrixTranslation(0, -200, 800.0f);

// カメラービュー射影行列
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_LightZNear, g_LightZFar );

// 平行光源の位置ベクトル( スポットライトとは連動するようにはしていないので )
XMFLOAT4 g_VecLightPos = XMFLOAT4( 0.0f, 1500.0f, 0.0f, 0 );

// さるの座標
XMMATRIX g_MatMonkeyPos = XMMatrixTranslation( 0, 100.0f, 100.0f );

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

   SAFE_DELETE( g_pFPS );
   SAFE_DELETE( g_pVolumetricShadowMapping );
   SAFE_DELETE( g_pSpotlightMesh );
   SAFE_DELETE( g_pSkydomeMesh );
   SAFE_DELETE( g_pMonkeyMesh );
   SAFE_DELETE( g_pPlaneMesh );
   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 );

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

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

   g_pMonkeyMesh = NEW MonkeyMesh();
   g_pMonkeyMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice );

   g_pSkydomeMesh = NEW SkydomeMesh();
   g_pSkydomeMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice );

   g_pSpotlightMesh = NEW SpotlightMesh();
   g_pSpotlightMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice );
}

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

   g_pVolumetricShadowMapping = NEW VolumetricShadowMapping();

   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_MatMonkeyPos *= XMMatrixTranslation(0, 0, 0.5f);
   if (GetKeyState(VK_DOWN) & 0x8000)
      g_MatMonkeyPos *= XMMatrixTranslation(0, 0, -0.5f);
   if (GetKeyState(VK_RIGHT) & 0x8000)
      g_MatMonkeyPos *= XMMatrixTranslation(0.5f, 0, 0);
   if (GetKeyState(VK_LEFT) & 0x8000)
      g_MatMonkeyPos *= XMMatrixTranslation(-0.5f, 0, 0);
   if (GetKeyState('Q') & 0x8000)
      g_MatMonkeyPos *= XMMatrixTranslation(0, 0.5f, 0);
   if (GetKeyState('A') & 0x8000)
      g_MatMonkeyPos *= XMMatrixTranslation(0, -0.5f, 0);

   g_pFPS->NextFrame();

   g_pPlaneMesh->NextFrame();
   g_pMonkeyMesh->NextFrame();
   g_pSkydomeMesh->NextFrame();
   g_pSpotlightMesh->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 );

   XMMATRIX mat = XMMatrixScaling( 3, 3, 3 ) * *g_pMonkeyMesh->GetMatWorld() * g_MatMonkeyPos;
   
   // レンダリング
   g_pVolumetricShadowMapping->Begin( &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj );
   {
      // ライトビューでシーンの深度値取得
      g_pVolumetricShadowMapping->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 0 );
      {
         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, &mat );
         g_pMonkeyMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );

         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pPlaneMesh->GetMatWorld() );
         g_pPlaneMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
      }g_pVolumetricShadowMapping->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

      // スポットライトの表面の深度値とアルファチャンネル取得
      g_pVolumetricShadowMapping->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 1 );
      {
         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pSpotlightMesh->GetMatWorld() );
         g_pSpotlightMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );      
      }g_pVolumetricShadowMapping->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

      // スポットライトの裏面の深度値とアルファチャンネル取得
      g_pVolumetricShadowMapping->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 2 );
      {
         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pSpotlightMesh->GetMatWorld() );
         g_pSpotlightMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );      
      }g_pVolumetricShadowMapping->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

      // シーンのレンダリング
      g_pVolumetricShadowMapping->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 3 );
      {
         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, &mat );
         g_pMonkeyMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );

         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pPlaneMesh->GetMatWorld() );
         g_pPlaneMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );

         g_pVolumetricShadowMapping->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pSkydomeMesh->GetMatWorld() );
         g_pSkydomeMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
      
      }g_pVolumetricShadowMapping->EndPass( g_pDirect3D11->m_pD3DDeviceContext );
   }g_pVolumetricShadowMapping->End();

#if defined(DEBUG) || defined(_DEBUG)
   int SrcRGB[4] = { 0, 0, 0, 0 };
//   g_pSRViewRenderer->SetSRView( g_pVolumetricShadowMapping->GetDepthMap(), SrcRGB );
   g_pSRViewRenderer->SetSRView( g_pVolumetricShadowMapping->GetSpotlightDepthMap(0), SrcRGB );
   g_pSRViewRenderer->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;
}

次で終わりだ。


web拍手 by FC2

Prev Top Next

inserted by FC2 system