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

■Direct3D 11.0 SSAO
( スクリーンスペース環境光遮蔽 )
Prev Top Next
関連ページ:Direct3D 11.0 初期化 Direct3D 11.0 デバック用フォント描画 FBX SDKを使う


SSAOあり
SSAOなし

今回は SSAO をやります。
このネタ自体は、いろんなサイトで既に紹介されています。おもなところで
gameRENDERING
もんしょの巣穴
床井研究室
などがあげられます。
上記3サイト、それぞれ異なるアプローチによりコーディングされています。 詳細については説明しませんが勉強のためにもチェックしてみるもの面白いと思います。

さてこのように既にサンプルが公開されているので、今回は丸写しで終わりかなと思っていましたが、 結局自分なりの解釈でコーディングしちゃいました。 まあ丸写しでは芸がないし、できの良し悪しは別として自分で考えてみたほうが楽しいしね。

前置きはこれくらいにして、説明していきます。

まず SSAO についてざっくり説明します。 SSAO つまりスクリーンスペース環境光遮蔽はメッシュ上の任意の点が周囲のメッシュによりどれだけ遮蔽されているか、つまり環境光が届きにくくなっているかを考えます。 この辺はサンプル画像を見てもらうとなんとなくわかっていただけるのではないでしょうか。 詳細な説明がほしい方は床井研究室さんのサイトを見ていただくとよいと思います。

さて、描画対象のピクセル位置から周囲にレイを飛ばしてそのピクセルとの状態の違いをチェックするということ自体は、どのサイトでも共通していますがそのチェック方法が異なります。 当サイトでは以下のアプローチにて実装しました。

1.法線ベクトルにより遮蔽判定する
まず、描画対象のピクセルとその周囲のピクセルの法線ベクトルの内角の大きさから遮蔽判定します。内角が大きくなるほどより強く遮蔽されていると考えます。

2.凸は遮蔽されていない
法線ベクトルの内角の大きさだけで判定するとメッシュのエッジ部分が凸になっている部分も遮蔽されていると判断されてしまいます。
例えばの青線部分です。
この部分を遮蔽されていないと判断するために、描画対象のピクセルとその周囲のピクセルの前後関係をチェックします。 描画対象のピクセルの深度値が周囲のピクセルの深度値より手前にあるときは遮蔽されていないと判断します。

3.深度値の差分が大きいときは遮蔽されていない
描画対象のピクセルの深度値と周囲のピクセルの深度値の距離が十分に離れているときは遮蔽されていないと判断します。
法線ベクトルだけで判定した場合、例えばのように距離が十分に離れていても遮蔽されていると判定されてしまうので、 深度値の距離の大きさも考慮します。

といった感じです。あとは作成された環境光遮蔽マップをブラー処理しますが、当サイトでのブラー処理は適当です。 ガウスフィルターを使おうかとも思いましたが、単純に64ボックスフィルタサンプリングを使用しました。 あと深度値も考慮してサンプリングしないとおかしな具合になると思いますが、そこまでやってません。 その辺は自分でやってみてください。

ではソースを見ていきます。


SSAO.hlsl SSAOのhlslファイル。
SSAO.h SSAOクラスのヘッダファイル。
SSAO.cpp SSAOクラスのソースファイル。
main.cpp メイン関数があるソースファイル。
Plane.fbx Plane.fbxファイル。
Object.fbx Object.fbxファイル。
01.jpg 01.jpgファイル。
02.jpg 02.jpgファイル。
今回は適当に作成したfbxファイルとテクスチャーもアップしておきます。使いたい人は使ってください。

---SSAO.hlsl---  ↑


// ************************************************************
// スクリーンスペース環境光遮蔽( SSAO )
// ************************************************************

// 周囲ピクセルへのオフセット値

// サンプリング数
#define SPHERE_COUNT 16
static float3 SphereArray16[SPHERE_COUNT] = {
        float3( 0.53812504, 0.18565957, -0.43192 )
      , float3( 0.13790712, 0.24864247, 0.44301823 )
      , float3( 0.33715037, 0.56794053, -0.005789503 )
      , float3( -0.6999805, -0.04511441, -0.0019965635 )
      , float3( 0.06896307, -0.15983082, -0.85477847 )
      , float3( 0.056099437, 0.006954967, -0.1843352 )
      , float3( -0.014653638, 0.14027752, 0.0762037 )
      , float3( 0.010019933, -0.1924225, -0.034443386)
      , float3( -0.35775623, -0.5301969, -0.43581226)
      , float3( -0.3169221, 0.106360726, 0.015860917)
      , float3(0.010350345, -0.58698344, 0.0046293875)
      , float3(-0.08972908, -0.49408212, 0.3287904)
      , float3(0.7119986, -0.0154690035, -0.09183723)
      , float3(-0.053382345, 0.059675813, -0.5411899)
      , float3(0.035267662, -0.063188605, 0.54602677)
      , float3(-0.47761092, 0.2847911, -0.0271716)
      };

// ブラーフィルター時のテクセルのオフセット配列
// サンプリング数
#define BLUROFFSET_COUNT 16
static float2 BlurOffset16[BLUROFFSET_COUNT] = {
        float2(  1,  1 )
      , float2( -1,  1 )
      , float2( -1, -1 )
      , float2(  1, -1 )
      , float2(  3,  1 )
      , float2(  3,  3 )
      , float2(  1,  3 )
      , float2( -1,  3 )
      , float2( -3,  3 )
      , float2( -3,  1 )
      , float2( -3, -1 )
      , float2( -3, -3 )
      , float2( -1, -3 )
      , float2(  1, -3 )
      , float2(  3, -3 )
      , float2(  3, -1 )
      };
// ************************************************************
// 構造体の宣言
// ************************************************************

// 法線マップ + 深度マップの描画フェーズで使用する構造体の宣言

// 頂点シェーダー入力用の構造体
struct _VS01
{
   float3 pos    : POSITION;   // 頂点座標
   float3 Normal : NORMAL;     // 法線
   float2 texel  : TEXCOORD;   // テクセル
};

// 頂点シェーダー - ピクセルシェーダーの構造体
struct VS_PS01
{
   float4 pos       : SV_POSITION;
   float3 Normal    : NORMAL;
   float2 texel     : TEXCOORD0;
   float4 posWVP    : TEXCOORD1;
};

// ピクセルシェーダー出力用の構造体
struct PS_01
{
   float4 BackBuffer   : SV_Target0;   // シーンのレンダリングイメージ
   float4 NormalBuffer : SV_Target1;   // 法線マップ + 深度マップ
};

// 環境光遮蔽マップ描画フェーズで使用する構造体の宣言

// 頂点シェーダー入力用の構造体
struct _VS02
{
   float3 pos   : POSITION;   // 頂点座標
   float2 texel : TEXCOORD;   // テクセル
};

// 頂点シェーダー - ピクセルシェーダー用の構造体
struct VS_PS02
{
   float4 pos    : SV_POSITION;
   float2 texel  : TEXCOORD0;
};

// ブラー処理フェーズで使用する構造体の宣言

// 頂点シェーダー入力用の構造体
struct _VS03
{
   float3 pos   : POSITION;   // 頂点座標
   float2 texel : TEXCOORD;   // テクセル
};

// 頂点シェーダー - ピクセルシェーダー用の構造体
struct VS_PS03
{
   float4 pos    : SV_POSITION;
   float2 texel  : TEXCOORD0;
};

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

// 定数バッファ1
cbuffer CB_STEP01 : register( b0 )
{
   column_major float4x4 g_matWVP : packoffset( c0 );   // ワールド × ビュー × 射影 行列
   column_major float4x4 g_matWV  : packoffset( c4 );   // ワールド × ビュー 行列
   float4 g_vecLight              : packoffset( c8 );   // ローカル座標系での平行光源の方向ベクトル
};

// 定数バッファ2
cbuffer CB_STEP02 : register( b0 )
{
   column_major float4x4 g_matInvProj : packoffset( c0 );   // 射影逆行列
   column_major float4x4 g_matProj    : packoffset( c4 );   // 射影行列
   float g_HemRadius                  : packoffset( c8.x ); // 環境光遮蔽の判定用の半球の半径
   float g_Zfar                       : packoffset( c8.y ); // Zfar
   float g_AOPower                    : packoffset( c8.z ); // 陰の強度
};

// 定数バッファ3
cbuffer CB_STEP03 : register( b0 )
{
   float2 g_ScreenSize                : packoffset( c0 );   // スクリーンサイズ
};

// ************************************************************
// テクスチャー
// ************************************************************

Texture2D g_DecalMap  : register( t0 );  // デカールマップ
Texture2D g_NormalMap : register( t0 );  // 法線マップ + 深度マップ
Texture2D g_SSAOMap   : register( t0 );  // 環境光遮蔽マップ

// ************************************************************
// サンプラーステート
// ************************************************************

SamplerState  g_Sampler : register( s0 );

// ************************************************************
// 法線マップ + 深度マップの描画フェーズ
// ************************************************************

// 頂点シェーダー
VS_PS01 Step01_VS_Main( _VS01 In )
{
   VS_PS01 Out;
   Out.pos    = mul( float4( In.pos, 1.0f ), g_matWVP );
   Out.Normal = In.Normal;
   Out.texel  = In.texel;
   Out.posWVP = Out.pos;

   return Out;
}

// ピクセルシェーダー
PS_01 Step01_PS_Main( VS_PS01 In )
{
   PS_01 Out;

   // デカールマップ
   float4 decalmap = g_DecalMap.Sample( g_Sampler, In.texel );
   
   // ライティング
   float lambert = dot( -g_vecLight.xyz, In.Normal );
   
   // ハーフランバート
   float halflambert = lambert * 0.5f + 0.5f;
   halflambert *= halflambert;

   // シーンのレンダリングイメージを出力
   Out.BackBuffer = float4( decalmap.rgb * halflambert, 1 );

   // 法線ベクトル + 深度マップを出力

   // 法線ベクトルをワールド空間上で行列変換する
   // 平行移動成分を無効にするためにw成分を 0 にする
   // 法線ベクトルのz成分は計算により算出するためここではいれない
   Out.NormalBuffer.xy = normalize( mul( float4( In.Normal, 0 ), g_matWV ).xyz ).xy;
   // 深度値
   Out.NormalBuffer.zw = In.posWVP.zw;

   return Out;
}

// ************************************************************
// 環境光遮蔽マップ描画フェーズ
// ************************************************************

// 頂点シェーダー
VS_PS02 Step02_VS_Main( _VS02 In )
{
   VS_PS02 Out;
   Out.pos    = float4( In.pos, 1 );
   Out.texel  = In.texel;
   return Out;
}

float3 CreateNormal( float2 xy )
{
   float3 normal;

   normal.xy = xy;
   // max() 入れないとなぜか正しく描画されないときがある
   normal.z = -sqrt( max( 1 - normal.x * normal.x - normal.y * normal.y, 0 ) );
   normal = normalize( normal );

   return normal;
}

float Step02_PS_Main( VS_PS02 In ) : SV_Target0
{
   float Out;
   
   // 描画ピクセルの法線マップ + 深度マップを取得
   float4 dispNormalMap = g_NormalMap.Sample( g_Sampler, In.texel );

   // 法線ベクトルを作成する
   float3 dispNormal = CreateNormal( dispNormalMap.xy );

   // 描画ピクセルのテクセル座標からクリップ空間上の座標を計算
   float4 dispClipPos;
   dispClipPos.xy = ( In.texel * float2( 2.0f, -2.0f ) + float2( -1.0f, 1.0f ) ) * dispNormalMap.w;
   dispClipPos.zw = dispNormalMap.zw;
   
   // カメラ空間上での座標を計算
   float4 dispViewPos = mul( dispClipPos, g_matInvProj );

   float normAO = 0;
   float depthAO = 0;
   
   for( uint i=0; i<SPHERE_COUNT; i++ )
   {
      // レイの方向ベクトル
      float3 ray = SphereArray16[i].xyz * g_HemRadius;

      // レイの方向ベクトルを描画ピクセルの法線方向の半球内に収まるように方向を変換する
      ray = sign( dot( dispNormal, ray ) ) * ray;
      
      // 周囲ピクセルの座標
      float4 envPos;
      // レイ方向に移動
      envPos.xyz = dispViewPos.xyz + ray;
      // クリップ空間上に行列変換
      envPos = mul( float4( envPos.xyz, 1 ), g_matProj );
      // スクリーン空間に変換
      envPos.xy = envPos.xy / envPos.w * float2( 0.5f, -0.5f ) + 0.5f;

      // 周囲ピクセルのサンプリング
      float4 envNormalMap = g_NormalMap.Sample( g_Sampler, envPos.xy );

      // 法線ベクトルを作成する
      float3 envNormal = CreateNormal( envNormalMap.xy );

      // 内積の角度が大きくなるほど環境光遮蔽係数が大きくなるように計算する
      float n = dot( dispNormal, envNormal ) * 0.5f + 0.5f;
      // エッジが凸になっている部分は遮蔽されないようにする
      n += step( dispNormalMap.z, envNormalMap.z );
      normAO += min( n, 1 );
      
      // 深度値の距離が大きいほど環境光遮蔽の影響力が小さくなるようにする
      depthAO += abs( dispNormalMap.z - envNormalMap.z ) / g_Zfar;
   }

   Out = normAO / (float)SPHERE_COUNT + depthAO;
   // 陰を強調する
   Out = pow( abs( Out ), g_AOPower );
   
   return Out;
}

// ************************************************************
// ブラー処理フェーズ
// ************************************************************

// 頂点シェーダー
VS_PS03 Step03_VS_Main( _VS03 In )
{
   VS_PS03 Out;
   Out.pos    = float4( In.pos, 1 );
   Out.texel  = In.texel;
   return Out;
}

float4 Step03_PS_Main( VS_PS03 In ) : SV_Target0
{
   float Out = 0;
   
   for( uint i=0; i<BLUROFFSET_COUNT; i++ )
   {
      Out += g_SSAOMap.Sample( g_Sampler, In.texel + BlurOffset16[i].xy / g_ScreenSize ).r;
   }
   Out = Out / (float)BLUROFFSET_COUNT;
   return Out;
}

---SSAO.h---  ↑

#ifndef SSAO_H
#define SSAO_H

#include "Polygon2DUser.h"

class SSAO
{
private:
   // 法線マップ + 深度マップの描画フェーズで使用する構造体定義
   typedef struct _CB_STEP01
   {
      // ワールド × ビュー × 射影 行列
      D3DXMATRIX  matWVP;
      // ワールド × ビュー 行列
      D3DXMATRIX  matWV;
      // 平行光源の方向ベクトル
      D3DXVECTOR4 vecLight;
   }CB_STEP01;
   
   // 環境光遮蔽マップ描画フェーズで使用する構造体定義
   typedef struct _CB_STEP02
   {
      // 射影逆行列
      D3DXMATRIX  matInvProj;
      // 射影行列
      D3DXMATRIX  matProj;
      // 環境光遮蔽の判定用の半球の半径
      float HemRadius;
      // Zfar
      float Zfar;
      // 陰の強度
      float AOPower;
      float Dummy3;
   }CB_STEP02;

   // ブラー処理フェーズで使用する構造体定義

   // 法線マップ + 深度マップの描画フェーズで使用するリソースの構造体定義
   typedef struct _STEP01
   {
      // 入力レイアウト
      ID3D11InputLayout* pLayout;

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

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

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

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

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

      // ブレンドステート
      ID3D11BlendState* pBlendState;
   }STEP01;

   // 環境光遮蔽マップ描画フェーズで使用するリソースの構造体定義
   typedef struct _STEP02
   {
      // 入力レイアウト
      ID3D11InputLayout* pLayout;

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

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

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

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

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

      // ブレンドステート
      ID3D11BlendState* pBlendState;
   }STEP02;

   // ブラー処理フェーズで使用するリソースの構造体定義
   typedef struct _STEP03
   {
      // 入力レイアウト
      ID3D11InputLayout* pLayout;

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

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

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

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

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

      // ブレンドステート
      ID3D11BlendState* pBlendState;
   }STEP03;

   CPolygon2D m_Polygon2D;

   // 宣言
   STEP01 m_Step01;
   STEP02 m_Step02;
   STEP03 m_Step03;

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

   // 法線マップ + 深度マップの描画フェーズの初期化
   HRESULT InitStep01( ID3D11Device* pD3DDevice
                     , const BYTE* pVSStep01Shader, size_t VSStep01Size
                     , const BYTE* pPSStep01Shader, size_t PSStep01Size
                     );

   // 環境光遮蔽マップ描画フェーズの初期化
   HRESULT InitStep02( ID3D11Device* pD3DDevice
                     , const BYTE* pVSStep02Shader, size_t VSStep02Size
                     , const BYTE* pPSStep02Shader, size_t PSStep02Size
                     );

   // ブラー処理フェーズの初期化
   HRESULT InitStep03( ID3D11Device* pD3DDevice
                     , const BYTE* pVSStep03Shader, size_t VSStep03Size
                     , const BYTE* pPSStep03Shader, size_t PSStep03Size
                     , D3DXVECTOR2* pScreenSize
                     );
public:
   SSAO();
   ~SSAO();

   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice
               // hlslファイルのファイル名
               , TCHAR pSrcFile[]
               // 法線マップ + 深度マップの描画フェーズ
               , CHAR pVSStep01FunctionName[], CHAR pPSStep01FunctionName[]
               // 環境光遮蔽マップの描画フェーズ
               , CHAR pVSStep02FunctionName[], CHAR pPSStep02FunctionName[]
               // ブラー処理フェーズ
               , CHAR pVSStep03FunctionName[], CHAR pPSStep03FunctionName[]
               , D3DXVECTOR2* pScreenSize
               );
   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
               // ブラー処理フェーズ
               , const BYTE* pVSStep03Shader, size_t VSStep03Size
               , const BYTE* pPSStep03Shader, size_t PSStep03Size
               , D3DXVECTOR2* pScreenSize
               );

   // 法線マップ + 深度マップの描画フェーズの開始処理
   HRESULT BeginStep01( ID3D11DeviceContext* pD3DDeviceContext );
   // 法線マップ + 深度マップの描画フェーズで使用する定数バッファを設定
   HRESULT SetCBStep01( ID3D11DeviceContext* pD3DDeviceContext
                      , D3DXMATRIX* p_matWVP, D3DXMATRIX* p_matWV
                      , D3DXVECTOR4* p_vecLight
                      , ID3D11ShaderResourceView* pDecalMap
                      );
   // 法線マップ + 深度マップの描画フェーズの終了処理
   HRESULT EndStep01( ID3D11DeviceContext* pD3DDeviceContext );

   // 環境光遮蔽マップ描画フェーズの描画関数
   HRESULT RenderStep02( ID3D11DeviceContext* pD3DDeviceContext
                       , D3DXMATRIX* p_matInvProj, D3DXMATRIX* p_matProj
                       , ID3D11ShaderResourceView* pSRView[1]
                       , float HemRadius, float Zfar, float AOPower
                       );

   // ブラー処理フェーズの描画関数
   HRESULT RenderStep03( ID3D11DeviceContext* pD3DDeviceContext
                       , ID3D11ShaderResourceView* pSRView[1]
                       );

};

#endif

---SSAO.cpp---  ↑

#include "DX11User.h"
#include "SSAO.h"

SSAO::SSAO()
{
   m_Step01.pLayout = NULL;
   m_Step01.pVertexShader = NULL;
   m_Step01.pPixelShader = NULL;
   m_Step01.pConstantBuffers = NULL;
   m_Step01.pSamplerState = NULL;
   m_Step01.pDepthStencilState = NULL;
   m_Step01.pBlendState = NULL;

   m_Step02.pLayout = NULL;
   m_Step02.pVertexShader = NULL;
   m_Step02.pPixelShader = NULL;
   m_Step02.pConstantBuffers = NULL;
   m_Step02.pSamplerState = NULL;
   m_Step02.pDepthStencilState = NULL;
   m_Step02.pBlendState = NULL;

   m_Step03.pLayout = NULL;
   m_Step03.pVertexShader = NULL;
   m_Step03.pPixelShader = NULL;
   m_Step03.pConstantBuffers = NULL;
   m_Step03.pSamplerState = NULL;
   m_Step03.pDepthStencilState = NULL;
   m_Step03.pBlendState = NULL;
}

SSAO::~SSAO()
{
   SAFE_RELEASE( m_Step01.pLayout );
   SAFE_RELEASE( m_Step01.pVertexShader );
   SAFE_RELEASE( m_Step01.pPixelShader );
   SAFE_RELEASE( m_Step01.pConstantBuffers );
   SAFE_RELEASE( m_Step01.pSamplerState );
   SAFE_RELEASE( m_Step01.pDepthStencilState );
   SAFE_RELEASE( m_Step01.pBlendState );

   SAFE_RELEASE( m_Step02.pLayout );
   SAFE_RELEASE( m_Step02.pVertexShader );
   SAFE_RELEASE( m_Step02.pPixelShader );
   SAFE_RELEASE( m_Step02.pConstantBuffers );
   SAFE_RELEASE( m_Step02.pSamplerState );
   SAFE_RELEASE( m_Step02.pDepthStencilState );
   SAFE_RELEASE( m_Step02.pBlendState );

   SAFE_RELEASE( m_Step03.pLayout );
   SAFE_RELEASE( m_Step03.pVertexShader );
   SAFE_RELEASE( m_Step03.pConstantBuffers );
   SAFE_RELEASE( m_Step03.pPixelShader );
   SAFE_RELEASE( m_Step03.pSamplerState );
   SAFE_RELEASE( m_Step03.pDepthStencilState );
   SAFE_RELEASE( m_Step03.pBlendState );
}

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

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

   hr = S_OK;
EXIT:
   return hr;
}

// 法線マップ + 深度マップの描画フェーズの初期化
HRESULT SSAO::InitStep01( ID3D11Device* pD3DDevice
                        , const BYTE* pVSStep01Shader, size_t VSStep01Size
                        , const BYTE* pPSStep01Shader, size_t PSStep01Size
                        )
{
   HRESULT hr = E_FAIL;
   D3D11_BUFFER_DESC BufferDesc;

   if( pD3DDevice == NULL )
      goto EXIT;

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

   hr = pD3DDevice->CreateVertexShader( pVSStep01Shader, VSStep01Size, NULL, &m_Step01.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 },
         { "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 },
   };
   hr = pD3DDevice->CreateInputLayout( layout, _countof( layout ), pVSStep01Shader, VSStep01Size, &m_Step01.pLayout );
   if( FAILED( hr ) )
      goto EXIT;

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

   hr = pD3DDevice->CreatePixelShader( pPSStep01Shader, PSStep01Size, NULL, &m_Step01.pPixelShader );
   if( FAILED( hr ) ) 
      goto EXIT;

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

   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CB_STEP01 );       // バッファサイズ
   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_Step01.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_Step01.pSamplerState );
   if( FAILED( hr ) )
      goto EXIT;

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

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

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

   D3D11_BLEND_DESC BlendDesc;
   ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) );
   BlendDesc.AlphaToCoverageEnable = FALSE;
   BlendDesc.IndependentBlendEnable = FALSE;
   // アルファブレンドを無効
   BlendDesc.RenderTarget[0].BlendEnable = FALSE;
   BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_Step01.pBlendState );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// 環境光遮蔽マップ描画フェーズの初期化
HRESULT SSAO::InitStep02( ID3D11Device* pD3DDevice
                        , const BYTE* pVSStep02Shader, size_t VSStep02Size
                        , const BYTE* pPSStep02Shader, size_t PSStep02Size
                        )
{
   HRESULT hr = E_FAIL;
   D3D11_BUFFER_DESC BufferDesc;
   D3DX11_IMAGE_LOAD_INFO info;

   if( pD3DDevice == NULL ) 
      goto EXIT;

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

   hr = pD3DDevice->CreateVertexShader( pVSStep02Shader, VSStep02Size, NULL, &m_Step02.pVertexShader );
   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_Step02.pLayout );
   if( FAILED( hr ) )
      goto EXIT;

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

   hr = pD3DDevice->CreatePixelShader( pPSStep02Shader, PSStep02Size, NULL, &m_Step02.pPixelShader );
   if( FAILED( hr ) )
      goto EXIT;

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

   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CB_STEP02 );
   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_Step02.pConstantBuffers );
   if( FAILED( hr ) )
      goto EXIT;

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

   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
   samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;     // 周囲ピクセルをサンプリングするので CLAMP にする
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;     // 周囲ピクセルをサンプリングするので CLAMP にする
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;     // 周囲ピクセルをサンプリングするので CLAMP にする
   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_Step02.pSamplerState );
   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_Step02.pDepthStencilState );
   if( FAILED( hr ) )
      goto EXIT;

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

   D3D11_BLEND_DESC BlendDesc;
   ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) );
   BlendDesc.AlphaToCoverageEnable = FALSE;
   BlendDesc.IndependentBlendEnable = FALSE;
   // アルファブレンドを無効
   BlendDesc.RenderTarget[0].BlendEnable = FALSE;
   BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_Step02.pBlendState );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// ブラー処理フェーズの初期化
HRESULT SSAO::InitStep03( ID3D11Device* pD3DDevice
                        , const BYTE* pVSStep03Shader, size_t VSStep03Size
                        , const BYTE* pPSStep03Shader, size_t PSStep03Size
                        , D3DXVECTOR2* pScreenSize
                        )
{
   HRESULT hr = E_FAIL;
   D3D11_BUFFER_DESC BufferDesc;

   if( pD3DDevice == NULL )
      goto EXIT;

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

   hr = pD3DDevice->CreateVertexShader( pVSStep03Shader, VSStep03Size, NULL, &m_Step03.pVertexShader );
   if( FAILED( hr ) )
      goto EXIT;

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

   D3D11_INPUT_ELEMENT_DESC* pInputElement = NULL;
   UINT InputElementCount;
   m_Polygon2D.GetInputElement( &pInputElement, &InputElementCount );
   hr = pD3DDevice->CreateInputLayout( pInputElement, InputElementCount, pVSStep03Shader, VSStep03Size, &m_Step03.pLayout );
   if( FAILED( hr ) )
      goto EXIT;

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

   hr = pD3DDevice->CreatePixelShader( pPSStep03Shader, PSStep03Size, NULL, &m_Step03.pPixelShader );
   if( FAILED( hr ) )
      goto EXIT;

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

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

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

   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
   samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;    // ブラーを適応するので CLAMP で設定する
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;    // ブラーを適応するので CLAMP で設定する
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;    // ブラーを適応するので CLAMP で設定する
   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_Step03.pSamplerState );
   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_Step03.pDepthStencilState );
   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_ZERO;
   BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_COLOR;
   BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
   BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
   BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
   BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
   hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_Step03.pBlendState );
   if( FAILED( hr ) )
      goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// 初期化
HRESULT SSAO::Init( ID3D11Device* pD3DDevice
                   // hlsl ファイル名
                  , TCHAR pSrcFile[]
                   // 法線マップ + 深度マップの描画フェーズ
                  , CHAR pVSStep01FunctionName[], CHAR pPSStep01FunctionName[]
                   // 環境光遮蔽マップ描画フェーズ
                  , CHAR pVSStep02FunctionName[], CHAR pPSStep02FunctionName[]
                   // ブラー処理フェーズ
                  , CHAR pVSStep03FunctionName[], CHAR pPSStep03FunctionName[]
                  , D3DXVECTOR2* pScreenSize
                  )
{
   HRESULT hr = E_FAIL;

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

   // *****************************************************************************************************************
   // 共通項目の初期化
   // *****************************************************************************************************************

   hr = InitCommon( pD3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

   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, 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 = InitStep01( pD3DDevice
                  , reinterpret_cast<LPBYTE>( pBlob[0]->GetBufferPointer() ), pBlob[0]->GetBufferSize()
                  , reinterpret_cast<LPBYTE>( pBlob[1]->GetBufferPointer() ), pBlob[1]->GetBufferSize()
                  );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // 環境光遮蔽マップ描画フェーズ用のシェーダーソースのコンパイル
   // *****************************************************************************************************************

   // 頂点シェーダーのコンパイル
   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 = InitStep02( pD3DDevice
                  , reinterpret_cast<LPBYTE>( pBlob[0]->GetBufferPointer() ), pBlob[0]->GetBufferSize()
                  , reinterpret_cast<LPBYTE>( pBlob[1]->GetBufferPointer() ), pBlob[1]->GetBufferSize()
                  );
   if( FAILED( hr ) )
      goto EXIT;

   // *****************************************************************************************************************
   // ブラー処理フェーズ用のシェーダーソースのコンパイル
   // *****************************************************************************************************************

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

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

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

   hr = S_OK;

EXIT:
   return hr;
}

// 初期化
HRESULT SSAO::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
                  // ブラー処理フェーズ
                  , const BYTE* pVSStep03Shader, size_t VSStep03Size
                  , const BYTE* pPSStep03Shader, size_t PSStep03Size
                  , D3DXVECTOR2* pScreenSize
                  )
{
   HRESULT hr = E_FAIL;

   // 法線マップ + 深度マップの描画フェーズ用の初期化
   hr = InitStep01( pD3DDevice, pVSStep01Shader, VSStep01Size, pPSStep01Shader, PSStep01Size );
   if( FAILED( hr ) )
      goto EXIT;

   // 環境光遮蔽マップ描画フェーズ用の初期化
   hr = InitStep02( pD3DDevice, pVSStep02Shader, VSStep02Size, pPSStep02Shader, PSStep02Size );
   if( FAILED( hr ) )
      goto EXIT;

   // ブラー処理フェーズ用の初期化
   hr = InitStep03( pD3DDevice, pVSStep03Shader, VSStep03Size, pPSStep03Shader, PSStep03Size, pScreenSize );
   if( FAILED( hr ) )
      goto EXIT;

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

   hr = S_OK;

EXIT:
   return hr;
}

// 法線マップ + 深度マップの描画フェーズの開始処理
HRESULT SSAO::BeginStep01( ID3D11DeviceContext* pD3DDeviceContext )
{
   HRESULT hr = E_FAIL;

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

   pD3DDeviceContext->IASetInputLayout( m_Step01.pLayout );

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

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

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

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

   // ジオメトリシェーダーを無効にする。
   pD3DDeviceContext->GSSetShader( NULL, NULL, 0 );
   
   // ピクセルシェーダーをデバイスに設定する
   pD3DDeviceContext->PSSetShader( m_Step01.pPixelShader, NULL, 0 );
   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_Step01.pSamplerState );

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

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

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

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

   hr = S_OK;
//EXIT:
   return hr;
}

// 法線マップ + 深度マップの描画フェーズの定数バッファの設定
HRESULT SSAO::SetCBStep01( ID3D11DeviceContext* pD3DDeviceContext
                         , D3DXMATRIX* p_matWVP, D3DXMATRIX* p_matWV
                         , D3DXVECTOR4* p_vecLight
                         , ID3D11ShaderResourceView* pDecalMap )
{
   HRESULT hr = E_FAIL;

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

   D3D11_MAPPED_SUBRESOURCE mappedResource;
   CB_STEP01* cbuffer;

   hr = pD3DDeviceContext->Map( m_Step01.pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) ) goto EXIT;
   cbuffer = reinterpret_cast<CB_STEP01*>(mappedResource.pData);

   ::CopyMemory( &cbuffer->matWVP, p_matWVP, sizeof( D3DXMATRIX ));
   ::CopyMemory( &cbuffer->matWV, p_matWV, sizeof( D3DXMATRIX ));
   ::CopyMemory( &cbuffer->vecLight, p_vecLight, sizeof( D3DXVECTOR4 ));

   pD3DDeviceContext->Unmap( m_Step01.pConstantBuffers, 0 );

   // *****************************************************************************************************************
   // 定数バッファをデバイスに設定
   // *****************************************************************************************************************

   // 頂点シェーダーに定数バッファを設定する
   pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_Step01.pConstantBuffers );

   // ピクセルシェーダーに定数バッファを設定する
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_Step01.pConstantBuffers );
   // デカールマップを設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &pDecalMap );

   hr = S_OK;
EXIT:
   return hr;
}

// 法線マップ + 深度マップの描画フェーズの終了処理( 何もしない )
HRESULT SSAO::EndStep01( ID3D11DeviceContext* /*pD3DDeviceContext*/ )
{
   HRESULT hr = E_FAIL;

   hr = S_OK;

//EXIT:
   return hr;
}

// 環境光遮蔽マップ描画フェーズの描画関数
HRESULT SSAO::RenderStep02( ID3D11DeviceContext* pD3DDeviceContext
                          , D3DXMATRIX* p_matInvProj, D3DXMATRIX* p_matProj
                          , ID3D11ShaderResourceView* pSRView[1]
                          , float HemRadius, float Zfar, float AOPower
                          )
{
   HRESULT hr = E_FAIL;

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

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

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

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

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

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

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

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

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

   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_Step02.pSamplerState );
   // 法線 + 深度マップ
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRView[0] );

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

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

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

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

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

   D3D11_MAPPED_SUBRESOURCE mappedResource;
   CB_STEP02* cbuffer;

   hr = pD3DDeviceContext->Map( m_Step02.pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
   if( FAILED( hr ) )
      goto EXIT;
   cbuffer = reinterpret_cast<CB_STEP02*>(mappedResource.pData);
   ::CopyMemory( cbuffer->matInvProj, p_matInvProj, sizeof( D3DXMATRIX ) );
   ::CopyMemory( cbuffer->matProj, p_matProj, sizeof( D3DXMATRIX ) );
   cbuffer->HemRadius = HemRadius;
   cbuffer->Zfar = Zfar;
   cbuffer->AOPower = AOPower;
   pD3DDeviceContext->Unmap( m_Step02.pConstantBuffers, 0 );

   // *****************************************************************************************************************
   // 定数バッファをデバイスに設定
   // *****************************************************************************************************************

   // ピクセルシェーダーに定数バッファを設定する
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_Step02.pConstantBuffers );

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

   m_Polygon2D.Render( pD3DDeviceContext );

   // クリアする
   ID3D11ShaderResourceView* pSRVNull[2] = { NULL, NULL };
   pD3DDeviceContext->PSSetShaderResources( 0, 2, pSRVNull );

   hr = S_OK;
EXIT:
   return hr;

}

// ブラー処理フェーズの描画関数
HRESULT SSAO::RenderStep03( ID3D11DeviceContext* pD3DDeviceContext
                          , ID3D11ShaderResourceView* pSRView[1]
                          )
{
   HRESULT hr = E_FAIL;

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

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

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

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

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

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

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

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

   // ピクセルシェーダーをデバイスに設定する。
   pD3DDeviceContext->PSSetShader( m_Step03.pPixelShader, NULL, 0 );
   // ピクセルシェーダーにサンプラーステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_Step03.pSamplerState );
   // 法線マップ + 深度マップのシェーダーリソースビューをデバイスに設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, pSRView );

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

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

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

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

   // *****************************************************************************************************************
   // 定数バッファをデバイスに設定
   // *****************************************************************************************************************

   // ピクセルシェーダーに定数バッファを設定する
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_Step03.pConstantBuffers );

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

   m_Polygon2D.Render( pD3DDeviceContext );

   hr = S_OK;
//EXIT:
   return hr;

}

---main.cpp---  ↑

#include "../../USER/DX11User.h"
#include "../../USER/D3D11User.h"
#include "../../USER/DebugFontUser.h"
#include "../../USER/SSAO.h"

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

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

#else
// SSAO
#include "../../USER/HLSL/SSAO_Step01_VS_Main.h"
#include "../../USER/HLSL/SSAO_Step01_PS_Main.h"
#include "../../USER/HLSL/SSAO_Step02_VS_Main.h"
#include "../../USER/HLSL/SSAO_Step02_PS_Main.h"
#include "../../USER/HLSL/SSAO_Step03_VS_Main.h"
#include "../../USER/HLSL/SSAO_Step03_PS_Main.h"
#endif

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

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

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

// FBX メッシュローダー
FBXSDK_MESHLOADER_USER* g_pMeshPlaneBallLoader = NULL;

// メッシュオブジェクト
BASE_MESH_USER*         g_pMeshPlane = NULL;
BASE_MESH_USER*         g_pMeshObject = NULL;

// SSAOクラス
SSAO* g_pSSAO = NULL;

// レンダーターゲットサーフェス
ID3D11RenderTargetView* g_pRTView[2] = { NULL, NULL };

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

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

// ビュー行列
D3DXMATRIX g_matView;

int g_Mode = 0;

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

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

// リソースの初期化
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_pMeshPlaneBallLoader = NEW FBXSDK_MESHLOADER_USER();
   hr = g_pMeshPlaneBallLoader->Initialize( g_pD3D11User->m_D3DDevice );
   if( FAILED( hr ) )
      goto EXIT;

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

   hr = g_pMeshPlaneBallLoader->LoadMeshData( _T("Res/Object.fbx"), &g_pMeshObject );
   if( FAILED( hr ) )
      goto EXIT;

   // シェーダー系クラスの初期化
   g_pSSAO = NEW SSAO();

   // バックバッファのサイズ
   DXGI_SWAP_CHAIN_DESC SwapchainDesc;
   g_pD3D11User->m_SwapChain->GetDesc( &SwapchainDesc );
#ifndef UNCOMPILED_SHADER
   hr = g_pSSAO->Init( g_pD3D11User->m_D3DDevice
                     , g_Step01_VS_Main, sizeof( g_Step01_VS_Main )
                     , g_Step01_PS_Main, sizeof( g_Step01_PS_Main )
                     , g_Step02_VS_Main, sizeof( g_Step02_VS_Main )
                     , g_Step02_PS_Main, sizeof( g_Step02_PS_Main )
                     , g_Step03_VS_Main, sizeof( g_Step03_VS_Main )
                     , g_Step03_PS_Main, sizeof( g_Step03_PS_Main )
                     , &D3DXVECTOR2( (float)SwapchainDesc.BufferDesc.Width, (float)SwapchainDesc.BufferDesc.Height )
                     );
   if( FAILED( hr ) )
      goto EXIT;
#else
   hr = g_pSSAO->Init( g_pD3D11User->m_D3DDevice
                     , _T("../../USER/HLSL/SSAO.hlsl")
                     , "Step01_VS_Main", "Step01_PS_Main"
                     , "Step02_VS_Main", "Step02_PS_Main"
                     , "Step03_VS_Main", "Step03_PS_Main"
                     , &D3DXVECTOR2( (float)SwapchainDesc.BufferDesc.Width, (float)SwapchainDesc.BufferDesc.Height )
                     );
   if( FAILED( hr ) )
      goto EXIT;
#endif

   // 法線マップ + 深度マップ
   hr = g_pD3D11User->CreateRenderTargetView( &g_pRTView[0], NULL, DXGI_FORMAT_R16G16B16A16_FLOAT );
   if( FAILED( hr ) )
      goto EXIT;

   // 環境光遮蔽マップ
   hr = g_pD3D11User->CreateRenderTargetView( &g_pRTView[1], NULL, DXGI_FORMAT_R8_UNORM );
   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 ) );

   hr = S_OK;

EXIT:
   return hr;
}

// メモリ開放
void Invalidate()
{
   SAFE_DELETE( g_pSSAO );
   SAFE_DELETE( g_pMeshObject );
   SAFE_DELETE( g_pMeshPlane );
   SAFE_DELETE( g_pMeshPlaneBallLoader );
   for( int i=0; i<_countof( g_pRTView ); i++ )
      SAFE_RELEASE( g_pRTView[i] );
   SAFE_DELETE( g_pDebugFontUser );
   SAFE_DELETE( g_pD3D11User );
}

// メッシュ描画
HRESULT RenderMesh( D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj )
{
   HRESULT hr = E_FAIL;

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

   // *****************************************************************************************************************
   // 地面の描画
   // *****************************************************************************************************************

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

   // インデックスバッファ設定
   g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pMeshPlane->MeshUser[0].IndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
  
   // デカールマップを取得
   ID3D11ShaderResourceView* pDecalMap = NULL;
   g_pMeshPlane->MeshUser[0].GetTexture( _T("DiffuseColor"), &pDecalMap );

   // 定数バッファとシェーダーリソースビューを設定する
   {
      // ワールド行列

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

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

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

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

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

      // 定数バッファとシェーダーリソースビューを設定する
      hr = g_pSSAO->SetCBStep01( g_pD3D11User->m_D3DDeviceContext, &matWVP, &matWV, &vec4LightDir, pDecalMap );
      if( FAILED( hr ) )
         goto EXIT;
   }

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

   // *****************************************************************************************************************
   // オブジェクトの描画
   // *****************************************************************************************************************

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

   // インデックスバッファ設定
   g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pMeshObject->MeshUser[0].IndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
  
   // デカールマップを取得
   pDecalMap = NULL;
   g_pMeshObject->MeshUser[0].GetTexture( _T("DiffuseColor"), &pDecalMap );

   // 定数バッファとシェーダーリソースビューを設定する
   {
      // ワールド行列

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

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

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

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

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

      // 定数バッファとシェーダーリソースビューを設定する
      hr = g_pSSAO->SetCBStep01( g_pD3D11User->m_D3DDeviceContext, &matWVP, &matWV, &vec4LightDir, pDecalMap );
      if( FAILED( hr ) )
         goto EXIT;
   }

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

   hr = S_OK;
EXIT:
   return hr;
}

// 描画処理
HRESULT Render()
{
   HRESULT hr = E_FAIL;
   D3DXMATRIX matProj, m, matInvProj;
   float Zfar = 100.0f;
   float BackBufferClearColor[4] = { 0.3f, 0.3f, 0.9f, 1.0f };
   float NormalMapClearColor[4] = { 0.0f, 0.0f, Zfar, Zfar };

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

   // 深度バッファをクリア
   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, Zfar );

   // ビュー行列
   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.01f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer[VK_DOWN] )
   {
      D3DXMatrixTranslation( &m, 0, 0, 0.01f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer['W'] )
   {
      D3DXMatrixRotationX( &m, 0.001f );
      g_matView = g_matView * m;
   }
   if( g_KeyBuffer['S'] )
   {
      D3DXMatrixRotationX( &m, -0.001f );
      g_matView = g_matView * m;
   }

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

   ID3D11RenderTargetView* pRTV[2] = { NULL, NULL };

   // レンダーターゲットサーフェスをクリア
   g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pRTView[0], NormalMapClearColor ); 

   // レンダーターゲットサーフェスのステージ0はそのまま
   pRTV[0] = g_pD3D11User->m_RenderTargetView;
   pRTV[1] = g_pRTView[0];

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

   // シェーダーの開始
   g_pSSAO->BeginStep01( g_pD3D11User->m_D3DDeviceContext );
   {
      hr = RenderMesh( &g_matView, &matProj );
      if( FAILED( hr ) )
         goto EXIT;
   }
   g_pSSAO->EndStep01( g_pD3D11User->m_D3DDeviceContext );

   ID3D11ShaderResourceView* pSRV[1] = { NULL };
   // シェーダーリソースビューを作成
   pSRV[0] = g_pD3D11User->GetSRViewFromRTView( g_pRTView[0] );

   pRTV[0] = g_pRTView[1];
   pRTV[1] = NULL;

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

   // 環境光遮蔽マップの描画
   D3DXMatrixInverse( &matInvProj, NULL, &matProj );
   hr = g_pSSAO->RenderStep02( g_pD3D11User->m_D3DDeviceContext, &matInvProj, &matProj, &pSRV[0], 0.2f, Zfar, 10.0f );
   if( FAILED( hr ) )
      goto EXIT;

   for( int i=0; i<_countof( pSRV ); i++ )
      SAFE_RELEASE( pSRV[i] );

   // シェーダーリソースビューを作成
   pSRV[0] = g_pD3D11User->GetSRViewFromRTView( g_pRTView[1] );

   // シェーダーリソースビューを作成
   pRTV[0] = g_pD3D11User->m_RenderTargetView;
   pRTV[1] = NULL;

   // レンダーターゲットサーフェスを戻す
   g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 2, pRTV, g_pD3D11User->m_DepthStencilView );

   // ブラー処理を行いバックバッファに合成する
   if( g_Mode == 0 )
   {
      hr = g_pSSAO->RenderStep03( g_pD3D11User->m_D3DDeviceContext, &pSRV[0] );
      if( FAILED( hr ) )
         goto EXIT;
   }

   for( int i=0; i<_countof( pSRV ); i++ )
      SAFE_RELEASE( pSRV[i] );

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

      switch( g_Mode )
      {
      case 0:
         hr = g_pDebugFontUser->RenderDebugText( g_pD3D11User->m_D3DDeviceContext, "SSAO", 0, 0.1f );
         if( FAILED( hr ) )
            goto EXIT;
         break;
      case 1:
         hr = g_pDebugFontUser->RenderDebugText( g_pD3D11User->m_D3DDeviceContext, "None SSAO", 0, 0.1f );
         if( FAILED( hr ) )
            goto EXIT;
         break;
      }
   }

   // レンダリングされたイメージをユーザーに表示。
   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;
}

今回はここまで

web拍手 by FC2

Prev Top Next

inserted by FC2 system