Microsoft Visual C++ 2010 Express
 Microsoft DirectX SDK (June 2010)
 Direct3D 11.0
 Shader Model 4.0
 FBX SDK 2011.3

■Direct3D 11.0 ディファードパーティクル Prev Top Next
関連ページ:Direct3D 11.0 初期化 Direct3D 11.0 デバック用フォント描画 FBX SDKを使う Direct3D 11.0 動的シェーダーリンク
2012/05/06:
  1. ほとんど作り直し...


DeferredParticles
ForwardParticles

今回はディファードパーティクル( 遅延パーティクル )をやります。かなり改造していますが、ベースは Direct3D 10 のサンプルです。 ですので解説はオンラインドキュメント参照というところでお願いします。

ParticleSystem.h パーティクルシステムクラスのヘッダファイル。
ParticleSystem.cpp パーティクルシステムクラスのソースファイル。
DeferredParticles.hlsl ディファードパーティクルクラスのhlslファイル。
DeferredParticles.h ディファードパーティクルクラスのヘッダファイル。
DeferredParticles.cpp ディファードパーティクルクラスのソースファイル。
ForwardParticles.hlsl フォワードパーティクルクラスのhlslファイル。ディファードパーティクルとの比較のために作成したおまけファイル。
ForwardParticles.h フォワードパーティクルクラスのヘッダファイル。ディファードパーティクルとの比較のために作成したおまけファイル。
ForwardParticles.cpp フォワードパーティクルクラスのソースファイル。ディファードパーティクルとの比較のために作成したおまけファイル。
main.cpp メイン関数があるソースファイル。


---ParticleSystem.h---  ↑

#ifndef PARTICLESYSTEM_H
#define PARTICLESYSTEM_H

class PARTICLESYSTEM
{
public:
   // パーティクルのパラメータ
   typedef struct _PARTICLE
   {
      D3DXVECTOR3 Pos;     // 表示座標
      float LifeAndAlpha;  // パーティクルのライフおよびアルファ値
      float Size;          // パーティクルのサイズ
      float AddAlpha;
   }PARTICLE;

   // 頂点定義
   typedef struct _PARTICLE_VERTEX
   {
      D3DXVECTOR3 Vertex;
      D3DXVECTOR2 UV;
   }PARTICLE_VERTEX;

   // 入力アセンブラ用定数バッファ0
   typedef struct _IBUFFER0
   {
      // ワールド × ビュー × 射影 行列
      D3DXMATRIX  matWVP;
      // 頂点カラー
      D3DXVECTOR4 Color;
   }IBUFFER0;

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

   // 入力アセンブラにデータを追加するためのバッファ
   ID3D11Buffer* m_pInputBuffer;

   // デカールマップ
   ID3D11ShaderResourceView* m_pSRVDecalMap;
   
   // パーティクルのパラメータ
   PARTICLE* m_pParticleArray;

   // パーティクルの数
   UINT m_NumParticles;

   // パーティクルのサイズ
   float m_ParticleSize;

   // パーティクルの描画範囲
   float m_ParticleRenderRange;

private:
   // パーティクルの初期化
   void InitParticleParam();
   // 深度値によりパーティクルをバブルソート
   void BubbleSortParticles( D3DXMATRIX* pMatView );

public:

   PARTICLESYSTEM();
   ~PARTICLESYSTEM();

   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice
               , UINT NumParticles
               , float SizeParticle
               , float Range
               , TCHAR pTextureFileNames[]
               );

   // 座標更新
   void NextFrame( D3DXMATRIX* pMatView );

   inline const float GetParticleSize(){ return m_ParticleSize; };
   inline const PARTICLE* GetParticles(){ return m_pParticleArray; };
   inline const UINT GetNumParticles(){ return m_NumParticles; };
   inline ID3D11Buffer* GetVertexBuffer(){ return m_pVertexBuffer; };
   inline ID3D11Buffer* GetInputBuffer(){ return m_pInputBuffer; };
   inline ID3D11ShaderResourceView* GetShaderResourceView(){ return m_pSRVDecalMap; };
};

#endif

---ParticleSystem.cpp---  ↑


#include "DX11User.h"
#include "ParticleSystem.h"

PARTICLESYSTEM::PARTICLESYSTEM()
{
   m_pParticleArray = NULL;
   m_pVertexBuffer = NULL;
   m_pInputBuffer = NULL;
   m_pSRVDecalMap = NULL;
}

PARTICLESYSTEM::~PARTICLESYSTEM()
{
   SAFE_DELETE_ARRAY( m_pParticleArray );
   SAFE_RELEASE( m_pVertexBuffer );
   SAFE_RELEASE( m_pInputBuffer );
   SAFE_RELEASE( m_pSRVDecalMap );
}

// 初期化
HRESULT PARTICLESYSTEM::Init( ID3D11Device* pD3DDevice
                            , UINT NumParticles
                            , float ParticleSize
                            , float ParticleRenderRange
                            , TCHAR pTextureFileNames[]
                            )
{
   HRESULT hr = E_FAIL;
   D3D11_BUFFER_DESC BufferDesc;
   D3DX11_IMAGE_LOAD_INFO info;

   // パーティクル数
   m_NumParticles = NumParticles;

   // パーティクルのサイズ
   m_ParticleSize = ParticleSize;

   // パーティクルを描画範囲
   m_ParticleRenderRange = ParticleRenderRange;

   m_pParticleArray = NEW PARTICLE[m_NumParticles];
   ::ZeroMemory( m_pParticleArray, sizeof( PARTICLE ) * m_NumParticles );

   // 座標とアルファ値を初期化
   InitParticleParam();

   // *****************************************************************************************************************
   // パーティクルの頂点座標の初期化
   // *****************************************************************************************************************

   PARTICLE_VERTEX VertexArray[4] = { D3DXVECTOR3( 1.0f, 1.0f, 0.0f ),   D3DXVECTOR2( 1.0f, 0.0f )
                                    , D3DXVECTOR3( -1.0f, 1.0f, 0.0f ),  D3DXVECTOR2( 0.0f, 0.0f )
                                    , D3DXVECTOR3( 1.0f, -1.0f, 0.0f ),  D3DXVECTOR2( 1.0f, 1.0f )
                                    , D3DXVECTOR3( -1.0f, -1.0f, 0.0f ), D3DXVECTOR2( 0.0f, 1.0f )
                                    };

   // バッファー リソース
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( PARTICLE_VERTEX ) * _countof( VertexArray ); // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DEFAULT;       // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_VERTEX_BUFFER;  // バッファの種類
   BufferDesc.CPUAccessFlags        = 0;                         // CPU アクセスしない
   BufferDesc.MiscFlags             = 0;                         // その他のフラグも設定しない
   // サブリソース( 初期値 )
   D3D11_SUBRESOURCE_DATA resource;
   resource.pSysMem = (void*)VertexArray;
   resource.SysMemPitch = 0;
   resource.SysMemSlicePitch = 0;
   // バッファを作成する
   hr = pD3DDevice->CreateBuffer( &BufferDesc, &resource, &m_pVertexBuffer );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 入力アセンブラ用のバッファを作成
   // *****************************************************************************************************************

   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = NumParticles * sizeof( IBUFFER0 );   // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DYNAMIC;                 // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_VERTEX_BUFFER;            // バッファの種類
   BufferDesc.CPUAccessFlags        = D3D11_CPU_ACCESS_WRITE;              // CPU アクセスする
   BufferDesc.MiscFlags             = 0;                                   // その他のフラグも設定しない
   hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_pInputBuffer );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // デカールマップの初期化
   // *****************************************************************************************************************

   // ファイルからシェーダーリソースビューを作成する
   ::ZeroMemory( &info, sizeof( D3DX11_IMAGE_LOAD_INFO ) );
   info.Width = D3DX11_DEFAULT; 
   info.Height = D3DX11_DEFAULT; 
   info.Depth = D3DX11_DEFAULT; 
   info.FirstMipLevel = D3DX11_DEFAULT;          // テクスチャーの最高解像度のミップマップ レベル。
   info.MipLevels = 0;                           // ミップマップ数。0 または D3DX11_DEFAULT を使用するとすべてのミップマップ チェーンを作成する。
   info.Usage = D3D11_USAGE_DEFAULT; 
   info.BindFlags = D3D11_BIND_SHADER_RESOURCE;
   info.CpuAccessFlags = 0;
   info.MiscFlags = 0;
   info.Format = DXGI_FORMAT_FROM_FILE;
   info.Filter = D3DX11_FILTER_POINT;            // テクスチャー読み込み時に使用するフィルター
   info.MipFilter = D3DX11_FILTER_POINT;         // ミップマップ作成時に使用するフィルター
   info.pSrcInfo = NULL;
   hr = D3DX11CreateShaderResourceViewFromFile( pD3DDevice, pTextureFileNames, &info, NULL, &m_pSRVDecalMap, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// パーティクルの初期化
void PARTICLESYSTEM::InitParticleParam()
{
   for( UINT i=0; i<m_NumParticles; i++ )
   {
      if( m_pParticleArray[i].LifeAndAlpha <= 0.0f )
      {
         m_pParticleArray[i].Pos = D3DXVECTOR3( static_cast<float>( rand() % 100 - 50 ) / 50.0f * m_ParticleRenderRange
                                              , static_cast<float>( rand() % 100 - 50 ) / 50.0f * m_ParticleRenderRange
                                              , static_cast<float>( rand() % 100 - 50 ) / 50.0f * m_ParticleRenderRange
                                              );
         m_pParticleArray[i].LifeAndAlpha = 1.0f;
         m_pParticleArray[i].Size = m_ParticleSize;
         m_pParticleArray[i].AddAlpha = -0.00005f - static_cast<float>( rand() % 100 ) * 0.000005f;
      }
   }
}

// 深度値によりパーティクルをバブルソート
void PARTICLESYSTEM::BubbleSortParticles( D3DXMATRIX* pMatView )
{
   D3DXVECTOR4 v1, v2;
   PARTICLE temp;
   for( UINT i=0; i<m_NumParticles; i++ )
   {
      if( m_pParticleArray[i].LifeAndAlpha == 0.0f )
         continue;

      D3DXVec3Transform( &v1, &m_pParticleArray[i].Pos, pMatView );

      for( UINT j=i; j<m_NumParticles; j++ )
      {
         if( m_pParticleArray[j].LifeAndAlpha == 0.0f )
            continue;

         D3DXVec3Transform( &v2, &m_pParticleArray[j].Pos, pMatView );

         // 深度値で奥から手前にむかってソート
         if( v1.z < v2.z )
         {
            ::CopyMemory( &temp, &m_pParticleArray[i], sizeof( PARTICLE ) );
            ::CopyMemory( &m_pParticleArray[i], &m_pParticleArray[j], sizeof( PARTICLE ) );
            ::CopyMemory( &m_pParticleArray[j], &temp, sizeof( PARTICLE ) );

            D3DXVec3Transform( &v1, &m_pParticleArray[i].Pos, pMatView );
         }
      }
   }
}

// 更新
void PARTICLESYSTEM::NextFrame( D3DXMATRIX* pMatView )
{
   // アルファ値の更新
   for( UINT i=0; i<m_NumParticles; i++ )
   {
      if( m_pParticleArray[i].LifeAndAlpha > 0.0f )
      {
         m_pParticleArray[i].LifeAndAlpha += m_pParticleArray[i].AddAlpha;
      }
   }

   // パーティクルの初期化
   InitParticleParam();

   // ソート
   BubbleSortParticles( pMatView );
}

パーティクルクラスです。生成と消滅を繰り返すだけでまったく運動しない超シンプル設計です。 ソートロジックは低速なバブルソートを使用していて、効率も悪いのであまり参考にしないように。

---DeferredParticles.hlsl---  ↑

// ************************************************************
// ParticlesIntoBuffer フェーズ
// ************************************************************

// 頂点シェーダーの入力パラメータ
struct VS0_IN
{
   float3 pos    : POSITION;           // 頂点座標
   float2 texel  : TEXCOORD;           // テクセル
   column_major float4x4 mat : MATRIX; // インスタンスごとに設定される行列
   float4 color  : COLOR;              // 頂点カラー( 使用するのはアルファ値のみ )
};

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

Texture2D g_DecalMap : register( t0 );  // デカールマップ

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

// 頂点シェーダー
VS0_OUT ParticlesIntoBuffer_VS_Main( VS0_IN In )
{
   VS0_OUT Out;
   Out.sv_pos = mul( float4( In.pos, 1.0f ), In.mat );
   Out.texel = In.texel;
   Out.color = In.color;
   return Out;
}

// ピクセルシェーダ
float4 ParticlesIntoBuffer_PS_Main( VS0_OUT In ) : SV_TARGET0
{
   float4 Out;
     
   float4 decalmap = g_DecalMap.Sample( g_Sampler0, In.texel );
   
   float alpha = In.color.a * decalmap.a;
   
   // 法線ベクトルを 0 〜 1 範囲を -1 〜 1 に変換する
   decalmap.rg = decalmap.rg * 2.0f - 1.0f;
   decalmap.r *= -1.0f;
   // 法線ベクトルおよび、アルファ値を出力
   Out = float4( decalmap.rg, 0, alpha );

   return Out;
}

// ************************************************************
// CompositeParticles フェーズ
// ************************************************************

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

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

Texture2D g_NormalMap : register( t0 );  // 法線マップ

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

// 定数バッファ0
cbuffer cbBuffer0 : register( b0 )
{
   float4 g_vecLight    : packoffset( c0 );    // 平行光源の方向ベクトル
   float4 g_Color       : packoffset( c1 );    // パーティクルカラー
};

// 頂点シェーダー
VS1_OUT CompositeParticles_VS_Main( VS1_IN In )
{
   VS1_OUT Out;
   Out.sv_pos = float4( In.pos, 1 );
   Out.texel = In.texel;
   return Out;
}

// ピクセルシェーダ
float4 CompositeParticles_PS_Main( VS1_OUT In ) : SV_TARGET0
{
   float4 Out;

   float4 normalmap = g_NormalMap.Sample( g_Sampler1, In.texel );

   float3 normal = float3( 0, 0, -1 );
   normal.rg += float2( normalmap.x, normalmap.y );
   normal = normalize( normal );

   // ライティング
   float diffuse = dot( normal, -g_vecLight.xyz );
   diffuse = diffuse * 0.5f + 0.5f;
   
   Out = float4( g_Color.rgb * diffuse, normalmap.a );

   return Out;
}

---DeferredParticles.h---  ↑

#ifndef DEFERRED_PARTICLES_H
#define DEFERRED_PARTICLES_H

#include "Polygon2DUser.h"

class DEFERRED_PARTICLES
{
private:
   // 定数バッファ0
   typedef struct _CBUFFER0
   {
      // 平行光源の方向ベクトル
      D3DXVECTOR4 vecLight;
      // パーティクルカラー
      D3DXVECTOR4 Color;
   }CBUFFER0;

   // 入力レイアウト
   ID3D11InputLayout* m_pLayout[2];

   // 頂点シェーダー
   ID3D11VertexShader* m_pVertexShader[2];

   // ピクセルシェーダー
   ID3D11PixelShader* m_pPixelShader[2];

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

   // ブレンドステート
   ID3D11BlendState* m_pBlendState[2];

   // 深度ステンシルステート
   ID3D11DepthStencilState*  m_pDepthStencilState[2];

   // 定数バッファ
   ID3D11Buffer* m_pConstantBuffers[2];

private:
   // 共通項目の初期化
   HRESULT InitCommon( ID3D11Device* pD3DDevice );

   // ParticlesIntoBuffer用の初期化
   HRESULT InitParticlesIntoBuffer( ID3D11Device* pD3DDevice
                                  , const BYTE* pVSStep01Shader, size_t VSStep01Size
                                  , const BYTE* pPSStep01Shader, size_t PSStep01Size
                                  );
   // CompositeParticles用の初期化
   HRESULT InitCompositeParticles( ID3D11Device* pD3DDevice
                                  , const BYTE* pVSStep02Shader, size_t VSStep02Size
                                  , const BYTE* pPSStep02Shader, size_t PSStep02Size
                                  );

   // ビュー行列からビルボード用の行列を作成
   D3DXMATRIX GetBillBoardMatrix( D3DXMATRIX* pMatView );

   CPolygon2D m_Polygon2D;

public:

   DEFERRED_PARTICLES();
   ~DEFERRED_PARTICLES();

   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice
               , TCHAR pSrcFile[]
               , CHAR pVSStep01FunctionName[]
               , CHAR pPSStep01FunctionName[]
               , CHAR pVSStep02FunctionName[]
               , CHAR pPSStep02FunctionName[]
               );
   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice
               , const BYTE* pVSStep01Shader, size_t VSStep01Size
               , const BYTE* pPSStep01Shader, size_t PSStep01Size
               , const BYTE* pVSStep02Shader, size_t VSStep02Size
               , const BYTE* pPSStep02Shader, size_t PSStep02Size
               );
   // ParticlesIntoBuffer用描画関数
   HRESULT RenderParticlesIntoBuffer( ID3D11DeviceContext* pD3DDeviceContext
                                    , D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj
                                    , D3DXVECTOR3* pCenterPosition
                                    , PARTICLESYSTEM* pParticleSystem
                                    );
   // CompositeParticles用描画関数
   HRESULT RenderCompositeParticles( ID3D11DeviceContext* pD3DDeviceContext
                                   , D3DXVECTOR4* pVecLightInvMatView
                                   , D3DXVECTOR3* pParticleColor
                                   , ID3D11ShaderResourceView* pSRView
                                   );
};

#endif

---DeferredParticles.cpp---  ↑

#include "DX11User.h"
#include "ParticleSystem.h"
#include "DeferredParticles.h"

DEFERRED_PARTICLES::DEFERRED_PARTICLES()
{
   for( int i=0; i<2; i++ )
   {
      m_pLayout[i] = NULL;
      m_pVertexShader[i] = NULL;
      m_pPixelShader[i] = NULL;
      m_pDepthStencilState[i] = NULL;
      m_pConstantBuffers[i] = NULL;
      m_pBlendState[i] = NULL;
   }
   m_pSamplerState = NULL;
}

DEFERRED_PARTICLES::~DEFERRED_PARTICLES()
{
   for( int i=0; i<2; i++ )
   {
      SAFE_RELEASE( m_pLayout[i] );
      SAFE_RELEASE( m_pVertexShader[i] );
      SAFE_RELEASE( m_pPixelShader[i] );
      SAFE_RELEASE( m_pDepthStencilState[i] );
      SAFE_RELEASE( m_pConstantBuffers[i] );
      SAFE_RELEASE( m_pBlendState[i] );
   }
   SAFE_RELEASE( m_pSamplerState );
}

// ParticlesIntoBuffer用の初期化
HRESULT DEFERRED_PARTICLES::InitParticlesIntoBuffer( ID3D11Device* pD3DDevice
                                                   , const BYTE* pVSStep01Shader, size_t VSStep01Size
                                                   , const BYTE* pPSStep01Shader, size_t PSStep01Size
                                                   )
{
   HRESULT hr = E_FAIL;

   if( pD3DDevice == NULL ) goto EXIT;

   // *****************************************************************************************************************
   // 頂点シェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreateVertexShader( pVSStep01Shader, VSStep01Size, NULL, &m_pVertexShader[0] );
   if( FAILED( hr ) )
      goto EXIT;

   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         // 入力アセンブラにジオメトリ処理用の行列を追加設定する
         { "MATRIX",   0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,  0, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         // 頂点カラー
         { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 64, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
   };

   // *****************************************************************************************************************
   // 入力レイアウトの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreateInputLayout( layout, _countof( layout ), pVSStep01Shader, VSStep01Size, &m_pLayout[0] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ピクセルシェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreatePixelShader( pPSStep01Shader, PSStep01Size, NULL, &m_pPixelShader[0] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 定数バッファを作成
   // *****************************************************************************************************************

   // 使用しない

   // *****************************************************************************************************************
   // ブレンドステートの作成
   // *****************************************************************************************************************

   D3D11_BLEND_DESC BlendDesc;
   ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) );
   BlendDesc.AlphaToCoverageEnable = FALSE;
   BlendDesc.IndependentBlendEnable = FALSE;
   BlendDesc.RenderTarget[0].BlendEnable = TRUE;
   BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
//   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;  // 明暗が強く出すぎる
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
//   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;  // パーティクルの輪郭が強く出る
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_pBlendState[0] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 深度ステンシルステートの作成
   // *****************************************************************************************************************

   // 深度ステンシルステートを作成する
   D3D11_DEPTH_STENCIL_DESC ddsDesc;
   ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) );
   ddsDesc.DepthEnable = TRUE;                            // 深度テストを有効
   ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;  // 深度バッファへの書き込みを行わない
   ddsDesc.DepthFunc = D3D11_COMPARISON_LESS;
   ddsDesc.StencilEnable = FALSE;
   hr = pD3DDevice->CreateDepthStencilState( &ddsDesc, &m_pDepthStencilState[0] );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// CompositeParticles用の初期化
HRESULT DEFERRED_PARTICLES::InitCompositeParticles( ID3D11Device* pD3DDevice
                                                  , const BYTE* pVSStep02Shader, size_t VSStep02Size
                                                  , const BYTE* pPSStep02Shader, size_t PSStep02Size
                                                  )
{
   HRESULT hr = E_FAIL;

   if( pD3DDevice == NULL ) goto EXIT;

   // 2Dポリクラスの作成処理
   hr = m_Polygon2D.Create( pD3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 頂点シェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreateVertexShader( pVSStep02Shader, VSStep02Size, NULL, &m_pVertexShader[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 入力レイアウトの作成
   // *****************************************************************************************************************

   D3D11_INPUT_ELEMENT_DESC* pInputElement = NULL;
   UINT InputElementCount;
   m_Polygon2D.GetInputElement( &pInputElement, &InputElementCount );
   hr = pD3DDevice->CreateInputLayout( pInputElement, InputElementCount, pVSStep02Shader, VSStep02Size, &m_pLayout[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ピクセルェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreatePixelShader( pPSStep02Shader, PSStep02Size, NULL, &m_pPixelShader[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 入力アセンブラ用のバッファを作成
   // *****************************************************************************************************************

   // CPolygon2Dクラスで作成するためここでは作成しない

   // *****************************************************************************************************************
   // パーティクルの頂点座標の初期化
   // *****************************************************************************************************************

   // CPolygon2Dクラスで作成するためここでは作成しない

   // *****************************************************************************************************************
   // 定数バッファオブジェクトを作成
   // *****************************************************************************************************************

   D3D11_BUFFER_DESC BufferDesc;
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CBUFFER0 );        // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DYNAMIC;       // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_CONSTANT_BUFFER;// バッファの種類
   BufferDesc.CPUAccessFlags        = D3D11_CPU_ACCESS_WRITE;    // CPU アクセスする
   BufferDesc.MiscFlags             = 0;                         // その他のフラグも設定しない
   hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_pConstantBuffers[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ブレンドステートの作成
   // *****************************************************************************************************************

   // ステージ0を線形合成で設定
   D3D11_BLEND_DESC BlendDesc;
   ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) );
   BlendDesc.AlphaToCoverageEnable = FALSE;
   BlendDesc.IndependentBlendEnable = FALSE;
   BlendDesc.RenderTarget[0].BlendEnable = TRUE;
   BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_pBlendState[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 深度ステンシルステートの作成
   // *****************************************************************************************************************

   // 深度ステンシルステートを作成する
   D3D11_DEPTH_STENCIL_DESC ddsDesc;
   ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) );
   ddsDesc.DepthEnable = FALSE;                            // 深度テストを無効
   ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;   // 深度バッファへの書き込みを行わない
   ddsDesc.DepthFunc = D3D11_COMPARISON_LESS;
   ddsDesc.StencilEnable = FALSE;
   hr = pD3DDevice->CreateDepthStencilState( &ddsDesc, &m_pDepthStencilState[1] );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // デカールマップの初期化
   // *****************************************************************************************************************

   // 使用しない

   hr = S_OK;

EXIT:
   return hr;
}

// 共通項目の初期化
HRESULT DEFERRED_PARTICLES::InitCommon( ID3D11Device* pD3DDevice )
{
   HRESULT hr = E_FAIL;

   // *****************************************************************************************************************
   // サンプラーステートの作成
   // *****************************************************************************************************************

   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;  // サンプリング時に使用するフィルタ。ここでは線形補間を使用する。
   samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある v テクスチャー座標
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある w テクスチャー座標
   samplerDesc.MipLODBias = 0;                            // 計算されたミップマップ レベルからのバイアス
   samplerDesc.MaxAnisotropy = 1;                         // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。
   samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;  // 比較オプション。
   ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色
   samplerDesc.MinLOD = 0;                                // アクセス可能なミップマップの下限値
   samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;                // アクセス可能なミップマップの上限値
   hr = pD3DDevice->CreateSamplerState( &samplerDesc, &m_pSamplerState );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;
EXIT:
   return hr;
}

// 初期化
HRESULT DEFERRED_PARTICLES::Init( ID3D11Device* pD3DDevice
                                , TCHAR pSrcFile[]
                                , CHAR pVSStep01FunctionName[]
                                , CHAR pPSStep01FunctionName[]
                                , CHAR pVSStep02FunctionName[]
                                , CHAR pPSStep02FunctionName[]
                                )
{
   HRESULT hr = E_FAIL;

   ID3D10Blob* pBlob[2] = { NULL, NULL };

   UINT Flag1 = D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR | D3D10_SHADER_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
   Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL0;
#else
   Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL3;
#endif


   // *****************************************************************************************************************
   // ParticlesIntoBuffer()用のシェーダーソースファイルのコンパイル
   // *****************************************************************************************************************

   // 頂点シェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pVSStep01FunctionName, "vs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   // ピクセルシェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pPSStep01FunctionName, "ps_4_0", Flag1, 0, NULL, &pBlob[1], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   // 初期化
   hr = InitParticlesIntoBuffer( pD3DDevice,
                                 (LPBYTE)pBlob[0]->GetBufferPointer(), pBlob[0]->GetBufferSize()
                               , (LPBYTE)pBlob[1]->GetBufferPointer(), pBlob[1]->GetBufferSize()
                               );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // CompositeParticles()用のシェーダーソースファイルのコンパイル
   // *****************************************************************************************************************

   // 頂点シェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pVSStep02FunctionName, "vs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   // ピクセルシェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pPSStep02FunctionName, "ps_4_0", Flag1, 0, NULL, &pBlob[1], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   // 初期化
   hr = InitCompositeParticles( pD3DDevice
                              , (LPBYTE)pBlob[0]->GetBufferPointer(), pBlob[0]->GetBufferSize()
                              , (LPBYTE)pBlob[1]->GetBufferPointer(), pBlob[1]->GetBufferSize()
                              );
   if( FAILED( hr ) )
      goto EXIT;

   // 共通項目の初期化
   hr = InitCommon( pD3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// 初期化
HRESULT DEFERRED_PARTICLES::Init( ID3D11Device* pD3DDevice
                                , const BYTE* pVSStep01Shader, size_t VSStep01Size
                                , const BYTE* pPSStep01Shader, size_t PSStep01Size
                                , const BYTE* pVSStep02Shader, size_t VSStep02Size
                                , const BYTE* pPSStep02Shader, size_t PSStep02Size
                                )
{
   HRESULT hr = E_FAIL;

   // ParticlesIntoBuffer用の初期化
   hr = InitParticlesIntoBuffer( pD3DDevice,
                                 pVSStep01Shader, VSStep01Size
                               , pPSStep01Shader, PSStep01Size
                               );
   if( FAILED( hr ) )
      goto EXIT;

   // CompositeParticles用の初期化
   hr = InitCompositeParticles( pD3DDevice
                              , pVSStep02Shader, VSStep02Size
                              , pPSStep02Shader, PSStep02Size
                              );
   if( FAILED( hr ) )
      goto EXIT;

   // 共通項目の初期化
   hr = InitCommon( pD3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// ビュー行列からビルボード用の行列を作成
D3DXMATRIX DEFERRED_PARTICLES::GetBillBoardMatrix( D3DXMATRIX* pMatView )
{
   D3DXMATRIX BillBoardMatrix;

   // ビュー行列から逆行列を作成する
   D3DXMatrixInverse( &BillBoardMatrix, NULL, pMatView );

   // 回転のみ考慮するので平行移動は無効にする
   BillBoardMatrix._41 = BillBoardMatrix._42 = BillBoardMatrix._43 = 0.0f;

   return BillBoardMatrix;
}

// ParticlesIntoBuffer用描画関数
HRESULT DEFERRED_PARTICLES::RenderParticlesIntoBuffer( ID3D11DeviceContext* pD3DDeviceContext
                                                     , D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj
                                                     , D3DXVECTOR3* pCenterPosition
                                                     , PARTICLESYSTEM* pParticleSystem
                                                     )
{
   HRESULT hr = E_FAIL;

   D3D11_MAPPED_SUBRESOURCE mappedResource;
   D3DXMATRIX matScaling, matTranslation, matWorld, matBillBoard, matWVP;

   // *****************************************************************************************************************
   // 入力アセンブラー ステージを設定
   // *****************************************************************************************************************

   // インスタンスごとに行列を作成して入力バッファに設定する

   hr = pD3DDeviceContext->Map( pParticleSystem->GetInputBuffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) )
      goto EXIT;

   PARTICLESYSTEM::IBUFFER0* ibuffer0 = (PARTICLESYSTEM::IBUFFER0*)(mappedResource.pData);

   UINT NumRender = 0;

   const PARTICLESYSTEM::PARTICLE* pParticles = pParticleSystem->GetParticles();

   for( UINT i=0; i<pParticleSystem->GetNumParticles(); i++ )
   {
      if( pParticles[i].LifeAndAlpha > 0.0f )
      {
         // ビルボード処理用の行列を取得する
         matBillBoard = GetBillBoardMatrix( pMatView );

         D3DXMatrixScaling( &matScaling, pParticles[i].Size, pParticles[i].Size, 1 );
         D3DXMatrixTranslation( &matTranslation
                              , pParticles[i].Pos.x + pCenterPosition->x
                              , pParticles[i].Pos.y + pCenterPosition->y
                              , pParticles[i].Pos.z + pCenterPosition->z
                              );
         matWorld = matScaling * matBillBoard * matTranslation;

         matWVP = matWorld * (*pMatView) * (*pMatProj);

         // シェーダー内では列優先にしているので転置行列を作成する。
         D3DXMatrixTranspose( &ibuffer0[NumRender].matWVP, &matWVP );

         // 頂点カラー
         ::CopyMemory( ibuffer0[NumRender].Color, &D3DXVECTOR4( 0, 0, 0, pParticles[i].LifeAndAlpha ), sizeof( D3DXVECTOR4 ) );

         NumRender++;
      }
   }   
   
   pD3DDeviceContext->Unmap( pParticleSystem->GetInputBuffer(), 0 );

   // 入力レイアウト設定
   pD3DDeviceContext->IASetInputLayout( m_pLayout[0] );

   // メッシュの描画方式を設定する
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // 頂点バッファ設定
   ID3D11Buffer* pBuf[2] = { pParticleSystem->GetVertexBuffer(), pParticleSystem->GetInputBuffer() };
   UINT stride[2] = { sizeof( PARTICLESYSTEM::PARTICLE_VERTEX ), sizeof( PARTICLESYSTEM::IBUFFER0 ) };
   UINT offset[2] = { 0, 0 };
   // 3Dアセットデータ、およびジオメトリ処理用の行列を入力アセンブラに設定する
   pD3DDeviceContext->IASetVertexBuffers( 0, 2, pBuf, stride, offset );

   // *****************************************************************************************************************
   // シェーダーをデバイスに設定
   // *****************************************************************************************************************

   // 頂点シェーダーをデバイスに設定する。
   pD3DDeviceContext->VSSetShader( m_pVertexShader[0], NULL, 0 );

   // ハルシェーダーを無効にする。
   pD3DDeviceContext->HSSetShader( NULL, NULL, 0 );

   // ドメインシェーダーを無効にする
   pD3DDeviceContext->DSSetShader( NULL, NULL, 0 );

   // ジオメトリシェーダーを無効にする。
   pD3DDeviceContext->GSSetShader( NULL, NULL, 0 );

   // ピクセルシェーダーをデバイスに設定する。
   pD3DDeviceContext->PSSetShader( m_pPixelShader[0], NULL, 0 );

   // コンピュートシェーダーを無効にする。
   pD3DDeviceContext->CSSetShader( NULL, NULL, 0 );

   // ピクセルシェーダーにテクスチャーを設定する。
   ID3D11ShaderResourceView* pSRV = pParticleSystem->GetShaderResourceView();
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRV );
   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

   // *****************************************************************************************************************
   // 出力結合ステージを設定
   // *****************************************************************************************************************

   // ブレンドステートを設定
   pD3DDeviceContext->OMSetBlendState( m_pBlendState[0], 0, 0xffffffff );

   // 深度ステンシルステートを設定
   pD3DDeviceContext->OMSetDepthStencilState( m_pDepthStencilState[0], 0 );

   // *****************************************************************************************************************
   // 描画
   // *****************************************************************************************************************

   // インスタンスを使用したを使用した描画
   pD3DDeviceContext->DrawInstanced( 4, NumRender, 0, 0 );

   hr = S_OK;
EXIT:
   return hr;
}

// CompositeParticles用描画関数
HRESULT DEFERRED_PARTICLES::RenderCompositeParticles( ID3D11DeviceContext* pD3DDeviceContext
                                                    , D3DXVECTOR4* pVecLightInvMatView
                                                    , D3DXVECTOR3* pParticleColor
                                                    , ID3D11ShaderResourceView* pSRView
                                                    )
{
   HRESULT hr = E_FAIL;

   CBUFFER0* cbuffer0;
   D3D11_MAPPED_SUBRESOURCE mappedResource;

   // *****************************************************************************************************************
   // 定数バッファを設定
   // *****************************************************************************************************************

   hr = pD3DDeviceContext->Map( m_pConstantBuffers[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) )
      goto EXIT;
   cbuffer0 = (CBUFFER0*)(mappedResource.pData);

   // ビュー行列の逆行列を適応済みの平行光源の方向ベクトルをセットする
   ::CopyMemory( &cbuffer0->vecLight, pVecLightInvMatView, sizeof( D3DXVECTOR4 ) );

   // パーティクルカラー
   cbuffer0->Color = D3DXVECTOR4( pParticleColor->x, pParticleColor->y, pParticleColor->z, 1 );

   pD3DDeviceContext->Unmap( m_pConstantBuffers[1], 0 );

   // *****************************************************************************************************************
   // 入力アセンブラー ステージを設定
   // *****************************************************************************************************************

   // 入力レイアウト設定
   pD3DDeviceContext->IASetInputLayout( m_pLayout[1] );

   // メッシュの描画方式を設定する
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // 頂点バッファはCPolygon2Dクラス内部で設定するのでここでは設定しない

   // *****************************************************************************************************************
   // シェーダーをデバイスに設定
   // *****************************************************************************************************************

   // 頂点シェーダーをデバイスに設定する。
   pD3DDeviceContext->VSSetShader( m_pVertexShader[1], NULL, 0 );

   // ハルシェーダーを無効にする。
   pD3DDeviceContext->HSSetShader( NULL, NULL, 0 );

   // ドメインシェーダーを無効にする
   pD3DDeviceContext->DSSetShader( NULL, NULL, 0 );

   // ジオメトリシェーダーを無効にする。
   pD3DDeviceContext->GSSetShader( NULL, NULL, 0 );

   // ピクセルシェーダーをデバイスに設定する。
   pD3DDeviceContext->PSSetShader( m_pPixelShader[1], NULL, 0 );
   // ピクセルシェーダーに定数バッファを設定する。
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers[1] );
   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );
   // ピクセルシェーダーにテクスチャーを設定する。
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRView );

   // コンピュートシェーダーを無効にする。
   pD3DDeviceContext->CSSetShader( NULL, NULL, 0 );

   // *****************************************************************************************************************
   // 出力結合ステージを設定
   // *****************************************************************************************************************

   // ブレンドステートを設定
   pD3DDeviceContext->OMSetBlendState( m_pBlendState[1], 0, 0xffffffff );

   // 深度ステンシルステートを設定
   pD3DDeviceContext->OMSetDepthStencilState( m_pDepthStencilState[1], 0 );

   // *****************************************************************************************************************
   // 描画
   // *****************************************************************************************************************

   m_Polygon2D.Render( pD3DDeviceContext );

   hr = S_OK;
EXIT:
   return hr;
}

ディファードパーティクル用クラスです。
簡単に説明します。

●RenderParticlesIntoBuffer()
ここではレンダーターゲットサーフェスに法線ベクトルと不透明度を蓄積していきます。

●RenderCompositeParticles()
RenderParticlesIntoBuffer()で描画したレンダーターゲットサーフェスの法線ベクトル情報をもとにライティングを行います。 蓄積した法線ベクトルの内容をもとにライティングするため、ボリューム感のあるパーティクルが表現できます。

---ForwardParticles.hlsl---  ↑

// ************************************************************
// 入出力パラメータの定義
// ************************************************************

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;           // 頂点座標
   float2 texel  : TEXCOORD;           // テクセル
   column_major float4x4 mat : MATRIX; // インスタンスごとに設定される行列
   float4 color  : COLOR;              // 頂点カラー
};

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

// ************************************************************
// テクスチャーの宣言
// ************************************************************

Texture2D g_DecalMap : register( t0 );  // デカールマップ

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

// ************************************************************
// 定数バッファの宣言
// ************************************************************

// 定数バッファ0
cbuffer cbBuffer0 : register( b0 )
{
   float4 g_vecLight : packoffset( c0 );      // 平行光源の方向ベクトル
};

// ************************************************************
// シェーダーの実装
// ************************************************************

// 頂点シェーダー
VS_OUT ForwardParticles_VS_Main( VS_IN In )
{
   VS_OUT Out;
   Out.sv_pos = mul( float4( In.pos, 1.0f ), In.mat );
   Out.texel = In.texel;
   Out.color = In.color;
   return Out;
}

// ピクセルシェーダ
float4 ForwardParticles_PS_Main( VS_OUT In ) : SV_TARGET0
{
   float4 Out;
     
   float4 decalmap = g_DecalMap.Sample( g_Sampler, In.texel );

   // 法線ベクトルを 0 〜 1 範囲を -1 〜 1 に変換する
   decalmap.rg = decalmap.rg * 2.0f - 1.0f;
   decalmap.rb *= -1.0f;
   
   // ライティング
   float diffuse = dot( decalmap.rgb, -g_vecLight.xyz );
   diffuse = diffuse * 0.5f + 0.5f;
   
   Out = float4( In.color.rgb * diffuse, In.color.a * decalmap.a );

   return Out;
}

---ForwardParticles.h---  ↑

#ifndef FORWARD_PARTICLES_H
#define FORWARD_PARTICLES_H

class FORWARD_PARTICLES
{
private:
   // 定数バッファ0
   typedef struct _CBUFFER0
   {
      // 平行光源の方向ベクトル
      D3DXVECTOR4 vecLight;
   }CBUFFER0;

   // 入力レイアウト
   ID3D11InputLayout* m_pLayout;

   // 入力アセンブラにデータを追加するためのバッファ
   ID3D11Buffer* m_pInputBuffer;

   // 頂点シェーダー
   ID3D11VertexShader* m_pVertexShader;

   // ピクセルシェーダー
   ID3D11PixelShader* m_pPixelShader;

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

   // ブレンドステート
   ID3D11BlendState* m_pBlendState;

   // 深度ステンシルステート
   ID3D11DepthStencilState*  m_pDepthStencilState;

   // 定数バッファ
   ID3D11Buffer* m_pConstantBuffers;

private:
   // ビュー行列からビルボード用の行列を作成
   D3DXMATRIX GetBillBoardMatrix( D3DXMATRIX* pMatView );

public:

   FORWARD_PARTICLES();
   ~FORWARD_PARTICLES();

   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice
               , TCHAR pSrcFile[]
               , CHAR pVSFunctionName[]
               , CHAR pPSFunctionName[]
               );
   HRESULT Init( ID3D11Device* pD3DDevice
               , const BYTE* pVSShader, size_t VSSize
               , const BYTE* pPSShader, size_t PSSize
               );
   // パーティクル用描画関数
   HRESULT RenderParticles( ID3D11DeviceContext* pD3DDeviceContext
                          , D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj, D3DXVECTOR4* pVecLight
                          , D3DXVECTOR3* pParticleColor
                          , D3DXVECTOR3* pCenterPosition
                          , PARTICLESYSTEM* pParticleSystem
                          );
};

#endif

---ForwardParticles.cpp---  ↑

#include "DX11User.h"
#include "ParticleSystem.h"
#include "ForwardParticles.h"

FORWARD_PARTICLES::FORWARD_PARTICLES()
{
   m_pLayout = NULL;
   m_pVertexShader = NULL;
   m_pPixelShader = NULL;
   m_pSamplerState = NULL;
   m_pBlendState = NULL;
   m_pDepthStencilState = NULL;
   m_pConstantBuffers = NULL;
}

FORWARD_PARTICLES::~FORWARD_PARTICLES()
{
   SAFE_RELEASE( m_pLayout );
   SAFE_RELEASE( m_pVertexShader );
   SAFE_RELEASE( m_pPixelShader );
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pBlendState );
   SAFE_RELEASE( m_pDepthStencilState );
   SAFE_RELEASE( m_pConstantBuffers );
}

// 初期化
HRESULT FORWARD_PARTICLES::Init( ID3D11Device* pD3DDevice
                               , TCHAR pSrcFile[]
                               , CHAR pVSFunctionName[]
                               , CHAR pPSFunctionName[]
                               )
{
   HRESULT hr = E_FAIL;

   ID3D10Blob* pBlob[2] = { NULL, NULL };

   UINT Flag1 = D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR | D3D10_SHADER_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
   Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL0;
#else
   Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL3;
#endif

   // 頂点シェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pVSFunctionName, "vs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   // ピクセルシェーダーのコンパイル
   hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pPSFunctionName, "ps_4_0", Flag1, 0, NULL, &pBlob[1], NULL, NULL );
   if( FAILED( hr ) )
      goto EXIT;

   hr = Init( pD3DDevice
            , (LPBYTE)pBlob[0]->GetBufferPointer(), pBlob[0]->GetBufferSize()
            , (LPBYTE)pBlob[1]->GetBufferPointer(), pBlob[1]->GetBufferSize()
            );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

HRESULT FORWARD_PARTICLES::Init( ID3D11Device* pD3DDevice
                               , const BYTE* pVSShader, size_t VSSize
                               , const BYTE* pPSShader, size_t PSSize
                               )
{
   HRESULT hr = E_FAIL;

   D3D11_BUFFER_DESC BufferDesc;

   if( pD3DDevice == NULL ) goto EXIT;

   // *****************************************************************************************************************
   // 頂点シェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreateVertexShader( pVSShader, VSSize, NULL, &m_pVertexShader );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 入力レイアウトの作成
   // *****************************************************************************************************************

   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         // 入力アセンブラにジオメトリ処理用の行列を追加設定する
         { "MATRIX",   0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,  0, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         { "MATRIX",   3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
         // 頂点カラー
         { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 64, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
   };
   hr = pD3DDevice->CreateInputLayout( layout, _countof( layout ), pVSShader, VSSize, &m_pLayout );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ピクセルェーダーの作成
   // *****************************************************************************************************************

   hr = pD3DDevice->CreatePixelShader( pPSShader, PSSize, NULL, &m_pPixelShader );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 定数バッファを作成
   // *****************************************************************************************************************

   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CBUFFER0 );        // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DYNAMIC;       // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_CONSTANT_BUFFER;// バッファの種類
   BufferDesc.CPUAccessFlags        = D3D11_CPU_ACCESS_WRITE;    // CPU アクセスする
   BufferDesc.MiscFlags             = 0;                         // その他のフラグも設定しない
   hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_pConstantBuffers );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // サンプラーステートの作成
   // *****************************************************************************************************************

   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;  // サンプリング時に使用するフィルタ。ここでは線形補間を使用する。
   samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある v テクスチャー座標
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある w テクスチャー座標
   samplerDesc.MipLODBias = 0;                            // 計算されたミップマップ レベルからのバイアス
   samplerDesc.MaxAnisotropy = 1;                         // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。
   samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;  // 比較オプション。
   ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色
   samplerDesc.MinLOD = 0;                                // アクセス可能なミップマップの下限値
   samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;                // アクセス可能なミップマップの上限値
   hr = pD3DDevice->CreateSamplerState( &samplerDesc, &m_pSamplerState );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ブレンドステートの作成
   // *****************************************************************************************************************

   // ステージ0を線形合成で設定
   D3D11_BLEND_DESC BlendDesc;
   ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) );
   BlendDesc.AlphaToCoverageEnable = FALSE;
   BlendDesc.IndependentBlendEnable = FALSE;
   BlendDesc.RenderTarget[0].BlendEnable = TRUE;
   BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_pBlendState );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 深度ステンシルステートの作成
   // *****************************************************************************************************************

   // 深度ステンシルステートを作成する
   D3D11_DEPTH_STENCIL_DESC ddsDesc;
   ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) );
   ddsDesc.DepthEnable = TRUE;                            // 深度テストを有効
   ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;  // 深度バッファへの書き込みを行わない
   ddsDesc.DepthFunc = D3D11_COMPARISON_LESS;
   ddsDesc.StencilEnable = FALSE;
   hr = pD3DDevice->CreateDepthStencilState( &ddsDesc, &m_pDepthStencilState );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// ビュー行列からビルボード用の行列を作成
D3DXMATRIX FORWARD_PARTICLES::GetBillBoardMatrix( D3DXMATRIX* pMatView )
{
   D3DXMATRIX BillBoardMatrix;

   // ビュー行列から逆行列を作成する
   D3DXMatrixInverse( &BillBoardMatrix, NULL, pMatView );

   // 回転のみ考慮するので平行移動は無効にする
   BillBoardMatrix._41 = BillBoardMatrix._42 = BillBoardMatrix._43 = 0.0f;

   return BillBoardMatrix;
}

// 描画
HRESULT FORWARD_PARTICLES::RenderParticles( ID3D11DeviceContext* pD3DDeviceContext
                                          , D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj, D3DXVECTOR4* pVecLight
                                          , D3DXVECTOR3* pParticleColor
                                          , D3DXVECTOR3* pCenterPosition
                                          , PARTICLESYSTEM* pParticleSystem
                                          )
{
   HRESULT hr = E_FAIL;

   CBUFFER0* cbuffer0;
   D3D11_MAPPED_SUBRESOURCE mappedResource;
   D3DXMATRIX matScaling, matTranslation, matWorld, matBillBoard, matWVP, matInv;
   D3DXVECTOR4 v;

   // *****************************************************************************************************************
   // 定数バッファを設定
   // *****************************************************************************************************************

   hr = pD3DDeviceContext->Map( m_pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) )
      goto EXIT;
   cbuffer0 = (CBUFFER0*)(mappedResource.pData);

   // 平行光源をビュー行列で回転
   D3DXMatrixInverse( &matInv, NULL, pMatView );
   D3DXVec4Transform( &v, pVecLight, &matInv );
   D3DXVec3Normalize( (D3DXVECTOR3*)&v, (D3DXVECTOR3*)&v );
   ::CopyMemory( &cbuffer0->vecLight, &v, sizeof( D3DXVECTOR4 ) );
   
   pD3DDeviceContext->Unmap( m_pConstantBuffers, 0 );

   // *****************************************************************************************************************
   // 入力アセンブラー ステージを設定
   // *****************************************************************************************************************

   // インスタンスごとに行列を作成して入力バッファに設定する

   hr = pD3DDeviceContext->Map( pParticleSystem->GetInputBuffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) )
      goto EXIT;

   PARTICLESYSTEM::IBUFFER0* ibuffer0 = (PARTICLESYSTEM::IBUFFER0*)(mappedResource.pData);

   UINT NumRender = 0;

   const PARTICLESYSTEM::PARTICLE* pParticles = pParticleSystem->GetParticles();

   for( UINT i=0; i<pParticleSystem->GetNumParticles(); i++ )
   {
      if( pParticles[i].LifeAndAlpha > 0.0f )
      {
         // ビルボード処理用の行列を取得する
         matBillBoard = GetBillBoardMatrix( pMatView );

         D3DXMatrixScaling( &matScaling, pParticles[i].Size, pParticles[i].Size, 1 );
         D3DXMatrixTranslation( &matTranslation
                              , pParticles[i].Pos.x + pCenterPosition->x
                              , pParticles[i].Pos.y + pCenterPosition->y
                              , pParticles[i].Pos.z + pCenterPosition->z
                              );
         matWorld = matScaling * matBillBoard * matTranslation;

         matWVP = matWorld * (*pMatView) * (*pMatProj);

         // シェーダー内では列優先にしているので転置行列を作成する。
         D3DXMatrixTranspose( &ibuffer0[NumRender].matWVP, &matWVP );

         // 頂点カラー
         ibuffer0[NumRender].Color = D3DXVECTOR4( pParticleColor->x, pParticleColor->y, pParticleColor->z, pParticles[i].LifeAndAlpha );

         NumRender++;
      }
   }   
   pD3DDeviceContext->Unmap( pParticleSystem->GetInputBuffer(), 0 );

   // 入力レイアウト設定
   pD3DDeviceContext->IASetInputLayout( m_pLayout );

   // メッシュの描画方式を設定する
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // 頂点バッファ設定
   ID3D11Buffer* pBuf[2] = { pParticleSystem->GetVertexBuffer(), pParticleSystem->GetInputBuffer() };
   UINT stride[2] = { sizeof( PARTICLESYSTEM::PARTICLE_VERTEX ), sizeof( PARTICLESYSTEM::IBUFFER0 ) };
   UINT offset[2] = { 0, 0 };
   // 3Dアセットデータ、およびジオメトリ処理用の行列を入力アセンブラに設定する
   pD3DDeviceContext->IASetVertexBuffers( 0, 2, pBuf, stride, offset );

   // *****************************************************************************************************************
   // シェーダーをデバイスに設定
   // *****************************************************************************************************************

   // 頂点シェーダーをデバイスに設定する。
   pD3DDeviceContext->VSSetShader( m_pVertexShader, NULL, 0 );

   // ハルシェーダーを無効にする。
   pD3DDeviceContext->HSSetShader( NULL, NULL, 0 );

   // ドメインシェーダーを無効にする
   pD3DDeviceContext->DSSetShader( NULL, NULL, 0 );

   // ジオメトリシェーダーを無効にする。
   pD3DDeviceContext->GSSetShader( NULL, NULL, 0 );

   // ピクセルシェーダーをデバイスに設定する。
   pD3DDeviceContext->PSSetShader( m_pPixelShader, NULL, 0 );
   // ピクセルシェーダーに定数バッファを設定する。
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers );
   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );
   // ピクセルシェーダーにテクスチャーを設定する。
   ID3D11ShaderResourceView* pSRV = pParticleSystem->GetShaderResourceView();
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRV );

   // コンピュートシェーダーを無効にする。
   pD3DDeviceContext->CSSetShader( NULL, NULL, 0 );

   // *****************************************************************************************************************
   // 出力結合ステージを設定
   // *****************************************************************************************************************

   // ブレンドステートを設定
   pD3DDeviceContext->OMSetBlendState( m_pBlendState, 0, 0xffffffff );

   // 深度ステンシルステートを設定
   pD3DDeviceContext->OMSetDepthStencilState( m_pDepthStencilState, 0 );

   // *****************************************************************************************************************
   // 描画
   // *****************************************************************************************************************

   // インスタンスを使用したを使用した描画
   pD3DDeviceContext->DrawInstanced( 4, NumRender, 0, 0 );

   hr = S_OK;
EXIT:
   return hr;
}

パーティクルを一つずつライティングして線形合成していきます。ボリューム感のないパーティクルとなります。

---main.cpp---  ↑


#include "../../USER/DX11User.h"
#include "../../USER/D3D11User.h"
#include "../../USER/DebugFontUser.h"
#include "../../USER/BaseShading.h"
#include "../../USER/ParticleSystem.h"
#include "../../USER/DeferredParticles.h"
#include "../../USER/ForwardParticles.h"

// FBX SDK 用
#include "../../USER/MeshUser.h"
#include "../../USER/FBXSDKMeshLoaderUser.h"

// シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える
#if defined(DEBUG) || defined(_DEBUG)
#define UNCOMPILED_SHADER     // ファイルを読み込んでコンパイルする

#else
// ランバート拡散照明用
#include "../../USER/HLSL/BaseShading_BaseShading_VS_Main.h"
#include "../../USER/HLSL/BaseShading_BaseShading_PS_Main.h"

// ディファードパーティクル用
#include "../../USER/HLSL/DeferredParticles_ParticlesIntoBuffer_VS_Main.h"
#include "../../USER/HLSL/DeferredParticles_ParticlesIntoBuffer_PS_Main.h"
#include "../../USER/HLSL/DeferredParticles_CompositeParticles_VS_Main.h"
#include "../../USER/HLSL/DeferredParticles_CompositeParticles_PS_Main.h"

// フォワードパーティクル用
#include "../../USER/HLSL/ForwardParticles_ForwardParticles_VS_Main.h"
#include "../../USER/HLSL/ForwardParticles_ForwardParticles_PS_Main.h"
#endif

// アプリケーション名
TCHAR* AppName = _T("DX11_Tutrial 170 Deferred Particles");

// Direct3D関連の自作クラス
D3D11USER* g_pD3D11User = NULL;

// デバッグ専用のテキスト描画する自作クラス
CDebugFont* g_pDebugFontUser = NULL;

// FBX メッシュローダー
FBXSDK_MESHLOADER_USER* g_pMeshLoader = NULL;
// メッシュオブジェクト
BASE_MESH_USER*         g_pMesh = NULL;

// サンプラーステート
ID3D11SamplerState* g_pSamplerState = NULL;

// レンダーターゲットサーフェス
ID3D11RenderTargetView* g_pRTView = NULL;

// シェーディング系シェーダークラス
BASE_SHADING* g_pBaseShading = NULL;

// パーティクルシステムクラス
PARTICLESYSTEM* g_pParticleSystem = NULL;

// ディファードパーティクルクラス
DEFERRED_PARTICLES* g_pDeferredParticles = NULL;

// フォワードパーティクルクラス
FORWARD_PARTICLES* g_pForwardParticles = NULL;

// 平行光源の方向ベクトル
D3DXVECTOR4 g_vecLight = D3DXVECTOR4( -0.3f, -1.0f, 0.3f, 0.0f );

// 連続入力されたかを判定する際に使用するキーボード入力バッファ
BYTE g_KeyBuffer[256];

// ビュー行列
D3DXMATRIX g_matView;

// 節電モードの制御に使用する変数。
bool Activate = true;    // ウィンドウがアクティブか
bool StandBy = false;    // スタンバイ状態か

bool ScreenShot = false; // スクリーンショットを作成するかフラグ

UINT g_Mode = 0;

// リソースの初期化
HRESULT Init()
{
   HRESULT hr = E_FAIL;

   // デバッグ専用フォント出力クラスの作成処理
   // デバックコンパイル時のみ使用する
#if defined(DEBUG) || defined(_DEBUG)
   g_pDebugFontUser = NEW CDebugFont();
   hr = g_pDebugFontUser->Create( g_pD3D11User->m_D3DDevice, 0.015f, 0.04f );
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("デバックフォントクラス初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }
#endif

   // 自作のメッシュローダーの初期化
   g_pMeshLoader = NEW FBXSDK_MESHLOADER_USER();
   hr = g_pMeshLoader->Initialize( g_pD3D11User->m_D3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

   // 頂点情報を取得する
   hr = g_pMeshLoader->LoadMeshData( _T("Res/object.fbx"), &g_pMesh );
   if( FAILED( hr ) )
      goto EXIT;

   g_pBaseShading = NEW BASE_SHADING();
#ifndef UNCOMPILED_SHADER
   hr = g_pBaseShading->Init( g_pD3D11User->m_D3DDevice
                              ,g_BaseShading_VS_Main, sizeof( g_BaseShading_VS_Main )
                              ,g_BaseShading_PS_Main, sizeof( g_BaseShading_PS_Main )
                              );
   if( FAILED( hr ) )
      goto EXIT;
#else
   hr = g_pBaseShading->Init( g_pD3D11User->m_D3DDevice
                              ,_T("../../USER/HLSL/BaseShading.hlsl")
                              ,"BaseShading_VS_Main"
                              ,"BaseShading_PS_Main"
                              );
   if( FAILED( hr ) )
      goto EXIT;
#endif

   // サンプラーステートを作成する
   hr = g_pD3D11User->CreateSamplerState( &g_pSamplerState, D3D11_FILTER_ANISOTROPIC, 16 );
   if( FAILED( hr ) )
      goto EXIT;

   // レンダーターゲットビューの作成

   // 法線マップ用のレンダーターゲットビュー
   hr = g_pD3D11User->CreateRenderTargetView( &g_pRTView, NULL, DXGI_FORMAT_R16G16B16A16_FLOAT );
   if( FAILED( hr ) )
      goto EXIT;

   // キーボード入力バッファの初期化
   ::ZeroMemory( g_KeyBuffer, sizeof( BYTE ) * _countof( g_KeyBuffer ) );

   // ビュー行列
   D3DXMatrixLookAtLH( &g_matView,
                       &D3DXVECTOR3( 0.0f, 0.0f, -20.0f ),
                       &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
                       &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

   // パーティクルシステムクラスの初期化
   g_pParticleSystem = NEW PARTICLESYSTEM();
   hr = g_pParticleSystem->Init( g_pD3D11User->m_D3DDevice, 20, 1.5f, 1.5f, _T("res/Smoke.dds") );
   if( FAILED( hr ) )
      goto EXIT;

   // ディファードパーティクル
   g_pDeferredParticles = NEW DEFERRED_PARTICLES();

   // フォワードパーティクル
   g_pForwardParticles = NEW FORWARD_PARTICLES();

#ifndef UNCOMPILED_SHADER
   // ディファードパーティクル
   hr = g_pDeferredParticles->Init( g_pD3D11User->m_D3DDevice
                                 , g_ParticlesIntoBuffer_VS_Main, sizeof( g_ParticlesIntoBuffer_VS_Main )
                                 , g_ParticlesIntoBuffer_PS_Main, sizeof( g_ParticlesIntoBuffer_PS_Main )
                                 , g_CompositeParticles_VS_Main, sizeof( g_CompositeParticles_VS_Main )
                                 , g_CompositeParticles_PS_Main, sizeof( g_CompositeParticles_PS_Main )
                                  );
   if( FAILED( hr ) )
      goto EXIT;

   // フォワードパーティクル
   hr = g_pForwardParticles->Init( g_pD3D11User->m_D3DDevice
                                , g_ForwardParticles_VS_Main, sizeof( g_ForwardParticles_VS_Main )
                                , g_ForwardParticles_PS_Main, sizeof( g_ForwardParticles_PS_Main )
                                );
   if( FAILED( hr ) )
      goto EXIT;
#else
   // ディファードパーティクル
   hr = g_pDeferredParticles->Init( g_pD3D11User->m_D3DDevice
                                 , _T("../../USER/HLSL/DeferredParticles.hlsl")
                                 , "ParticlesIntoBuffer_VS_Main"
                                 , "ParticlesIntoBuffer_PS_Main"
                                 , "CompositeParticles_VS_Main"
                                 , "CompositeParticles_PS_Main"
                                  );
   if( FAILED( hr ) )
      goto EXIT;

   // フォワードパーティクル
   hr = g_pForwardParticles->Init( g_pD3D11User->m_D3DDevice
                                , _T("../../USER/HLSL/ForwardParticles.hlsl")
                                , "ForwardParticles_VS_Main"
                                , "ForwardParticles_PS_Main"
                                );
   if( FAILED( hr ) )
      goto EXIT;
#endif

   hr = S_OK;

EXIT:
   return hr;
}

// メモリ開放
void Invalidate()
{
   SAFE_DELETE( g_pDeferredParticles );
   SAFE_DELETE( g_pForwardParticles );
   SAFE_DELETE( g_pParticleSystem );
   SAFE_DELETE( g_pBaseShading );
   SAFE_DELETE( g_pMesh );
   SAFE_DELETE( g_pMeshLoader );
   SAFE_RELEASE( g_pRTView );
   SAFE_RELEASE( g_pSamplerState );
   SAFE_DELETE( g_pDebugFontUser );
   SAFE_DELETE( g_pD3D11User );
}

// 地面描画
HRESULT RenderPlane( D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj )
{
   HRESULT hr = E_FAIL;

   D3DXMATRIX matScaling, matTranslation, matWorld, matWVP, matInv;
   D3DXVECTOR4 vec4LightDir;

   // ブレンドステート設定用の変数
   D3D11_RENDER_TARGET_BLEND_DESC RTBlendDesc;

   // 頂点バッファ設定
   UINT stride = sizeof( MESH_USER::VERTEX_USER );
   UINT offset = 0;
   g_pD3D11User->m_D3DDeviceContext->IASetVertexBuffers( 0, 1, &g_pMesh->MeshUser[0].VertexBuffer, &stride, &offset );

   // インデックスバッファ設定
   g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pMesh->MeshUser[0].IndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

   // 三角ポリゴン描画
   g_pD3D11User->m_D3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

   // 定数バッファにセット
   {
      // ワールド行列

      // スケーリング行列
      D3DXMatrixScaling( &matScaling, 3.0f, 3.0f, 3.0f );
      // 平行移動行列
      D3DXMatrixTranslation( &matTranslation, 5.0f, 0.0f, 0.0f );
      // ワールド座標系の行列の合成
      matWorld = matScaling * matTranslation;

      // 行列を合成
      matWVP = matWorld * (*pMatView) * (*pMatProj);
      // シェーダー内では列優先にしているので転置行列を作成する。
      D3DXMatrixTranspose( &matWVP, &matWVP );

      // 頂点シェーダー用の定数バッファを設定する
      g_pBaseShading->SetCBVertexShader( g_pD3D11User->m_D3DDeviceContext, &matWVP );

      // 平行光源の方向ベクトル

      // ワールド行列の逆行列を作成
      D3DXMatrixInverse( &matInv, NULL, &matWorld );
      D3DXVec4Transform( &vec4LightDir, &g_vecLight, &matInv );
   }

   // ピクセルシェーダーにサンプラーステートを設定する。
   g_pD3D11User->m_D3DDeviceContext->PSSetSamplers( 0, 1, &g_pSamplerState );

   ID3D11ShaderResourceView* pDecalMap = NULL;
   g_pMesh->MeshUser[0].GetTexture( _T("DiffuseColor"), &pDecalMap );

   // 定数シェーダーの設定
   hr = g_pBaseShading->SetCBHalfLambert( g_pD3D11User->m_D3DDeviceContext, &vec4LightDir, pDecalMap );
   if( FAILED( hr ) )
      goto EXIT;
   // シェーダーの設定
   hr = g_pBaseShading->Begin( g_pD3D11User->m_D3DDeviceContext, "g_HalfLambert" );
   if( FAILED( hr ) )
      goto EXIT;

   // ステージ0のアルファブレンドを無効にする
   RTBlendDesc = g_pD3D11User->GetDefaultBlendDesc();
   hr = g_pD3D11User->SetBlendState( &RTBlendDesc, 1, FALSE );
   if( FAILED( hr ) )
      goto EXIT;

   // 深度バッファに書き込む
   hr = g_pD3D11User->SetDepthStencilState( TRUE, D3D11_DEPTH_WRITE_MASK_ALL );
   if( FAILED( hr ) )
      goto EXIT;

   // インデックスバッファを使用した描画
   g_pD3D11User->m_D3DDeviceContext->DrawIndexed( g_pMesh->MeshUser[0].IndexesCount, 0, 0 );

   g_pBaseShading->End();

   hr = S_OK;
EXIT:
   return hr;
}

// ディファードパーティクル描画
HRESULT RenderDeferredParticles( D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj, D3DXVECTOR3* pParticleColor, D3DXVECTOR3* pParticleCenterPosition )
{
   HRESULT hr = E_FAIL;

   ID3D11RenderTargetView* pOldRTView = NULL;
   ID3D11DepthStencilView* pOldDSView = NULL;
   float NormalMapClearColor[4] = { 0, 0, 0, 0 };
   D3DXMATRIX matInv;
   D3DXVECTOR4 vecLightInvMatView;

   // *****************************************************************************************************************
   // レンダーターゲットサーフェスにパーティクルを描画する
   // *****************************************************************************************************************

   // 法線マップのクリア
   g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pRTView, NormalMapClearColor ); 
 
   // 現在のレンダーターゲットサーフェスを退避
   g_pD3D11User->m_D3DDeviceContext->OMGetRenderTargets( 1, &pOldRTView, &pOldDSView );

   // レンダーターゲットサーフェスを切り替える
   g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 1, &g_pRTView, pOldDSView );

   // 描画
   hr = g_pDeferredParticles->RenderParticlesIntoBuffer( g_pD3D11User->m_D3DDeviceContext
                                                       , pMatView, pMatProj
                                                       , pParticleCenterPosition
                                                       , g_pParticleSystem
                                                       );
   if( FAILED( hr ) )
      goto EXIT;

   // レンダーターゲットサーフェスを戻す
   ID3D11RenderTargetView* pRTViewRestore[2];
   pRTViewRestore[0] = pOldRTView;
   pRTViewRestore[1] = NULL;
   g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 2, pRTViewRestore, pOldDSView );

   SAFE_RELEASE( pOldRTView );
   SAFE_RELEASE( pOldDSView );

   // *****************************************************************************************************************
   // レンダーターゲットサーフェスを参照し、ライティングする
   // *****************************************************************************************************************

   // レンダーターゲットビューからシェーダーリソースビューを取得する
   ID3D11ShaderResourceView* pSRV = NULL;
   pSRV = g_pD3D11User->GetSRViewFromRTView( g_pRTView );

   // 平行光源をビュー行列で回転
   D3DXMatrixInverse( &matInv, NULL, pMatView );
   D3DXVec4Transform( &vecLightInvMatView, &g_vecLight, &matInv );
   D3DXVec3Normalize( (D3DXVECTOR3*)&vecLightInvMatView, (D3DXVECTOR3*)&vecLightInvMatView );

   // 描画
   hr = g_pDeferredParticles->RenderCompositeParticles( g_pD3D11User->m_D3DDeviceContext
                                                      , &vecLightInvMatView
                                                      , pParticleColor
                                                      , pSRV
                                                      );
   if( FAILED( hr ) )
      goto EXIT;

   SAFE_RELEASE( pSRV );

   hr = S_OK;
EXIT:
   return hr;
}

// フォワードパーティクル描画
HRESULT RenderForwardParticles( D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj, D3DXVECTOR3* pParticleColor, D3DXVECTOR3* pParticleCenterPosition )
{
   HRESULT hr = E_FAIL;

   // 描画
   hr = g_pForwardParticles->RenderParticles( g_pD3D11User->m_D3DDeviceContext
                                            , pMatView, pMatProj, &g_vecLight
                                            , pParticleColor, pParticleCenterPosition
                                            , g_pParticleSystem
                                            );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;
EXIT:
   return hr;
}

// 描画処理
HRESULT Render()
{
   HRESULT hr = E_FAIL;
   D3DXMATRIX matProj, m;
  
   float BackBufferColor[4] = { 0.3f, 0.3f, 0.9f, 1.0f };
   D3DXVECTOR3 ParticleColor = D3DXVECTOR3( 1, 1, 1 );
   D3DXVECTOR3 ParticleCenterPosition = D3DXVECTOR3( 0, 0, 0 );

   // パーティクルの座標更新
   g_pParticleSystem->NextFrame( &g_matView );

   // バックバッファをクリア
   g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pD3D11User->m_RenderTargetView, BackBufferColor ); 

   // 深度バッファをクリア
   if( g_pD3D11User->m_DepthStencilView )
      g_pD3D11User->m_D3DDeviceContext->ClearDepthStencilView( g_pD3D11User->m_DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

   // 射影行列
   D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 5.0f, 4.0f / 3.0f, 1.0f, 50.0f );

   // ビュー行列
   D3DXMatrixIdentity( &m );
   if( g_KeyBuffer[VK_RIGHT] )
   {
      D3DXMatrixRotationY( &m, -0.001f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer[VK_LEFT] )
   {
      D3DXMatrixRotationY( &m, 0.001f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer[VK_UP] )
   {
      D3DXMatrixTranslation( &m, 0, 0, -0.005f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer[VK_DOWN] )
   {
      D3DXMatrixTranslation( &m, 0, 0, 0.005f );
      g_matView = g_matView * m;
   }

   // 不透明メッシュを描画
   hr = RenderPlane( &g_matView, &matProj );
   if( FAILED( hr ) )
      goto EXIT;

   switch( g_Mode )
   {
   case 0:
      // ディファードパーティクル描画
      hr = RenderDeferredParticles( &g_matView, &matProj, &ParticleColor, &ParticleCenterPosition );
      if( FAILED( hr ) )
         goto EXIT;
      break;
   case 1:
      // フォワードパーティクル描画
      hr = RenderForwardParticles( &g_matView, &matProj, &ParticleColor, &ParticleCenterPosition );
      if( FAILED( hr ) )
         goto EXIT;
      break;
   }

   if( g_pDebugFontUser )
   {
      switch( g_Mode )
      {
      case 0:
         hr = g_pDebugFontUser->RenderDebugText( g_pD3D11User->m_D3DDeviceContext, "DeferredParticles", 0, 0.08f );
         if( FAILED( hr ) )
            goto EXIT;
         break;

      case 1:
         hr = g_pDebugFontUser->RenderDebugText( g_pD3D11User->m_D3DDeviceContext, "ForwardParticle", 0, 0.08f );
         if( FAILED( hr ) )
            goto EXIT;
         break;
      }

      // デバッグ専用フォント描画
      hr = g_pDebugFontUser->RenderFPS( g_pD3D11User->m_D3DDeviceContext, 0, 0 );
      if( FAILED( hr ) )
         goto EXIT;
   }

   // レンダリングされたイメージをユーザーに表示。
   hr = g_pD3D11User->m_SwapChain->Present( 0, 0 );
   if( FAILED( hr ) )
      goto EXIT;

   if( ScreenShot )
   {
      // スクリーンショット作成
      hr = g_pD3D11User->CreateScreenShot();
      if( FAILED( hr ) )
         goto EXIT;
      ScreenShot = false;
   }

   hr = S_OK;

EXIT:
   return hr;
}

// 節電処理および描画処理
HRESULT PowerSavingAndRender()
{
   HRESULT hr = E_FAIL;

   switch( StandBy )
   {
   // スタンバイモード
   case  true:
      // テストのみ行い、描画処理は行わない。
      hr = g_pD3D11User->m_SwapChain->Present( 0, DXGI_PRESENT_TEST );
      switch( hr )
      {
      // いまだスタンバイ中。。。
      case DXGI_STATUS_OCCLUDED:
         // 電源管理によるスリープ状態の場合ここにくる。
         // フルスクリーンモード時にスクリーンセーバーが起動時した場合は、表示モードが強制的にウィンドウモードに変更されるためここにこない。
         goto EXIT;
         break;
      case S_OK:
         // フルスクリーンモード時にスクリーンセーバーが起動時した場合は表示モードが強制的にウィンドウモードに変更される。
         // ウィンドウモードの場合スタンバイから復帰してしまうため、ウィンドウがアクティブになったときに復帰するようにする。
         if( Activate == true )
         {
            // たまにウィンドウが表示されないときがあるので表示するようにする
            ::ShowWindow( g_pD3D11User->m_hWnd, SW_SHOW );
            StandBy = false;
         }
         break;
      default:
         goto EXIT;
         break;
      }
      break;
   // スタンバイモードでない
   case false:
      // 描画処理
      hr = Render();
      if( FAILED( hr ) ) goto EXIT;

      switch( hr )
      {
      case DXGI_STATUS_OCCLUDED:
         // スタンバイモードへ移行
         // フルスクリーンモード時のスクリーンセーバー起動時、
         // スリープ状態に移行した時に発生する。
         StandBy = true;
         goto EXIT;
         break;
      case S_OK:
         break;
      default:
         goto EXIT;
         break;
      }
      break;
   }

   hr = S_OK;

EXIT:

   return hr;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch( msg )
   {
   case WM_KEYDOWN:
      g_KeyBuffer[wParam] = 1;
      break;

   case WM_KEYUP:
      g_KeyBuffer[wParam] = 0;

      // アプリ終了
      switch( wParam )
      {
      case VK_ESCAPE:
         ::DestroyWindow( hWnd );
         break;

      // F2キーを押すと、ウィンドウモードを切り替える。
      // 自動的にウィンドウモードを切り替える機能もあるが、ウィンドウスタイルを自由に変更するために自分で実装することにした。
      case VK_F2:
         g_pD3D11User->ChangeWindowMode();
         break;

      // スクリーンショットを作成する
      case VK_SNAPSHOT:
         ScreenShot = true;
         break;

      // モード切替
      case 'M':
         switch( g_Mode )
         {
         case 0:
            g_Mode = 1;
            break;
         case 1:
            g_Mode = 0;
            break;
         }
      }
      break;


   case WM_ACTIVATE:
      Activate = true;
      break;

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

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

   return 0L;
}

// メイン関数
int APIENTRY _tWinMain( HINSTANCE hInstance,
                        HINSTANCE,
                        LPTSTR,
                        INT )
{
   HRESULT hr = E_FAIL;
   MSG msg;
   ::ZeroMemory(&msg, sizeof(MSG));

   // メモリリーク検出
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF);

   // 表示モードを記述するための構造体。
   DXGI_MODE_DESC sd;

   // Direct3D 関連自作クラスのインスタンスを作成
   g_pD3D11User = NEW D3D11USER();

   // ディスプレイモード一覧を取得する。
   // 取得した値はクラス内部に保持される。
   hr = g_pD3D11User->GetDisplayMode();
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("ディスプレイモード取得エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }
   // とりあえず最初に見つかったディスプレイモードを選択する
   CopyMemory( &sd, &g_pD3D11User->m_DisplayModeDesc[0], sizeof( DXGI_MODE_DESC ) );

   // ウィンドウの作成およびDirect3D の初期化
   // マルチサンプルを無効にする
   hr = g_pD3D11User->InitD3D11( AppName, hInstance, WndProc, &sd, TRUE, TRUE, FALSE, TRUE );
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("Direct3D 11.0 初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }

   // リソースの初期化
   hr = Init();
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("リソース初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }
   
   ::ShowWindow(g_pD3D11User->m_hWnd, SW_SHOW);
   ::UpdateWindow(g_pD3D11User->m_hWnd);

   // メッセージループ
   do
   { 
      if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
      {
         ::TranslateMessage(&msg); 
         ::DispatchMessage(&msg); 
      }
      else
      {
         hr = PowerSavingAndRender();
         if( FAILED( hr ) )
            ::DestroyWindow( g_pD3D11User->m_hWnd );
      }
   }while( msg.message != WM_QUIT );

EXIT:
   if( g_pD3D11User && g_pD3D11User->m_hWnd )
      ::DestroyWindow( g_pD3D11User->m_hWnd );

   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

Smoke.ddsはDirect3D 10のサンプルから拝借してます。ファイル名は変更しています。

しかし、ようやくまともなシェーダーサンプルやった気がする。


web拍手 by FC2

Prev Top Next

inserted by FC2 system