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

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


今回はDeep Shadow Mapsというものをやります。残念ながら日本語解説しているサイトがなかったので、英語論文を適当に解釈して実装しました。
論文はここです。

Deep Shadow Maps は煙のような半透明メッシュによって生じる影をシミュレートします。
半透明メッシュで光を遮られた場合、完全に影になることはなく透明度によって遮蔽率が変化します。
したがって光が半透明メッシュを通過するたびに光度が減衰していくようにします。
これをシミュレートするために、減衰率( = 透明度 )を加算合成した減衰率マップを生成します。
減衰率は当然のことながら3次元空間上で奥行を持った情報として処理する必要があります。
そのため減衰率マップは、これまで使用してきた深度マップのような2Dテクスチャーではなくボリュームテクスチャーを使用します。

以上が概要です。まあこの辺の説明はリンク先の論文に図があるのでそれを見たほうがイメージがつかみやすいかと思います。

さて、あらかじめ書いておきますが、今回のサンプルは課題がいっぱい残っています。
まず、パーティクルの品質向上のためにやらなければならない、ソフトパーティクル、ライティング、ボリュームパーティクル、
そしてパーティクルの座標更新をCPUで処理しているため、パフォーマンスにも問題があります。
とどめにソートしていないため、パーティクルに発生するセルフシャドーがおかしな感じに発生するときがあります。( サンプルではセルフシャドーを薄くしているのでわかりにくいですが )
CPUでソートするととんでもなくパフォーマンスが落ちたため、GPUでソートする方法を調べましたが、t-potさんのサイトのBitonic sort を使用すればできるようです。
Bitonic sort については、気が向いたらやってみようかと思います。


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

Aシェーダー系で使用するソースです。
DeepShadowMaps_Pass0.hlsl 減衰率マップを生成するシェーダーソース
DeepShadowMaps_Pass1.hlsl 不透明メッシュをレンダリングするシェーダーソース
DeepShadowMaps_Pass2.hlsl 半透明メッシュをレンダリングするシェーダーソース
DeepShadowMaps.h DeepShadowMapsクラスのヘッダーファイル
DeepShadowMaps.cpp DeepShadowMapsクラスのソースファイル

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


---DeepShadowMaps_Pass0.hlsl---  ↑

// ************************************************************
// Deep Shadow Maps Pass0
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   float g_ZFar               : packoffset( c0.x );
   uint  g_TextureArraySize   : packoffset( c0.y );
};

cbuffer CBuffer : register( b1 )
{
   column_major float4x4 g_matLightViewProj   : packoffset( c0 );    // ライトビューのビュー射影行列
   column_major float4x4 g_matLightBillboardViewProj  : packoffset( c4 );    // ライトビューの射影空間上でパーティクルの大きさを計算するための行列
};

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos           : POSITION;    // 頂点座標
   float  width         : TEXCOORD0;   // パーティクルのサイズ
   float  Attenuation   : TEXCOORD1;   // 減衰率
};

// 頂点シェーダーの出力パラメータ
typedef VS_IN VS_OUT_GS_IN;

// ジオメトリシェーダーの出力パラメータ
struct GS_OUT_PS_IN
{
   float4 pos            : SV_POSITION;   // 頂点座標
   float2 texel          : TEXCOORD0;     // テクセル( ジオメトリシェーダー内で作成 )
   float  Attenuation    : TEXCOORD1;     // アルファ( 減衰率 )
   uint   layer          : SV_RenderTargetArrayIndex;
};

// テクスチャー( a成分には透明度を設定 )
Texture2D g_DecalMap : register( t0 );

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

// 頂点シェーダー
VS_OUT_GS_IN DeepShadowMaps_Pass0_VS_Main( VS_IN In )
{
   return In;
}

// ジオメトリシェーダー
[maxvertexcount(6)]                                                             // ジオメトリシェーダーで出力する最大頂点数
void DeepShadowMaps_Pass0_GS_Main( point VS_OUT_GS_IN In[1],                    // ポイント プリミティブの入力情報
                                   inout TriangleStream<GS_OUT_PS_IN> TStream   // ポリゴン プリミティブの出力ストリーム
                                 )
{
   if( In[0].Attenuation <= 0.1f )
      return;
   
   // ライトビューのビュー射影行列でパーティクルの中心座標を変換
   float4 center = mul( float4( In[0].pos, 1 ), g_matLightViewProj );

   // 射影空間上でパーティクルの大きさを計算する
   float4 width = mul( float4( In[0].width, In[0].width, In[0].pos.z, 1 ), g_matLightBillboardViewProj );

   uint layer = center.z * ( g_TextureArraySize - 1 ) / g_ZFar;
   
   float Lleft   = center.x - width.x;
   float Ltop    = center.y + width.y;
   float Lright  = center.x + width.x;
   float Lbottom = center.y - width.y;
   
   GS_OUT_PS_IN vertex[4] = { 
      Lright, Ltop,    center.z, center.w, 1, 0, In[0].Attenuation, layer,   // 右上
      Lleft , Ltop,    center.z, center.w, 0, 0, In[0].Attenuation, layer,   // 左上
      Lleft , Lbottom, center.z, center.w, 0, 1, In[0].Attenuation, layer,   // 左下
      Lright, Lbottom, center.z, center.w, 1, 1, In[0].Attenuation, layer,   // 右下
   };
   
   TStream.Append( vertex[0] );  // 右上
   TStream.Append( vertex[1] );  // 左上
   TStream.Append( vertex[2] );  // 左下
   TStream.RestartStrip();

   TStream.Append( vertex[0] );  // 右上
   TStream.Append( vertex[2] );  // 左下
   TStream.Append( vertex[3] );  // 右下
   TStream.RestartStrip();
}

// ピクセルシェーダ
float4 DeepShadowMaps_Pass0_PS_Main( GS_OUT_PS_IN In ) : SV_Target
{
   float4 col = g_DecalMap.Sample( g_Sampler, In.texel );

   return float4( col.gbr * min( col.a, In.Attenuation ), 1 );
}

SV_RenderTargetArrayIndexセマンティックを設定することによってボリュームテクスチャーの出力先のレンダーターゲットサーフェスを指定します。

---DeepShadowMaps_Pass1.hlsl---  ↑


// ************************************************************
// Deep Shadow Maps ( 不透明メッシュのレンダリング用 )
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   float g_ZFar               : packoffset( c0.x );
};

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

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

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

// ボリュームテクスチャー
Texture3D g_VolumeMap : register( t1 );

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

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos       : SV_POSITION;
   float3 normal    : NORMAL;
   float2 texel     : TEXCOORD0;
   float4 Lpos      : TEXCOORD1;     // ライトビューで行列変換した頂点座標
   float  z         : TEXCOORD2;
};

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

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

   // ライトビューでワールドビュー射影行列
   Out.Lpos = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );

   Out.z = Out.Lpos.z / g_ZFar;

   return Out;
}

// ピクセルシェーダ
float4 DeepShadowMaps_Pass1_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   float2 texel = float2( In.Lpos.x / In.Lpos.w * 0.5f + 0.5f, In.Lpos.y / In.Lpos.w * -0.5f + 0.5f );

   float a = 0;

   // 減衰率を加算
   [unroll(10)]
   for( float i=In.z; i>=0; i-=0.05f )
   {
      a += g_VolumeMap.Sample( g_SamplerVolumeMap, float3( texel, i ) ).r;
   }

   a = exp( -a * 0.3f );

   // ハーフランバート
   float lambert = dot( g_vecLightPos.xyz, In.normal );
   lambert = lambert * 0.5f + 0.5f;
   lambert = max( lambert * a, 0.3f );
   
   // デカールマップ
   float4 decalmap = g_DecalMap.Sample( g_SamplerDecalMap, In.texel );

   return ( decalmap * lambert ).bgra;
}

ボリュームテクスチャーのサンプリング時に指定するw成分( Z方向 )は[ 0.0f 〜 1.0f ]の範囲内で指定するようです。

---DeepShadowMaps_Pass2.hlsl---  ↑


// ************************************************************
// Deep Shadow Maps ( 半透明メッシュのレンダリング用 )
// ************************************************************

// 定数バッファ
cbuffer CBuffer : register( b0 )
{
   float g_ZFar               : packoffset( c0.x );
};

cbuffer CBuffer : register( b1 )
{
   column_major float4x4 g_matLightViewProj   : packoffset( c0 );    // ライトビューのビュー射影行列
   column_major float4x4 g_matLightBillboardViewProj  : packoffset( c4 );    // ライトビューの射影空間上でパーティクルの大きさを計算するための行列
   column_major float4x4 g_matCameraViewProj   : packoffset( c8 );    // カメラビューのビュー射影行列
   column_major float4x4 g_matCameraBillboardViewProj  : packoffset( c12 );   // カメラビューの射影空間上でパーティクルの大きさを計算するための行列
};

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos           : POSITION;    // 頂点座標
   float  width         : TEXCOORD0;   // パーティクルのサイズ
   float  Attenuation   : TEXCOORD1;   // 透明度
};

// 頂点シェーダーの出力パラメータ
typedef VS_IN VS_OUT_GS_IN;

// ジオメトリシェーダーの出力パラメータ
struct GS_OUT_PS_IN
{
   float4 pos            : SV_POSITION;   // 頂点座標
   float2 texel          : TEXCOORD0;     // テクセル( ジオメトリシェーダー内で作成 )
   float  Attenuation    : TEXCOORD1;     // アルファ( 透明度 )
   float4 Lpos           : TEXCOORD2;     // ライトビューで行列変換した頂点座標
   float  z              : TEXCOORD3;     // ボリュームテクスチャーの深度
};

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

// ボリュームテクスチャー
Texture3D g_VolumeMap : register( t1 );

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

// 頂点シェーダー
VS_OUT_GS_IN DeepShadowMaps_Pass2_VS_Main( VS_IN In )
{
   return In;
}

// ジオメトリシェーダー
[maxvertexcount(6)]                                                             // ジオメトリシェーダーで出力する最大頂点数
void DeepShadowMaps_Pass2_GS_Main( point VS_OUT_GS_IN In[1],                    // ポイント プリミティブの入力情報
                                   inout TriangleStream<GS_OUT_PS_IN> TStream   // ポリゴン プリミティブの出力ストリーム
                                 )
{
   if( In[0].Attenuation <= 0.1f )
      return;

   // カメラビューでビュー射影行列でパーティクルの中心座標を変換
   float4 Ccenter = mul( float4( In[0].pos, 1 ), g_matCameraViewProj );
   // カメラビューの射影空間上でのパーティクルの大きさを計算する
   float4 Cwidth = mul( float4( In[0].width, In[0].width, In[0].pos.z, 1 ), g_matCameraBillboardViewProj );
   
   // ライトビューでビュー射影行列でパーティクルの中心座標を変換
   float4 Lcenter = mul( float4( In[0].pos, 1 ), g_matLightViewProj );
   // ライトビューでの射影空間上でのパーティクルの大きさを計算する
   float4 Lwidth = mul( float4( In[0].width, In[0].width, In[0].pos.z, 1 ), g_matLightBillboardViewProj );

   float layer = Lcenter.z / g_ZFar;
   
   float Cleft   = Ccenter.x - Cwidth.x;
   float Ctop    = Ccenter.y + Cwidth.y;
   float Cright  = Ccenter.x + Cwidth.x;
   float Cbottom = Ccenter.y - Cwidth.y;

   float Lleft   = Lcenter.x - Lwidth.x;
   float Ltop    = Lcenter.y + Lwidth.y;
   float Lright  = Lcenter.x + Lwidth.x;
   float Lbottom = Lcenter.y - Lwidth.y;

   GS_OUT_PS_IN vertex[4] = { 
      Cright, Ctop,    Ccenter.z, Ccenter.w, 1, 0, In[0].Attenuation, Lright, Ltop,    Lcenter.z, Lcenter.w, layer,   // 右上
      Cleft,  Ctop,    Ccenter.z, Ccenter.w, 0, 0, In[0].Attenuation, Lleft,  Ltop,    Lcenter.z, Lcenter.w, layer,   // 左上
      Cleft,  Cbottom, Ccenter.z, Ccenter.w, 0, 1, In[0].Attenuation, Lleft,  Lbottom, Lcenter.z, Lcenter.w, layer,   // 左下
      Cright, Cbottom, Ccenter.z, Ccenter.w, 1, 1, In[0].Attenuation, Lright, Lbottom, Lcenter.z, Lcenter.w, layer,   // 右下
   };
   
   TStream.Append( vertex[0] );  // 右上
   TStream.Append( vertex[1] );  // 左上
   TStream.Append( vertex[2] );  // 左下
   TStream.RestartStrip();

   TStream.Append( vertex[0] );  // 右上
   TStream.Append( vertex[2] );  // 左下
   TStream.Append( vertex[3] );  // 右下
   TStream.RestartStrip();
}

// ピクセルシェーダ
float4 DeepShadowMaps_Pass2_PS_Main( GS_OUT_PS_IN In ) : SV_TARGET
{
   float2 texel = float2( In.Lpos.x / In.Lpos.w * 0.5f + 0.5f, In.Lpos.y / In.Lpos.w * -0.5f + 0.5f );

   float a = 0;
   
   // 減衰率を加算
   [unroll(10)]
   for( float i=In.z; i>=0; i-=0.05f )
   {
      a += g_VolumeMap.Sample( g_Sampler, float3( texel, i ) ).r;
   }

   a = exp( -a * 0.1f );

   // テクスチャーカラーを取得
   float4 col = g_DecalMap.Sample( g_Sampler, In.texel );
   
   // 減衰率から影をかます
   col = float4( max( col.gbr * a , 0.3f ), min( col.a, In.Attenuation ) );
   
   return col;
}

---DeepShadowMaps.h---  ↑


#ifndef DEEP_SHADOW_MAPS_H
#define DEEP_SHADOW_MAPS_H

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

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

class DeepShadowMaps
{
private:
   typedef struct _CBUFFER_COMMON
   {
      float ZFar;
      UINT  Depth;
      float Dummy3;
      float Dummy4;
   }CBUFFER_COMMON;

   // 半透明メッシュによる減衰率マップ生成用
   typedef struct _CBUFFER_PASS0
   {
      // ライトビューのビューと射影行列
      XMMATRIX matLightViewProj;
      // ライトビューのビルボード処理したビューと射影行列
      XMMATRIX matLightBillboardViewProj;
   }CBUFFER_PASS0;

   // 不透明メッシュレンダリング用
   typedef struct _CBUFFER_PASS1
   {
      // ライトビューのワールドビュー射影行列
      XMMATRIX matLightWorldViewProj;
      // カメラビューのワールドビュー射影行列
      XMMATRIX matCameraWorldViewProj;
      XMFLOAT4 vecLightDir;
   }CBUFFER_PASS1;

   // 半透明メッシュレンダリング用
   typedef struct _CBUFFER_PASS2
   {
      // ライトビューのビューと射影行列
      XMMATRIX matLightViewProj;
      // ライトビューのビルボード処理したビューと射影行列
      XMMATRIX matLightBillboardViewProj;
      // カメラビューのビューと射影行列
      XMMATRIX matCameraViewProj;
      // カメラビューのビルボード処理したビューと射影行列
      XMMATRIX matCameraBillboardViewProj;
   }CBUFFER_PASS2;

   // パーティクルによる光の減衰率を書き込むためのボリュームテクスチャー用のレンダーターゲットビュー
   ID3D11RenderTargetView* m_pRTView;
   ID3D11ShaderResourceView* m_pSRViewOfRTView;

   // 減衰率マップサンプリング用サンプラーステート
   ID3D11SamplerState* m_pSamplerVolumeMap;

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

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

   UGraphicsPipeline* m_pGraphicsPipeline[3];

   UINT m_Width, m_Height, m_Depth;
   float m_ZFar;

   int m_Pass;

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

   XMMATRIX CreateBillboardMatrix( XMMATRIX* pMatView, XMMATRIX* pMatProj );
public:
   DeepShadowMaps();
   virtual ~DeepShadowMaps();
   void Invalidate();
   void Create( ID3D11Device* pD3DDevice, UINT Width, UINT Height, float ZFar, UINT Depth );
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass,
                   XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj );
   void SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld );
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
   inline const ID3D11ShaderResourceView* GetDepthMap(){ return m_pSRViewOfRTView; };
};

#endif

---DeepShadowMaps.cpp---  ↑


#include "../../Header/Shader/DeepShadowMaps.h"
#include "../../HLSL/DeepShadowMaps_Pass0_VS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass0_GS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass0_PS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass1_VS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass1_PS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass2_VS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass2_GS_Main.h"
#include "../../HLSL/DeepShadowMaps_Pass2_PS_Main.h"

DeepShadowMaps::DeepShadowMaps()
{
   m_pRTView = nullptr;
   m_pSRViewOfRTView = nullptr;
   for( int i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      m_pGraphicsPipeline[i] = nullptr;
      m_pConstantBuffers[i] = nullptr;
   }
   m_pConstantBuffersCommon = nullptr;
   m_pSamplerVolumeMap = nullptr;
   
   m_Pass = -1;
}

DeepShadowMaps::~DeepShadowMaps()
{
   SAFE_RELEASE( m_pSamplerVolumeMap );
   SAFE_RELEASE( m_pConstantBuffersCommon );
   for( int i=0; i<_countof( m_pGraphicsPipeline ); i++ )
   {
      SAFE_DELETE( m_pGraphicsPipeline[i] );
      SAFE_RELEASE( m_pConstantBuffers[i] );
   }
   SAFE_RELEASE( m_pSRViewOfRTView );
   SAFE_RELEASE( m_pRTView );
}

void DeepShadowMaps::Create( ID3D11Device* pD3DDevice, UINT Width, UINT Height, float ZFar, UINT Depth )
{
   m_Width = Width;
   m_Height = Height;
   m_Depth = Depth;
   m_ZFar = ZFar;

   m_Pass = -1;

   // *******************************************************************************************************
   // 半透明メッシュによる減衰率マップ生成用UGraphicsPipelineの作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[0] = NEW UGraphicsPipeline();

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

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

   // ブレンドステートを作成する( ボリュームテクスチャーに光の減衰率を書き込むため加算合成 )
   UGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UGraphicsPipeline::UEBLEND_STATE::ADD };
   m_pGraphicsPipeline[0]->CreateBlendState( pD3DDevice, BlendStateType, 1 );

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

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[0]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass0.hlsl"), "DeepShadowMaps_Pass0_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreateGeometryShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass0.hlsl"), "DeepShadowMaps_Pass0_GS_Main" );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass0.hlsl"), "DeepShadowMaps_Pass0_PS_Main" );
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass0_VS_Main, sizeof( g_DeepShadowMaps_Pass0_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[0]->CreateGeometryShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass0_GS_Main, sizeof( g_DeepShadowMaps_Pass0_GS_Main ) );
   m_pGraphicsPipeline[0]->CreatePixelShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass0_PS_Main, sizeof( g_DeepShadowMaps_Pass0_PS_Main ) );
#endif

   // ボリュームテクスチャーのレンダーターゲットビューを作成する
   UMaps::CreateRenderTargetViewOfVolumeTexture( pD3DDevice, DXGI_FORMAT_R16_FLOAT, m_Width, m_Height, Depth, &m_pRTView, &m_pSRViewOfRTView );

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

   // *******************************************************************************************************
   // 不透明メッシュのレンダリング用UGraphicsPipelineの作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[1] = NEW UGraphicsPipeline();

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

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

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

   // 減衰率マップ用のサンプラーステートを作成する
   m_pSamplerVolumeMap = USamplers::CreateSamplerState( pD3DDevice, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT );
   
   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[1]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass1.hlsl"), "DeepShadowMaps_Pass1_VS_Main", layout1, _countof( layout ) );
   m_pGraphicsPipeline[1]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass1.hlsl"), "DeepShadowMaps_Pass1_PS_Main" );
#else
   m_pGraphicsPipeline[1]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass1_VS_Main, sizeof( g_DeepShadowMaps_Pass1_VS_Main ), layout1, _countof( layout ) );
   m_pGraphicsPipeline[1]->CreatePixelShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass1_PS_Main, sizeof( g_DeepShadowMaps_Pass1_PS_Main ) );
#endif

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

   // *******************************************************************************************************
   // 半透明メッシュレンダリング用UGraphicsPipelineの作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[2] = NEW UGraphicsPipeline();

   // 深度ステンシルステートを作成する( 深度ステンシルバッファへの書き込みしない )
   m_pGraphicsPipeline[2]->CreateDepthStencilState( pD3DDevice, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ZERO );

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

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[2]->CreateVertexShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass2.hlsl"), "DeepShadowMaps_Pass2_VS_Main", layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreateGeometryShaderFromFile( pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass2.hlsl"), "DeepShadowMaps_Pass2_GS_Main" );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromFile(  pD3DDevice, _T("../HLSL/DeepShadowMaps_Pass2.hlsl"), "DeepShadowMaps_Pass2_PS_Main" );
#else
   m_pGraphicsPipeline[2]->CreateVertexShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass2_VS_Main, sizeof( g_DeepShadowMaps_Pass2_VS_Main ), layout, _countof( layout ) );
   m_pGraphicsPipeline[2]->CreateGeometryShaderFromMemory(  pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass2_GS_Main, sizeof( g_DeepShadowMaps_Pass2_GS_Main ) );
   m_pGraphicsPipeline[2]->CreatePixelShaderFromMemory( pD3DDevice, (LPBYTE)g_DeepShadowMaps_Pass2_PS_Main, sizeof( g_DeepShadowMaps_Pass2_PS_Main ) );
#endif

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

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

   m_Pass = (int)Pass;

   switch( m_Pass )
   {
   case 0:
      {
         // 深度ステンシルビューを切り替える。レンダーターゲットビューは使用しない。

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

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

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

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

         pD3DDeviceContext->ClearRenderTargetView( m_pRTView, ClearColor ); 

         m_VecLightPos = *pVecLightPos;

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

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

   case 1:
      {
         // 減衰率を書き込んだボリュームテクスチャーをシェーダーに設定
         pD3DDeviceContext->PSSetShaderResources( 1, 1, &m_pSRViewOfRTView );

         pD3DDeviceContext->PSSetSamplers( 1, 1, &m_pSamplerVolumeMap );

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

   case 2:
      {
         // 減衰率を書き込んだボリュームテクスチャーをシェーダーに設定
         pD3DDeviceContext->PSSetShaderResources( 1, 1, &m_pSRViewOfRTView );
      }
      break;
   }

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

XMMATRIX DeepShadowMaps::CreateBillboardMatrix( XMMATRIX* pMatView, XMMATRIX* pMatProj )
{
   // ビルボーディング処理したビュー行列と射影行列
   // ただしビュー行列の平行移動はz成分のみ使用する
   XMMATRIX mat = XMMatrixIdentity();
   // 射影空間上でのパーティクルの幅を計算するためにビュー行列のz値のみ使う
   mat._43 = pMatView->_43;
   mat = mat * *pMatProj;
   return XMMatrixTranspose( mat );
}

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

   if (m_Pass == -1)
   {
      throw(UException(-1, _T("DeepShadowMaps::SetConstantBuffers()はBeginPass()実行後に使用してください")));
   }

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

         XMMATRIX matLightBillboardViewProj = CreateBillboardMatrix( &m_MatLightView, &m_MatLightProj );

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

         // 定数バッファをロックする
         if( FAILED( hr = pD3DDeviceContext->Map( m_pConstantBuffersCommon, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
            throw( UException( -1, _T("DeepShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。") ) );
         DeepShadowMaps::CBUFFER_COMMON* cbufferCommon = (DeepShadowMaps::CBUFFER_COMMON*)mappedResource.pData;
         cbufferCommon->ZFar = m_ZFar;
         // ボリュームテクスチャーの深度
         cbufferCommon->Depth = m_Depth;
         pD3DDeviceContext->Unmap( m_pConstantBuffersCommon, 0 );

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

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

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

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

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

   case 2:
      {
         // ライトビューでのビュー行列と射影行列
         XMMATRIX matLightViewProj = XMMatrixTranspose( m_MatLightView * m_MatLightProj );

         XMMATRIX matLightBillboardViewProj = CreateBillboardMatrix( &m_MatLightView, &m_MatLightProj );

         // カメラビューでのビュー行列と射影行列
         XMMATRIX matCameraViewProj = XMMatrixTranspose( m_MatCameraView * m_MatCameraProj );

         XMMATRIX matCameraBillboardViewProj = CreateBillboardMatrix( &m_MatCameraView, &m_MatCameraProj );

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

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

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

      pD3DDeviceContext->OMSetRenderTargets( 1, &m_pOldRTView, m_pOldDSView );
      SAFE_RELEASE( m_pOldRTView );
      SAFE_RELEASE( m_pOldDSView );

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

   case 1:
      {
         ID3D11ShaderResourceView* pSRViewNull = nullptr;
         pD3DDeviceContext->PSSetShaderResources( 1, 1, &pSRViewNull );

         ID3D11SamplerState* pSamplerNull = nullptr;
         pD3DDeviceContext->PSSetSamplers( 1, 1, &pSamplerNull );
      }
      break;

   case 2:
      {
         ID3D11ShaderResourceView* pSRViewNull = nullptr;
         pD3DDeviceContext->PSSetShaderResources( 1, 1, &pSRViewNull );
      }
      break;
   }
   
   m_Pass = -1;
}

---ParticlesMesh.h---  ↑


#ifndef PARTICLESMESH_H
#define PARTICLESMESH_H

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

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

class ParticlesMesh
{
private:
   typedef struct _PARTICLE
   {
      // 入力レイアウト用
      typedef struct _VERTEX
      {
         XMFLOAT3 Position;      // 座標
         FLOAT    Width;         // パーティクルのサイズ
         FLOAT    Transparency;  // 透明度
      }VERTEX;
      
      VERTEX Vertex;

      XMFLOAT3 Velocity;        // 速度
      FLOAT    AddTransparency; // 透明度の加算値
      FLOAT    Flicker;         // xz平面上での移動方向の揺らぎ.sin波.
      FLOAT    FlickerRadius;   // 揺らぎの半径
      FLOAT    FlickerSpeed;    // 揺らぎの速度
      FLOAT    AddWidth;        // パーティクルのサイズの加算値
   }PARTICLE;

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

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

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

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

   PARTICLE* m_pParticleArray;
   PARTICLE::VERTEX* m_pSortedVertex;
   UINT* m_pIndexArray;
   UINT m_ParticleCount;

   // パーティクルの初期座標
   XMFLOAT3 m_InitialPosition;

   // パーティクルの半径
   float m_ParticleRadius;

   // ランダム値取得
   inline float GetRandomize(){ return (float)(rand()%100 - 50) / 50.0f; };
   inline float GetRandomizeZeroToOne(){ return (float)(rand()%100) / 100.0f; };

   // パーティクルの初期化
   void InitializeParticle( UINT Index );

public:
   ParticlesMesh();
   virtual ~ParticlesMesh();
   void Invalidate();
   void CreateMesh( ID3D11Device* pD3DDevice, UINT ParticleCount, float ParticleRadius, XMFLOAT3* pInitialPosition );
   void NextFrame();
   inline UINT GetParticleCount(){ return m_ParticleCount; };
   void Render( ID3D11DeviceContext* pD3DDeviceContext );
};

#endif

---ParticlesMesh.cpp---  ↑


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

ParticlesMesh::ParticlesMesh()
{
   m_pVertexBuffer = nullptr;
   m_pIndexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
   m_pParticleArray = nullptr;
   m_pSortedVertex = nullptr;
   m_pIndexArray = nullptr;
   m_ParticleCount = 0;
}

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

void ParticlesMesh::Invalidate()
{
   m_ParticleCount = 0;
   SAFE_DELETE_ARRAY( m_pIndexArray );
   SAFE_DELETE_ARRAY( m_pSortedVertex );
   SAFE_DELETE_ARRAY( m_pParticleArray );
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pIndexBuffer );
   SAFE_RELEASE( m_pVertexBuffer );
}

void ParticlesMesh::CreateMesh( ID3D11Device* pD3DDevice, UINT ParticleCount, float ParticleRadius, XMFLOAT3* pInitialPosition )
{
   m_ParticleCount = ParticleCount;
   m_InitialPosition = *pInitialPosition;
   m_ParticleRadius = ParticleRadius;

   m_pParticleArray = NEW PARTICLE[m_ParticleCount];
   m_pSortedVertex = NEW PARTICLE::VERTEX[m_ParticleCount];
   m_pIndexArray = NEW UINT[m_ParticleCount];

   for( UINT i=0; i<GetParticleCount(); i++ )
   {
      InitializeParticle( i );
   }

   // 頂点バッファを作成する
   m_pVertexBuffer = UBuffers::CreateVertexBuffer( pD3DDevice, nullptr, sizeof( PARTICLE::VERTEX ) * m_ParticleCount, D3D11_CPU_ACCESS_WRITE );

   // インデックスバッファを作成する
   m_pIndexBuffer = UBuffers::CreateIndexBuffer( pD3DDevice, nullptr, sizeof( UINT ) * m_ParticleCount, D3D11_CPU_ACCESS_WRITE );

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

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

// パーティクルの初期化
void ParticlesMesh::InitializeParticle( UINT Index )
{
   const float MaxVelocity = 0.05f;        // 初速度
   const float InitialRadius = 10.0f;      // 初期位置のxz平面上での半径
   const float AddTransparency = 0.0004f;  // 透明度の加算値
   const float FlickerRadius = 0.02f;      // xz平面上への揺らぎ半径
   const float FlickerSpeed = 0.002f;      // 揺らぎの移動速度
   const float AddWidth = 0.01f;           // パーティクルのサイズの加算値

   // パーティクルのxy平面上の初期位置の半径を計算する
   float initRadius = GetRandomize();
   initRadius = InitialRadius;

   // パーティクルのxy平面上の初期位置の方向を計算する
   float initDir = GetRandomize() * XM_2PI;

   m_pParticleArray[Index].Vertex.Position = XMFLOAT3( m_InitialPosition.x + sinf( initDir ) * initRadius,
                                                       m_InitialPosition.y,
                                                       m_InitialPosition.z + cosf( initDir ) * initRadius );
     
   // パーティクルのサイズ
   m_pParticleArray[Index].Vertex.Width = m_ParticleRadius;

   // 減衰率
   m_pParticleArray[Index].Vertex.Transparency = 1.0f;

   // 速度を適当に揺らぎをもたせて初期化
   float initVelocity = ( GetRandomizeZeroToOne() + 1.0f ) * 0.5f * MaxVelocity;

   XMFLOAT3 vel = XMFLOAT3( GetRandomize() * 0.3f, ( GetRandomizeZeroToOne() + 0.5f ), GetRandomize() * 0.3f );
   XMVECTOR vel2 = XMVector3Normalize( XMLoadFloat3( &vel ) );
   vel2 = XMVectorScale( vel2, initVelocity );
   XMStoreFloat3( &vel, vel2 );
   m_pParticleArray[Index].Velocity = vel;

   // 透明度の加算値
   m_pParticleArray[Index].AddTransparency = -( GetRandomizeZeroToOne() + 1.0f ) * 0.5f * AddTransparency;

   // 揺らぎ
   m_pParticleArray[Index].Flicker = GetRandomize() * XM_2PI;

   // 揺らぎの半径
   m_pParticleArray[Index].FlickerRadius = GetRandomizeZeroToOne() * FlickerRadius;

   // 揺らぎの速度
   m_pParticleArray[Index].FlickerSpeed = GetRandomize() * FlickerSpeed;

   // パーティクルのサイズの加算値
   m_pParticleArray[Index].AddWidth = GetRandomizeZeroToOne() * AddWidth;

   // インデックス配列
   m_pIndexArray[Index] = Index;

   ::CopyMemory( &m_pSortedVertex[Index], &m_pParticleArray[Index].Vertex, sizeof( PARTICLE::VERTEX ) );
}

void ParticlesMesh::NextFrame()
{
   for( UINT i=0; i<GetParticleCount(); i++ )
   {
      if( m_pParticleArray[i].Vertex.Transparency > 0.1f )
      {
         // ワールド空間上でのパーティクルの各種状態の更新

         // 揺らぎの更新
         m_pParticleArray[i].Flicker += m_pParticleArray[i].FlickerSpeed;

         // 座標更新
         m_pParticleArray[i].Vertex.Position.x += m_pParticleArray[i].Velocity.x +
            sinf( m_pParticleArray[i].Flicker ) * m_pParticleArray[i].FlickerRadius;

         m_pParticleArray[i].Vertex.Position.y += m_pParticleArray[i].Velocity.y;

         m_pParticleArray[i].Vertex.Position.z += m_pParticleArray[i].Velocity.z +
            cosf( m_pParticleArray[i].Flicker ) * m_pParticleArray[i].FlickerRadius;

         // 透明度の更新
         m_pParticleArray[i].Vertex.Transparency += m_pParticleArray[i].AddTransparency;

         // パーティクルのサイズの更新
         m_pParticleArray[i].Vertex.Width += m_pParticleArray[i].AddWidth;

         // インデックス配列
         m_pIndexArray[i] = i;

         ::CopyMemory( &m_pSortedVertex[i], &m_pParticleArray[i].Vertex, sizeof( PARTICLE::VERTEX ) );
      }

      else
      {
         InitializeParticle( i );
      }
   }
}

void ParticlesMesh::Render( ID3D11DeviceContext* pD3DDeviceContext )
{
   HRESULT hr = E_FAIL;

   // 頂点バッファ
   D3D11_MAPPED_SUBRESOURCE mappedResource;
   PARTICLE::VERTEX* cBuffer;
   if( FAILED( hr = pD3DDeviceContext->Map( m_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
      throw( UException( hr, _T("ParticlesMesh::Render()でエラーが発生しました。ロックできません") ) );
   cBuffer = (PARTICLE::VERTEX*)(mappedResource.pData);
   ::CopyMemory( cBuffer, m_pSortedVertex, sizeof( PARTICLE::VERTEX ) * GetParticleCount() );
   pD3DDeviceContext->Unmap( m_pVertexBuffer, 0 );

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

   // インデックスバッファ
   UINT* cBuffer2;
   if( FAILED( hr = pD3DDeviceContext->Map( m_pIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ) ) )
      throw( UException( hr, _T("ParticlesMesh::Render()でエラーが発生しました。ロックできません") ) );
   cBuffer2 = (UINT*)(mappedResource.pData);
   ::CopyMemory( cBuffer2, m_pIndexArray, sizeof( UINT ) * GetParticleCount() ); 
   pD3DDeviceContext->Unmap( m_pIndexBuffer, 0 );

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

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

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

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

   // 描画
   pD3DDeviceContext->DrawIndexed( m_ParticleCount, 0, 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/DeepShadowMaps.h"

#include "../Header/Mesh/F14Mesh.h"
#include "../Header/Mesh/PlaneMesh.h"
#include "../Header/Mesh/ParticlesMesh.h"

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

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

DeepShadowMaps* g_pDeepShadowMaps = nullptr;

F14Mesh* g_pF14Mesh = nullptr;
PlaneMesh* g_pPlaneMesh = nullptr;
ParticlesMesh* g_pParticlesMesh = nullptr;

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

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

DWORD g_Width = 640, g_Height = 480;
float LZFar = 1000.0f, LZNear = 10.0f;

float g_VolumeLevel = 0;

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

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

// ライトビュー射影行列
XMMATRIX g_MatLightProj = XMMatrixPerspectiveFovLH( XM_PI / 4.0f, 1, LZNear, LZFar );

// 平行光源の位置ベクトル
XMFLOAT4 g_VecLightPos = XMFLOAT4( 0.0f, 200.0f, 340.0f, 0 );

// メモリ解放
void Invalidate()
{
#if defined(DEBUG) || defined(_DEBUG)
   SAFE_DELETE( g_pSRViewRenderer );
#endif
   SAFE_DELETE( g_pDeepShadowMaps );
   SAFE_DELETE( g_pFPS );
   SAFE_DELETE( g_pDebugFont );
   SAFE_DELETE( g_pParticlesMesh );
   SAFE_DELETE( g_pPlaneMesh );
   SAFE_DELETE( g_pF14Mesh );
   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 );

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

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

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

void CreateGraphicePipeline()
{
   DWORD Width = 128, Height = 128, ArraySize = 20;

   g_pDeepShadowMaps->Create( g_pDirect3D11->m_pD3DDevice, Width, Height, LZFar, ArraySize );
}

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

   g_pPlaneMesh = NEW PlaneMesh();
   g_pPlaneMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice );

   g_pParticlesMesh = NEW ParticlesMesh();
   g_pParticlesMesh->CreateMesh( g_pDirect3D11->m_pD3DDevice, 50, 20.0f, &XMFLOAT3( 0.0f, -35.0f, 80.0f ) );
}

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

   g_pDeepShadowMaps = NEW DeepShadowMaps();

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

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

   // Direct3Dの作成
   CreateDirect3D( hInstance );

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

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

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

   if( GetKeyState( 'V' ) & 0x8000 )
   {
      g_VolumeLevel += 0.001f;
      if( g_VolumeLevel > 1.0f )
         g_VolumeLevel = 1.0f;
   }
   if( GetKeyState( 'B' ) & 0x8000 )
   {
      g_VolumeLevel -= 0.001f;
      if( g_VolumeLevel < 0.0f )
         g_VolumeLevel = 0.0f;
   }

   g_pFPS->NextFrame();

   g_pF14Mesh->NextFrame();
   g_pPlaneMesh->NextFrame();
   g_pParticlesMesh->NextFrame();

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

// 描画処理
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 );

   // 半透明メッシュによる減衰率マップを作成
   g_pDeepShadowMaps->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 0, &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj );
   g_pDeepShadowMaps->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, nullptr );
   g_pParticlesMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
   g_pDeepShadowMaps->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

   // 不透明メッシュをレンダリング
   g_pDeepShadowMaps->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 1, &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj );
   g_pDeepShadowMaps->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pPlaneMesh->GetMatWorld() );
   g_pPlaneMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
   for( UINT j=0; j<g_pF14Mesh->GetMaxCount(); j++ )
   {
      g_pDeepShadowMaps->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, g_pF14Mesh->GetMatWorld(j) );
      g_pF14Mesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
   }
   g_pDeepShadowMaps->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

   // 半透明メッシュをレンダリング
   g_pDeepShadowMaps->BeginPass( g_pDirect3D11->m_pD3DDeviceContext, 2, &g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj );
   g_pDeepShadowMaps->SetConstantBuffers( g_pDirect3D11->m_pD3DDeviceContext, nullptr );
   g_pParticlesMesh->Render( g_pDirect3D11->m_pD3DDeviceContext );
   g_pDeepShadowMaps->EndPass( g_pDirect3D11->m_pD3DDeviceContext );

#if defined(DEBUG) || defined(_DEBUG)
   int SrvRGB[] = { 0, 1, 2, 3 };
   g_pSRViewRenderer->SetSRView( g_pDeepShadowMaps->GetDepthMap(), SrvRGB, g_VolumeLevel );
   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;
}

パーティクルにも影つけてますが、ソートしてないので正しくはないです。


web拍手 by FC2

Prev Top Next

inserted by FC2 system