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

■Direct3D 11.0 ガウスフィルター Prev Top Next
関連ページ:Direct3D 11.0 初期化 Direct3D 11.0 デバック用フォント描画
2011/03/23:
  1. ハーフランバートシェーダーを記述
2011/05/10:
  1. 入力レイアウトの作成処理を D3D11USER クラス内で行うように修正
201105/22:
  1. いろいろ大改造
2012/03/11:
  1. マルチレンダーターゲットに対応するためにブレンドステートを設定する関数を修正


 

今回はガウスフィルターをやります。ブラー処理自体は DirectX 9.0 のサンプルで紹介してますが、これとは別の方法で実装します。 ガウスフィルターはガウス関数を使用してブラー処理を適応します。さてこのガウス関数ですが、当サイトでは例によって解説しません。 この辺を詳しく知りたい方は、今給黎氏の著書「DirectX 9 シェーダプログラミングブック」を参照してください。 実装方法についても詳しく解説しないのでよくわからない方は、そちらを参照してください。

さて、このガウスフィルターですが1個のパラメータによってぼけ具合を調整できるので非常に便利です。 今後のサンプルPGでブラー処理が必要となったらガウスフィルターを使用して行く予定です。

ちなみに今回のネタと一緒に Direct3D 11.0 の初期化クラスの D3D11USER も修正しています。すでに参照されている方はDirect3D 11.0 初期化を参照して修正してください。

あと球体の照明計算はハーフランバートを使用しています。今回のページで一応ソースを載せますが、既出なので説明は省略します。

Polygon2DUser.h 2Dポリゴンクラスの定義。
Polygon2DUser.cpp 2Dポリゴンクラスの実装部分。
ShaderUser.h 不完全なシェーダーの基底クラス(笑)。
ShaderUser.cpp 不完全なシェーダーの基底クラスの実装部分。
HalfLambert.hlsl ハーフランバートのシェーダーソース。
HalfLambert.h ハーフランバートクラスの定義。
HalfLambert.cpp ハーフランバートクラスの実装部分。
GaussianFilter.hlsl ブラーフィルターのシェーダーソース。
GaussianFilter.h ブラーフィルタークラスの定義。
GaussianFilter.cpp ブラーフィルタークラスの実装部分。
main.cpp メイン処理。


---Polygon2DUser.h---  ↑

#ifndef POLYGON2DUSER_H
#define POLYGON2DUSER_H

class CPolygon2D
{
private:
   // 2Dポリゴンの頂点定義
   typedef struct _VERTEX
   {
      // 頂点座標
      D3DXVECTOR3 pos;
      // テクセル
      D3DXVECTOR2 texel;
   }VERTEX;

   D3D11_INPUT_ELEMENT_DESC m_pInputElement[2];

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

public:
   CPolygon2D();
   void Invalidate();
   virtual ~CPolygon2D();
   // 作成処理
   HRESULT Create( ID3D11Device* pD3DDevice );
   // 頂点エレメントを取得
   void GetInputElement( D3D11_INPUT_ELEMENT_DESC** ppInputElement, UINT* pInputElementCount );
   // 描画
   void Render( ID3D11DeviceContext* pD3DDeviceContext ) const;
};

#endif

---Polygon2DUser.cpp---  ↑

#include <mbstring.h>
#include "DX11User.h"
#include "D3D11User.h"
#include "Polygon2DUser.h"

CPolygon2D::CPolygon2D()
{
   m_pVertexBuffer = nullptr;
   m_pInputElement[0].SemanticName = nullptr;
   m_pInputElement[1].SemanticName = nullptr;
}

void CPolygon2D::Invalidate()
{
   SAFE_RELEASE( m_pVertexBuffer );
   SAFE_DELETE_ARRAY( m_pInputElement[0].SemanticName );
   SAFE_DELETE_ARRAY( m_pInputElement[1].SemanticName );
}

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

// 作成処理
HRESULT CPolygon2D::Create( ID3D11Device* pD3DDevice )
{
   HRESULT hr = E_FAIL;

   Invalidate();

   // 射影座標系上での頂点座標を設定する
   VERTEX v[] = {
         D3DXVECTOR3(  1,  1, 0 ), D3DXVECTOR2( 1, 0 ),
         D3DXVECTOR3( -1,  1, 0 ), D3DXVECTOR2( 0, 0 ),
         D3DXVECTOR3(  1, -1, 0 ), D3DXVECTOR2( 1, 1 ),
         D3DXVECTOR3( -1, -1, 0 ), D3DXVECTOR2( 0, 1 )
   };

   D3D11_BUFFER_DESC BufferDesc;

   // 頂点バッファー リソース
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( v );               // バッファサイズ
   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*)v;
   resource.SysMemPitch = 0;
   resource.SysMemSlicePitch = 0;
   // バッファを作成する
   hr = pD3DDevice->CreateBuffer( &BufferDesc, &resource, &m_pVertexBuffer );
   if( FAILED( hr ) ) goto EXIT;

   size_t size = 9;
   m_pInputElement[0].SemanticName = NEW char[size];
   _mbscpy_s( (unsigned char*)m_pInputElement[0].SemanticName, size, (unsigned char*)"POSITION" );
   m_pInputElement[0].SemanticIndex = 0;
   m_pInputElement[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
   m_pInputElement[0].InputSlot = 0;
   m_pInputElement[0].AlignedByteOffset = 0;
   m_pInputElement[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
   m_pInputElement[0].InstanceDataStepRate = 0;

   size = 9;
   m_pInputElement[1].SemanticName = NEW char[size];
   _mbscpy_s( (unsigned char*)m_pInputElement[1].SemanticName, size, (unsigned char*)"TEXCOORD" );
   m_pInputElement[1].SemanticIndex = 0;
   m_pInputElement[1].Format = DXGI_FORMAT_R32G32_FLOAT;
   m_pInputElement[1].InputSlot = 0;
   m_pInputElement[1].AlignedByteOffset = 12;
   m_pInputElement[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
   m_pInputElement[1].InstanceDataStepRate = 0;

   hr = S_OK;

EXIT:
   return hr;
}

// 頂点エレメントを取得
void CPolygon2D::GetInputElement( D3D11_INPUT_ELEMENT_DESC** ppInputElement, UINT* pInputElementCount )
{
   *ppInputElement = &m_pInputElement[0];
   *pInputElementCount = _countof( m_pInputElement );
}

// 描画
void CPolygon2D::Render( ID3D11DeviceContext* pD3DDeviceContext ) const
{
   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

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

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

2Dポリゴンクラスです。 2Dポリゴンの頂点座標は、頂点シェーダー内で行列変換しないため、あらかじめ射影座標系上で、スクリーン全体を覆う座標に設定しておきます。 もともとこのクラス内でレンダーターゲットサーフェスを保持してましたが、逆に使いにくくなってたのではずしました。 現在は2Dポリゴンのみ管理します。

---ShaderUser.h---  ↑


#ifndef SHADERUSER_H
#define SHADERUSER_H

class SHADERUSER
{
private:
   static const int PASS_COUNT = 5;

   enum SHADER_TYPE
   {
      VERTEXSHADER = 0,
      GEOMETRYSHADER = 1,
      PIXELSHADER = 2,
   };

   typedef struct _SHADER
   {
      // シェーダーオブジェクトのポインタ
      void* Shader;
      ID3D10Blob* Blob;
      // エントリーポイント
      CHAR FunctionName[50];
      // シェーダーバージョン
      CHAR Profile[10];
   }SHADER;

   typedef struct _PASS
   {
      CHAR PassName[5];

      // 頂点シェーダー
      SHADER VertexShader;
      // 入力レイアウト
      ID3D11InputLayout* Layout;
      // ジオメトリシェーダー
      SHADER GeometryShader;
      // ピクセルシェーダー
      SHADER PixelShader;
   }PASS;

   PASS PassArray[PASS_COUNT];
   
   UINT PassMaxCount;

   void SetProfile( IN CHAR* pSMType, IN CHAR* pStrLine, OUT CHAR* pProfile );
   void SetFunctionName( IN CHAR* pStrLine, OUT CHAR* pEntryPoint );
   HRESULT ShaderCompileFromFile( IN ID3D11Device* pD3DDevice, SHADER_TYPE pShaderType, IN TCHAR pSrcFile[], IN OUT SHADER* pShader );
   HRESULT SetShader( IN ID3D11Device* pD3DDevice, IN TCHAR* pSrcFile, IN CHAR* pStrLine, SHADER_TYPE pShaderType, OUT SHADER* pShader );

protected:
   SHADERUSER();
   ~SHADERUSER();
   HRESULT Init( ID3D11Device* pD3DDevice, TCHAR pSrcFile[] );
   HRESULT CreateLayout( ID3D11Device* pD3DDevice, UINT Pass, D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, UINT NumElements );
   HRESULT SetPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass );
   inline UINT GetMaxPath(){ return PassMaxCount; };
};

#endif

---ShaderUser.cpp---  ↑

#include "DX11User.h"
#include "SHADERUSER.h"

SHADERUSER::SHADERUSER()
{
   for( int i=0; i<PASS_COUNT; i++ )
   {
      PassArray[i].PassName[0] = NULL;

      PassArray[i].VertexShader.Shader = NULL;
      PassArray[i].VertexShader.Blob = NULL;
      PassArray[i].VertexShader.FunctionName[0] = NULL;
      PassArray[i].VertexShader.Profile[0] = NULL;
      PassArray[i].Layout = NULL;

      PassArray[i].GeometryShader.Shader = NULL;
      PassArray[i].GeometryShader.Blob = NULL;
      PassArray[i].GeometryShader.FunctionName[0] = NULL;
      PassArray[i].GeometryShader.Profile[0] = NULL;

      PassArray[i].PixelShader.Shader = NULL;
      PassArray[i].PixelShader.Blob = NULL;
      PassArray[i].PixelShader.FunctionName[0] = NULL;
      PassArray[i].PixelShader.Profile[0] = NULL;
   }
   PassMaxCount = 0;
}

SHADERUSER::~SHADERUSER()
{
   for( int i=0; i<PASS_COUNT; i++ )
   {
      if( PassArray[i].VertexShader.Shader )
      {
         SAFE_RELEASE( PassArray[i].VertexShader.Blob );
         ID3D11VertexShader* pShader = (ID3D11VertexShader*)PassArray[i].VertexShader.Shader;
         SAFE_RELEASE( pShader );
      }
      SAFE_RELEASE( PassArray[i].Layout );

      if( PassArray[i].GeometryShader.Shader )
      {
         SAFE_RELEASE( PassArray[i].GeometryShader.Blob );
         ID3D11GeometryShader* pShader = (ID3D11GeometryShader*)PassArray[i].GeometryShader.Shader;
         SAFE_RELEASE( pShader );
      }

      if( PassArray[i].PixelShader.Shader )
      {
         SAFE_RELEASE( PassArray[i].PixelShader.Blob );
         ID3D11PixelShader* pShader = (ID3D11PixelShader*)PassArray[i].PixelShader.Shader;
         SAFE_RELEASE( pShader );
      }

   }
}

void SHADERUSER::SetProfile( IN CHAR* pSMType, IN CHAR* pStrLine, OUT CHAR* pProfile )
{
   CHAR* str = strstr( pStrLine, pSMType );
   if( str != NULL )
   {
      CHAR cstr[100];
      strcpy( cstr, str );
      cstr[6] = NULL;
      strcpy( pProfile, cstr );
   }
}

void SHADERUSER::SetFunctionName( IN CHAR* pStrLine, OUT CHAR* pFunctionName )
{
   CHAR* str = strstr( pStrLine, "," );
   if( str != NULL )
   {
      int index = str - pStrLine;

      CHAR cstr[100];
      strcpy( cstr, &pStrLine[index+2] );

      CHAR* str2 = strstr( cstr, "()" );
      if( str2 != NULL )
      {
         int index = str2 - cstr;

         cstr[index] = NULL;

         strcpy( pFunctionName, cstr );
      }
   }
}

HRESULT SHADERUSER::ShaderCompileFromFile( IN ID3D11Device* pD3DDevice, SHADER_TYPE pShaderType, IN TCHAR pSrcFile[], IN OUT SHADER* pShader )
{
   HRESULT hr = E_FAIL;

   // 行列を列優先で設定し、古い形式の記述を許可しないようにする
   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, pShader->FunctionName, pShader->Profile, Flag1, 0, NULL, &pShader->Blob, NULL, NULL );
   if( FAILED( hr ) ) goto EXIT;

   // コンパイル済みシェーダーから、シェーダー オブジェクトを作成する
   switch( pShaderType )
   {
   case VERTEXSHADER:
      {
         ID3D11VertexShader* pVertexShader = NULL;
         hr = pD3DDevice->CreateVertexShader( pShader->Blob->GetBufferPointer(), pShader->Blob->GetBufferSize(), NULL, &pVertexShader );
         if( FAILED( hr ) ) goto EXIT;
         pShader->Shader = pVertexShader;
      }
      break;

   case GEOMETRYSHADER:
      {
         ID3D11GeometryShader* pGeometryShader = NULL;
         hr = pD3DDevice->CreateGeometryShader( pShader->Blob->GetBufferPointer(), pShader->Blob->GetBufferSize(), NULL, &pGeometryShader );
         if( FAILED( hr ) ) goto EXIT;
         pShader->Shader = pGeometryShader;
      }
      break;

   case PIXELSHADER:
      {
         ID3D11PixelShader* pPixelShader = NULL;
         hr = pD3DDevice->CreatePixelShader( pShader->Blob->GetBufferPointer(), pShader->Blob->GetBufferSize(), NULL, &pPixelShader );
         if( FAILED( hr ) ) goto EXIT;
         pShader->Shader = pPixelShader;
      }
      break;
   }

   hr = S_OK;
EXIT:
   return hr;
}

HRESULT SHADERUSER::SetShader( IN ID3D11Device* pD3DDevice, IN TCHAR* pSrcFile, IN CHAR* pStrLine, SHADER_TYPE pShaderType, OUT SHADER* pShader )
{
   HRESULT hr = E_FAIL;

   CHAR type[100];
   CHAR profile[3];

   switch( pShaderType )
   {
   case VERTEXSHADER:
      strcpy( type, "SetVertexShader" );
      strcpy( profile, "vs" );
      break;
   case GEOMETRYSHADER:
      strcpy( type, "SetGeometryShader" );
      strcpy( profile, "gs" );
      break;
   case PIXELSHADER:
      strcpy( type, "SetPixelShader" );
      strcpy( profile, "ps" );
      break;
   }

   if( strstr( pStrLine, type ) != NULL )
   {
      hr = true;

      if( strstr( pStrLine, "NULL" ) == NULL )
      {
         SetProfile( profile, pStrLine, pShader->Profile );
         SetFunctionName( pStrLine, pShader->FunctionName );

         hr = ShaderCompileFromFile( pD3DDevice, pShaderType, pSrcFile, pShader );
         if( FAILED( hr ) ) goto EXIT;
      }

      else
      {
         pShader->Shader = NULL;
         pShader->FunctionName[0] = NULL;
         pShader->Profile[0] = NULL;
      }

      hr = S_OK;
   }

   hr = S_FALSE;

EXIT:

   return hr;
}

HRESULT SHADERUSER::Init( ID3D11Device* pD3DDevice, TCHAR pSrcFile[] )
{
   HRESULT hr = E_FAIL;

   CHAR line[512];
   CHAR filePath[512];

   // Unicode 文字コードを第一引数で指定した文字コードに変換する
   WideCharToMultiByte( CP_ACP, 0, pSrcFile, -1, filePath, (int)((wcslen(pSrcFile)+1) * 2), NULL, NULL );

   // HLSLファイルが存在するか
   FILE* f = NULL;
   f = fopen( filePath, "r" );
   if( f == NULL )
      goto EXIT;

   while( fgets( line, _countof( line ), f ) != NULL)
   {
      // エントリポイントの定義の検索
      if( strstr( line, "technique11" ) != NULL )
      {
         // passのループ
         while( fgets( line, _countof( line ), f ) != NULL)
         {
            CHAR* str = NULL;
            str = strstr( line, "pass" );
            if( str != NULL )
            {
               strcpy( PassArray[PassMaxCount].PassName, &str[5] );

               // エントリポイント、バージョン、シェーダーのコンパイル
               while( fgets( line, _countof( line ), f ) != NULL)
               {
                  if( ( hr = SetShader( pD3DDevice, pSrcFile, line, VERTEXSHADER, &PassArray[PassMaxCount].VertexShader ) ) != S_FALSE )
                  {
                     if( FAILED( hr ) ) goto EXIT;
                     break;
                  }
                  else if( ( hr = SetShader( pD3DDevice, pSrcFile, line, GEOMETRYSHADER, &PassArray[PassMaxCount].GeometryShader ) ) != S_FALSE )
                  {
                     if( FAILED( hr ) ) goto EXIT;
                     break;
                  }
                  else if( ( hr = SetShader( pD3DDevice, pSrcFile, line, PIXELSHADER, &PassArray[PassMaxCount].PixelShader ) ) != S_FALSE )
                  {
                     if( FAILED( hr ) ) goto EXIT;
                     break;
                  }
                  else
                  {
                     if( strstr( line, "}" ) != NULL )
                        break;
                  }
               }

               PassMaxCount++;
            }
         }
      }
   }

   hr = S_OK;

EXIT:
   return hr;
}

HRESULT SHADERUSER::CreateLayout( ID3D11Device* pD3DDevice, UINT Pass, D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, UINT NumElements )
{
   HRESULT hr = E_FAIL;

   if( Pass >= PassMaxCount ) goto EXIT;

   // シェーダーで使用される入力バッファーを記述するための入力レイアウトオブジェクトを作成する。
   hr = pD3DDevice->CreateInputLayout( pInputElementDescs, NumElements, PassArray[Pass].VertexShader.Blob->GetBufferPointer(), PassArray[Pass].VertexShader.Blob->GetBufferSize(), &PassArray[Pass].Layout );
   if( FAILED( hr ) ) goto EXIT;

   hr = S_OK;
EXIT:
   return hr;
}

HRESULT SHADERUSER::SetPass( ID3D11DeviceContext* pD3DDeviceContext, UINT Pass )
{
   HRESULT hr = E_FAIL;

   if( Pass >= PassMaxCount ) goto EXIT;

   pD3DDeviceContext->IASetInputLayout( PassArray[Pass].Layout );

   pD3DDeviceContext->VSSetShader( (ID3D11VertexShader*)PassArray[Pass].VertexShader.Shader, NULL, NULL );
   pD3DDeviceContext->GSSetShader( (ID3D11GeometryShader*)PassArray[Pass].GeometryShader.Shader, NULL, NULL );
   pD3DDeviceContext->PSSetShader( (ID3D11PixelShader*)PassArray[Pass].PixelShader.Shader, NULL, NULL );

   hr = S_OK;
EXIT:
   return hr;
}

hlslファイルからシェーダーを読み込む機能を実装したクラスです。 こんなの作成するくらいならエフェクト使用したほうがいいじゃんと思われそうですが、ソースでの提供がどうにも気に入らないので自作してみました。 ですが結局中途半端になりました(笑)。 このクラスを使用する場合は、technique11 キーワード内がフリーフォーマットで記述できないので注意を。

あと初期化時に頂点シェーダーへの入力レイアウトを設定する必要があります。 hlslソースを解析して自動入力させることも可能かもしれませんが、めんどうなのでやめました。

---HalfLambert.hlsl---  ↑


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

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

// サンプラーステート
SamplerState  g_Sampler;

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

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

// 頂点シェーダー
VS_OUT HalfLambert_VS_Main( VS_IN In )
{
   VS_OUT Out;
   Out.pos = mul( float4( In.pos, 1.0f ), g_matWVP );
   Out.normal = In.normal;
   Out.texel = In.texel;

   return Out;
}

typedef VS_OUT PS_IN;

// ピクセルシェーダ
float4 HalfLambert_PS_Main( PS_IN In ) : SV_TARGET
{
   // ハーフランバート
   float lambert = dot( -g_vecLight.xyz, normalize( In.normal ) );
   lambert = lambert * 0.5f + 0.5f;
   lambert *= lambert;

   return g_Tex.Sample( g_Sampler, In.texel ) * lambert;
}

// エントリーポイントとバージョンを指定する
technique11 TShader
{
   pass P0
   {
      SetVertexShader( CompileShader( vs_4_0, HalfLambert_VS_Main() ) );
      SetGeometryShader( NULL );
      SetHullShader( NULL );
      SetDomainShader( NULL );
      SetPixelShader(  CompileShader( ps_4_0, HalfLambert_PS_Main() ) );
      SetComputeShader( NULL );
   }
}

ハーフランバートシェーダーです。technique11を追加しました。 SHADERUSERクラスは、technique11の内容から各シェーダーのエントリーポイントとバージョンを決定します。

---HalfLambert.h---  ↑


#ifndef HALFLAMBERT_H
#define HALFLAMBERT_H

#include "ShaderUser.h"

class HALFLAMBERT : public SHADERUSER
{
private:
   // 定数バッファ定義( float * 4 バイト数の倍数のサイズである必要がある )
   typedef struct _CBUFFER0
   {
      // ワールド × ビュー × 射影 行列
      D3DXMATRIX  matWVP;
      // 平行光源の方向ベクトル
      D3DXVECTOR4 vecLight;
   }CBUFFER0;

   // 定数バッファ
   ID3D11Buffer* m_pConstantBuffers;
   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;

public:
   HALFLAMBERT();
   ~HALFLAMBERT();
   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice, TCHAR pSrcFile[] );
   // 定数バッファを設定する
   HRESULT SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext,
                               D3DXMATRIX* pMatWVP,
                               D3DXVECTOR4* pLightDir );
   // 描画開始処理
   void BeginPass( ID3D11DeviceContext* pD3DDeviceContext );
   // 描画終了処理
   void EndPass( ID3D11DeviceContext* pD3DDeviceContext );
};

#endif

---HalfLambert.cpp---  ↑

#include "DX11User.h"
#include "D3D11User.h"
#include "HalfLambert.h"

HALFLAMBERT::HALFLAMBERT()
{
   m_pConstantBuffers = NULL;
   m_pSamplerState = NULL;
}

HALFLAMBERT::~HALFLAMBERT()
{
   SAFE_RELEASE( m_pConstantBuffers );
   SAFE_RELEASE( m_pSamplerState );
}

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

   // シェーダーの初期化
   hr = SHADERUSER::Init( pD3DDevice, pSrcFile );
   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 = SHADERUSER::CreateLayout( pD3DDevice, 0, layout, _countof( layout ) );
   if( FAILED( hr ) ) goto EXIT;

   // 定数バッファを作成
   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 );
   if( FAILED( hr ) ) goto EXIT;

   // サンプラーの作成
   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;         // サンプリング時に使用するフィルタ。ここでは異方性フィルターを使用する。
   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 = 16;                        // サンプリングに異方性補間を使用している場合の限界値。有効な値は 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 HALFLAMBERT::SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext,
                                         D3DXMATRIX* pMatWVP,
                                         D3DXVECTOR4* pLightDir )
{
   HRESULT hr = E_FAIL;
   D3D11_MAPPED_SUBRESOURCE mappedResource;

   CBUFFER0* cbuffer;

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

   if( pMatWVP )  ::CopyMemory( &cbuffer->matWVP, pMatWVP, sizeof( D3DXMATRIX ) );
   if( pLightDir )::CopyMemory( &cbuffer->vecLight, pLightDir, sizeof( D3DXVECTOR4 ) );

   pD3DDeviceContext->Unmap( m_pConstantBuffers, 0 );

   hr = S_OK;
EXIT:
   return hr;
}

// 描画
void HALFLAMBERT::BeginPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   SHADERUSER::SetPass( pD3DDeviceContext, 0 );

   // 頂点シェーダーに定数バッファを設定する
   pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers );
   // ピクセルシェーダーに定数バッファを設定する
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers );
   // ピクセルシェーダーにサンプラステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

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

void HALFLAMBERT::EndPass( ID3D11DeviceContext* pD3DDeviceContext )
{
   ID3D11Buffer* NullBuffer[] = { NULL };
   pD3DDeviceContext->VSSetConstantBuffers( 0, 1, NullBuffer );
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, NullBuffer );

   ID3D11SamplerState* NullSampler[] = { NULL };
   pD3DDeviceContext->PSSetSamplers( 0, 1, NullSampler );
}

ハーフランバートクラスです。

---GaussianFilter.hlsl---  ↑


// 定数バッファ0
cbuffer cbBuffer0 : register( b0 )
{
   float  g_Weight0 : packoffset( c0.x );    // 重み
   float  g_Weight1 : packoffset( c0.y );    // 重み
   float  g_Weight2 : packoffset( c0.z );    // 重み
   float  g_Weight3 : packoffset( c0.w );    // 重み
   float  g_Weight4 : packoffset( c1.x );    // 重み
   float  g_Weight5 : packoffset( c1.y );    // 重み
   float  g_Weight6 : packoffset( c1.z );    // 重み
   float  g_Weight7 : packoffset( c1.w );    // 重み
   float  g_Width   : packoffset( c2.x );    // サーフェスの横サイズ
   float  g_Height  : packoffset( c2.y );    // サーフェスの縦サイズ
   float  g_OffsetX : packoffset( c2.z );
   float  g_OffsetY : packoffset( c2.w );
};

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

// サンプラーステート
SamplerState  g_Sampler;

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

// 頂点シェーダーの出力パラメータ
struct VS_OUT
{
   float4 pos    : SV_POSITION;
   float2 texel0 : TEXCOORD0;   // テクセル
   float2 texel1 : TEXCOORD1;   // テクセル
   float2 texel2 : TEXCOORD2;   // テクセル
   float2 texel3 : TEXCOORD3;   // テクセル
   float2 texel4 : TEXCOORD4;   // テクセル
   float2 texel5 : TEXCOORD5;   // テクセル
   float2 texel6 : TEXCOORD6;   // テクセル
   float2 texel7 : TEXCOORD7;   // テクセル
};

// X方向にブラーを適応する頂点シェーダー
VS_OUT GaussianFilter_VS0_Main( VS_IN In )
{
   VS_OUT Out;

   Out.pos = float4( In.pos, 1.0f );
   Out.texel0 = In.texel + float2( -1.0f  / g_Width, 0.0f );
   Out.texel1 = In.texel + float2( -3.0f  / g_Width, 0.0f );
   Out.texel2 = In.texel + float2( -5.0f  / g_Width, 0.0f );
   Out.texel3 = In.texel + float2( -7.0f  / g_Width, 0.0f );
   Out.texel4 = In.texel + float2( -9.0f  / g_Width, 0.0f );
   Out.texel5 = In.texel + float2( -11.0f / g_Width, 0.0f );
   Out.texel6 = In.texel + float2( -13.0f / g_Width, 0.0f );
   Out.texel7 = In.texel + float2( -15.0f / g_Width, 0.0f );
   return Out;
}

// ピクセルシェーダーの入力パラメータ
typedef VS_OUT PS_IN;

// ピクセルシェーダ
float4 GaussianFilter_PS0_Main( PS_IN In ) : SV_TARGET
{
   float4 Out = 0.0f;
   
   Out += ( g_Tex.Sample( g_Sampler, In.texel0 ) + g_Tex.Sample( g_Sampler, float2( In.texel7.x + g_OffsetX, In.texel7.y ) ) ) * g_Weight0;
   Out += ( g_Tex.Sample( g_Sampler, In.texel1 ) + g_Tex.Sample( g_Sampler, float2( In.texel6.x + g_OffsetX, In.texel6.y ) ) ) * g_Weight1;
   Out += ( g_Tex.Sample( g_Sampler, In.texel2 ) + g_Tex.Sample( g_Sampler, float2( In.texel5.x + g_OffsetX, In.texel5.y ) ) ) * g_Weight2;
   Out += ( g_Tex.Sample( g_Sampler, In.texel3 ) + g_Tex.Sample( g_Sampler, float2( In.texel4.x + g_OffsetX, In.texel4.y ) ) ) * g_Weight3;
   Out += ( g_Tex.Sample( g_Sampler, In.texel4 ) + g_Tex.Sample( g_Sampler, float2( In.texel3.x + g_OffsetX, In.texel3.y ) ) ) * g_Weight4;
   Out += ( g_Tex.Sample( g_Sampler, In.texel5 ) + g_Tex.Sample( g_Sampler, float2( In.texel2.x + g_OffsetX, In.texel2.y ) ) ) * g_Weight5;
   Out += ( g_Tex.Sample( g_Sampler, In.texel6 ) + g_Tex.Sample( g_Sampler, float2( In.texel1.x + g_OffsetX, In.texel1.y ) ) ) * g_Weight6;
   Out += ( g_Tex.Sample( g_Sampler, In.texel7 ) + g_Tex.Sample( g_Sampler, float2( In.texel0.x + g_OffsetX, In.texel0.y ) ) ) * g_Weight7;
   return Out;
}

// Y方向にブラーを適応する頂点シェーダー
VS_OUT GaussianFilter_VS1_Main( VS_IN In )
{
   VS_OUT Out;

   Out.pos = float4( In.pos, 1.0f );
   Out.texel0 = In.texel + float2( 0.0f, -1.0f  / g_Height );
   Out.texel1 = In.texel + float2( 0.0f, -3.0f  / g_Height );
   Out.texel2 = In.texel + float2( 0.0f, -5.0f  / g_Height );
   Out.texel3 = In.texel + float2( 0.0f, -7.0f  / g_Height );
   Out.texel4 = In.texel + float2( 0.0f, -9.0f  / g_Height );
   Out.texel5 = In.texel + float2( 0.0f, -11.0f / g_Height );
   Out.texel6 = In.texel + float2( 0.0f, -13.0f / g_Height );
   Out.texel7 = In.texel + float2( 0.0f, -15.0f / g_Height );
   return Out;
}

// Y方向にブラーを適応するピクセルシェーダ
float4 GaussianFilter_PS1_Main( PS_IN In ) : SV_TARGET
{
   float4 Out = 0.0f;

   Out += ( g_Tex.Sample( g_Sampler, In.texel0 ) + g_Tex.Sample( g_Sampler, float2( In.texel7.x, In.texel7.y + g_OffsetY ) ) ) * g_Weight0;
   Out += ( g_Tex.Sample( g_Sampler, In.texel1 ) + g_Tex.Sample( g_Sampler, float2( In.texel6.x, In.texel6.y + g_OffsetY ) ) ) * g_Weight1;
   Out += ( g_Tex.Sample( g_Sampler, In.texel2 ) + g_Tex.Sample( g_Sampler, float2( In.texel5.x, In.texel5.y + g_OffsetY ) ) ) * g_Weight2;
   Out += ( g_Tex.Sample( g_Sampler, In.texel3 ) + g_Tex.Sample( g_Sampler, float2( In.texel4.x, In.texel4.y + g_OffsetY ) ) ) * g_Weight3;
   Out += ( g_Tex.Sample( g_Sampler, In.texel4 ) + g_Tex.Sample( g_Sampler, float2( In.texel3.x, In.texel3.y + g_OffsetY ) ) ) * g_Weight4;
   Out += ( g_Tex.Sample( g_Sampler, In.texel5 ) + g_Tex.Sample( g_Sampler, float2( In.texel2.x, In.texel2.y + g_OffsetY ) ) ) * g_Weight5;
   Out += ( g_Tex.Sample( g_Sampler, In.texel6 ) + g_Tex.Sample( g_Sampler, float2( In.texel1.x, In.texel1.y + g_OffsetY ) ) ) * g_Weight6;
   Out += ( g_Tex.Sample( g_Sampler, In.texel7 ) + g_Tex.Sample( g_Sampler, float2( In.texel0.x, In.texel0.y + g_OffsetY ) ) ) * g_Weight7;
   return Out;
}

// エントリーポイントとバージョンを指定する
technique11 TShader
{
   pass P0
   {
      SetVertexShader( CompileShader( vs_4_0, GaussianFilter_VS0_Main() ) );
      SetGeometryShader( NULL );
      SetHullShader( NULL );
      SetDomainShader( NULL );
      SetPixelShader(  CompileShader( ps_4_0, GaussianFilter_PS0_Main() ) );
      SetComputeShader( NULL );
   }

   pass P1
   {
      SetVertexShader( CompileShader( vs_4_0, GaussianFilter_VS1_Main() ) );
      SetGeometryShader( NULL );
      SetHullShader( NULL );
      SetDomainShader( NULL );
      SetPixelShader(  CompileShader( ps_4_0, GaussianFilter_PS1_Main() ) );
      SetComputeShader( NULL );
   }
}

ガウスフィルターのシェーダーソースです。

---GaussianFilter.h---  ↑


#ifndef GAUSSIANFILTER_H
#define GAUSSIANFILTER_H

#include "ShaderUser.h"
#include "Polygon2DUser.h"

class GAUSSIANFILTER : public SHADERUSER
{
private:
   // ブラーフィルターの定数バッファ定義
   typedef struct _CBUFFER
   {
      float Weight[8];
      float Width;
      float Height;
      D3DXVECTOR2 Offset;
   }CBUFFER;

   // 定数バッファ
   ID3D11Buffer* m_pConstantBuffers;
   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;

   // レンダーターゲット用のリソース
   ID3D11RenderTargetView* m_pRTV; // レンダー ターゲット ビュー

   // 縮小バッファの解像度
   UINT m_Width;
   UINT m_Height;

   CPolygon2D m_Polygon2D;

public:
   GAUSSIANFILTER();
   ~GAUSSIANFILTER();
   // 初期化
   HRESULT Init( ID3D11Device* pD3DDevice, TCHAR pSrcFile[], UINT Width, UINT Height );
   // 定数バッファを設定する
   HRESULT SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext,
                               float Dispersion );
   // 描画
   HRESULT Render( ID3D11Device* pD3DDevice, 
                   ID3D11DeviceContext* pD3DDeviceContext,
                   IN  ID3D11RenderTargetView* pInRTView,        // ガウスフィルターを適応させるレンダーターゲットビュー
                   OUT ID3D11RenderTargetView* pOutRTView );     // ガウスフィルターを適応させたレンダーターゲットビュー
};

#endif

---GaussianFilter.cpp---  ↑

#include "DX11User.h"
#include "D3D11User.h"
#include "GaussianFilter.h"

GAUSSIANFILTER::GAUSSIANFILTER()
{
   m_pConstantBuffers = NULL;
   m_pSamplerState = NULL;
   m_pRTV = NULL;
   m_Width = 0;
   m_Height = 0;
}

GAUSSIANFILTER::~GAUSSIANFILTER()
{
   SAFE_RELEASE( m_pConstantBuffers );
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pRTV );
}

// 初期化
HRESULT GAUSSIANFILTER::Init( ID3D11Device* pD3DDevice, TCHAR pSrcFile[], UINT Width, UINT Height )
{
   HRESULT hr = E_FAIL;

   ID3D11Texture2D* pTex2D = NULL;

   m_Width = Width;
   m_Height = Height;

   // シェーダーの初期化
   hr = SHADERUSER::Init( pD3DDevice, pSrcFile );
   if( FAILED( hr ) ) goto EXIT;

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

   // 入力レイアウトを取得する
   D3D11_INPUT_ELEMENT_DESC* pInputElement;
   UINT InputElementCount;
   m_Polygon2D.GetInputElement( &pInputElement, &InputElementCount );

   // 入力レイアウトを作成する。
   hr = SHADERUSER::CreateLayout( pD3DDevice, 0, pInputElement, InputElementCount );
   if( FAILED( hr ) ) goto EXIT;

   hr = SHADERUSER::CreateLayout( pD3DDevice, 1, pInputElement, InputElementCount );
   if( FAILED( hr ) ) goto EXIT;

   // 定数バッファを作成
   D3D11_BUFFER_DESC BufferDesc;
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CBUFFER );         // バッファサイズ
   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_CLAMP;
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
   samplerDesc.MipLODBias = 0;
   samplerDesc.MaxAnisotropy = 1;
   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;

   // レンダーターゲットビューを作成
   {
      D3D11_TEXTURE2D_DESC Tex2DDesc;
      D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;

      ::ZeroMemory( &Tex2DDesc, sizeof( D3D11_TEXTURE2D_DESC ) );
      Tex2DDesc.ArraySize        = 1;
      Tex2DDesc.BindFlags        = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
      Tex2DDesc.Usage            = D3D11_USAGE_DEFAULT;
      Tex2DDesc.Format           = DXGI_FORMAT_R8G8B8A8_UNORM;
      Tex2DDesc.Width            = m_Width;
      Tex2DDesc.Height           = m_Height;
      Tex2DDesc.MipLevels        = 1;
      Tex2DDesc.SampleDesc.Count = 1;

      ::ZeroMemory( &RTVDesc, sizeof( D3D11_RENDER_TARGET_VIEW_DESC ) );
      RTVDesc.Format = Tex2DDesc.Format;
      RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
      RTVDesc.Texture2D.MipSlice = 0;

      hr = pD3DDevice->CreateTexture2D( &Tex2DDesc, NULL, &pTex2D );
      if( FAILED( hr ) ) goto EXIT;

      hr = pD3DDevice->CreateRenderTargetView( pTex2D, &RTVDesc, &m_pRTV );
      if( FAILED( hr ) ) goto EXIT;

      SAFE_RELEASE( pTex2D );
   }

   hr = S_OK;

EXIT:
   SAFE_RELEASE( pTex2D );
   return hr;
}

// 定数バッファを設定する
HRESULT GAUSSIANFILTER::SetConstantBuffers( ID3D11DeviceContext* pD3DDeviceContext,
                                            float Dispersion )
{
   HRESULT hr = E_FAIL;
   D3D11_MAPPED_SUBRESOURCE mappedResource;

   const UINT Division = 8;

   CBUFFER* cbuffer;

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

   float total = 0.0f;
   float weight[Division];
   
   // ガウス関数による重みの計算
   for( int i=0; i<Division; i++ )
   {
      float pos = (float)i * 2.0f;
      weight[i] = expf( - pos * pos * Dispersion );
      total += weight[i];
   }

   // 重みの規格化
   for( int i=0; i<Division; i++ )
      weight[i] = weight[i] / total * 0.5f;

   ::CopyMemory( &cbuffer->Weight, weight, sizeof( float ) * Division );

   cbuffer->Width    = (float)m_Width;
   cbuffer->Height   = (float)m_Height;
   cbuffer->Offset.x = 16.0f / (float)m_Width;
   cbuffer->Offset.y = 16.0f / (float)m_Height;

   pD3DDeviceContext->Unmap( m_pConstantBuffers, 0 );

   hr = S_OK;
EXIT:
   return hr;
}

HRESULT GAUSSIANFILTER::Render( ID3D11Device* pD3DDevice, ID3D11DeviceContext* pD3DDeviceContext, IN ID3D11RenderTargetView* pInRTView, OUT ID3D11RenderTargetView* pOutRTView )
{
   HRESULT hr = E_FAIL;

   ID3D11Resource* pResource = NULL;
   ID3D11ShaderResourceView* pSRV = NULL;
   ID3D11Texture2D* pTexture = NULL;
   D3D11_TEXTURE2D_DESC TexDesc;

   // 現在のレンダーターゲットサーフェスを退避

   ID3D11RenderTargetView* pOldRTView = NULL;
   ID3D11DepthStencilView* pOldDSView = NULL;
   pD3DDeviceContext->OMGetRenderTargets( 1, &pOldRTView, &pOldDSView );

   // ビューポートを退避

   UINT pNumVierports = 1;
   D3D11_VIEWPORT OldViewport;
   pD3DDeviceContext->RSGetViewports( &pNumVierports, &OldViewport );
   D3D11_VIEWPORT NewViewport;
   ::CopyMemory( &NewViewport, &OldViewport, sizeof( D3D11_VIEWPORT ) );
   NewViewport.Width = (FLOAT)m_Width;
   NewViewport.Height = (FLOAT)m_Height;
   pD3DDeviceContext->RSSetViewports( 1, &NewViewport );

   // pInRTView の解像度が初期化時に指定した解像度と一致しているかチェック

   pInRTView->GetResource( &pResource );
   pTexture = (ID3D11Texture2D*)pResource;
   pTexture->GetDesc( &TexDesc );
   SAFE_RELEASE( pResource );
   // 解像度が一致していないときはエラー
   if( m_Width != TexDesc.Width ) goto EXIT;
   if( m_Height != TexDesc.Height ) goto EXIT;

   // 頂点シェーダーに定数バッファを設定する
   pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_pConstantBuffers );
   // ピクセルシェーダーに定数バッファを設定する
   pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_pConstantBuffers );
   // ピクセルシェーダーにサンプラステートを設定する。
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );
   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

   // Pass0を処理
   {
      // レンダーターゲットサーフェスを切り替える
      pD3DDeviceContext->OMSetRenderTargets( 1, &m_pRTV, NULL );

      hr = SHADERUSER::SetPass( pD3DDeviceContext, 0 );
      if( FAILED( hr ) ) goto EXIT;

      // pInRTView からシェーダーリソースビューを取得
      pInRTView->GetResource( &pResource );
      pD3DDevice->CreateShaderResourceView( pResource, NULL, &pSRV );
      SAFE_RELEASE( pResource );

      // シェーダーリソースビュー
      pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRV );
      // 描画
      m_Polygon2D.Render( pD3DDeviceContext );

      SAFE_RELEASE( pSRV );
   }

   // pOutRTView の解像度を取得する

   pOutRTView->GetResource( &pResource );
   pTexture = (ID3D11Texture2D*)pResource;
   pTexture->GetDesc( &TexDesc );
   SAFE_RELEASE( pResource );

   // ビューポートのサイズを変更する

   NewViewport.Width = (FLOAT)TexDesc.Width;
   NewViewport.Height = (FLOAT)TexDesc.Height;
   pD3DDeviceContext->RSSetViewports( 1, &NewViewport );

   // Pass1を処理
   {
      // レンダーターゲットサーフェスを切り替える
      pD3DDeviceContext->OMSetRenderTargets( 1, &pOutRTView, NULL );

      hr = SHADERUSER::SetPass( pD3DDeviceContext, 1 );
      if( FAILED( hr ) ) goto EXIT;

      // m_pRTVからシェーダーリソースビューを取得
      m_pRTV->GetResource( &pResource );
      pD3DDevice->CreateShaderResourceView( pResource, NULL, &pSRV );
      SAFE_RELEASE( pResource );

      // シェーダーリソースビュー
      pD3DDeviceContext->PSSetShaderResources( 0, 1, &pSRV );
      // 描画
      m_Polygon2D.Render( pD3DDeviceContext );

      SAFE_RELEASE( pSRV );
   }

   hr = S_OK;
EXIT:

   // レンダーターゲットを戻す
   pD3DDeviceContext->OMSetRenderTargets( 1, &pOldRTView, pOldDSView );
   // ビューポートを戻す
   pD3DDeviceContext->RSSetViewports( 1, &OldViewport );
   SAFE_RELEASE( pSRV );
   SAFE_RELEASE( pResource );
   SAFE_RELEASE( pOldRTView );
   SAFE_RELEASE( pOldDSView );

   return hr;
}

ガウスフィルターを処理するためのクラスです。

---main.cpp---  ↑


#include "../../USER/DX11User.h"
#include "../../USER/D3D11User.h"
#include "../../USER/HalfLambert.h"
#include "../../USER/GaussianFilter.h"
#include "../../USER/DebugFontUser.h"

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

// アプリケーション名
TCHAR* AppName = _T("DX11_Tutrial11 Gaussian Filter");

// Direct3D関連の自作クラス
D3D11USER* g_pD3D11User = NULL;
// デバッグ専用のテキスト描画する自作クラス
CDebugFont* g_pDebugFontUser = NULL;
// ハーフランバートクラス
HALFLAMBERT* g_pHalfLambert = NULL;
// ガウスフィルタークラス
GAUSSIANFILTER* g_pGaussianFilter = NULL;
// ガウスフィルターの分散率
float g_Dispersion = 0.03f;

// 頂点バッファ
ID3D11Buffer* g_pVertexBuffer = NULL;
// インデックスバッファ
ID3D11Buffer* g_pIndexBuffer = NULL;
// シェーダーリソースビュー
ID3D11ShaderResourceView* g_pSRView = NULL;

// レンダーターゲット用のリソース
ID3D11RenderTargetView* g_pRTV = NULL; // レンダー ターゲット ビュー
ID3D11DepthStencilView* g_pDSV = NULL; // 深度ステンシルビュー

// 頂点定義
typedef struct _VERTEX
{
   // 頂点座標
   D3DXVECTOR3 pos;
   // 法線ベクトル
   D3DXVECTOR3 normal;
   // テクセル
   D3DXVECTOR2 texel;
}VERTEX;

// 頂点数
UINT g_VertexBufferCnt = 0;
// 頂点インデックス数
UINT g_IndexBufferCnt = 0;

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

UINT g_Width = 320;
UINT g_Height = 240;

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

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

// 球メッシュを作成する
HRESULT CreateBall( VERTEX** pVertex, UINT** pIndex, float Radius, UINT Division, UINT* pVertexBufferCnt, UINT* pIndexBufferCnt, D3DXVECTOR2* pTexelScale )
{
   HRESULT hr = E_FAIL;

   if( Radius <= 0 || Division < 2 ) goto EXIT;

   // 頂点数を計算
   *pVertexBufferCnt = 2 +                       // 上部、下部の2頂点
                       ( Division - 1 ) *        // 縦方向の分割
                       ( Division * 2 + 1 );     // 水平方向の分割

   (*pVertex) = new VERTEX[*pVertexBufferCnt];
   if( (*pVertex) == NULL ) goto EXIT;

   UINT Index = 0;

   // 上部の頂点
   (*pVertex)[Index].pos = D3DXVECTOR3( 0.0f, Radius, 0.0f );
   D3DXVec3Normalize( &((*pVertex)[Index].normal), &((*pVertex)[Index].pos) );
   (*pVertex)[Index].texel = D3DXVECTOR2( 0.0f, 0.0f );

   Index++;

   float R = D3DX_PI / (float)( Division );
   float Y;
   float Z;
   // 縦方向の分割ループ
   for( UINT i=1; i<Division; i++ )
   {
      Y = Radius * cosf( R * (float)i );
      Z = Radius * sinf( R * (float)i ); 

      // 水平方向の分割ループ
      for( UINT j=0; j<Division * 2 + 1; j++ )
      {
         if( j != Division * 2 )
         {
            (*pVertex)[Index].pos = D3DXVECTOR3( Z * cosf( R * (float)j ), Y, Z * sinf( R * (float)j ) );
            D3DXVec3Normalize( &((*pVertex)[Index].normal), &((*pVertex)[Index].pos) );
         }
         else
         {
            (*pVertex)[Index].pos = (*pVertex)[Index - Division * 2].pos;
            (*pVertex)[Index].normal = (*pVertex)[Index - Division * 2].normal;
         }

         (*pVertex)[Index].texel = D3DXVECTOR2( (float)j / (float)( Division * 2 ) * pTexelScale->x, (float)i / (float)( Division ) * pTexelScale->y );

         Index++;
      }
   }

   // 下部の頂点
   (*pVertex)[Index].pos = D3DXVECTOR3( 0.0f, -Radius, 0.0f );
   D3DXVec3Normalize( &((*pVertex)[Index].normal), &((*pVertex)[Index].pos) );
   (*pVertex)[Index].texel = D3DXVECTOR2( 0.0f, 1.0f );

   // バグチェック
   if( *pVertexBufferCnt != Index + 1 ) goto EXIT;

   // インデックス数を計算
   *pIndexBufferCnt = 3 * Division * 2 * 2 +                   // 上下部分のポリゴン
                      3 * ( Division - 2 ) * Division * 2 * 2; // 上下以外の部分のポリゴン

   (*pIndex) = new UINT[*pIndexBufferCnt];
   if( (*pIndex) == NULL ) goto EXIT;

   Index = 0;

   // 上部
   for( UINT i=0; i<Division*2; i++ )
   {
      (*pIndex)[Index++] = 0;
      (*pIndex)[Index++] = i + 1;
      (*pIndex)[Index++] = i + 2;
   }

   // 側面
   for( UINT i=0; i<Division-2; i++ )
   {
      for( UINT j=0; j<Division*2; j++ )
      {
         (*pIndex)[Index++] = 1 + i * ( Division * 2 + 1 ) + j;
         (*pIndex)[Index++] = 1 + ( i + 1 ) * ( Division * 2 + 1 ) + j;
         (*pIndex)[Index++] = 1 + ( i + 1 ) * ( Division * 2 + 1 ) + 1 + j;

         (*pIndex)[Index++] = 1 + i * ( Division * 2 + 1 ) + j;
         (*pIndex)[Index++] = 1 + ( i + 1 ) * ( Division * 2 + 1 ) + 1 + j;
         (*pIndex)[Index++] = 1 + i * ( Division * 2 + 1 ) + 1 + j;
      }
   }

   // 下部
   for( UINT i=0; i<Division*2; i++ )
   {
      (*pIndex)[Index++] = 1 + ( Division - 2 ) * ( Division * 2 + 1 ) + i;
      (*pIndex)[Index++] = *pVertexBufferCnt - 1;
      (*pIndex)[Index++] = 1 + ( Division - 2 ) * ( Division * 2 + 1 ) + 1 + i;
   }

   // バグチェック
   if( *pIndexBufferCnt != Index ) goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

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

   D3DX11_IMAGE_LOAD_INFO info;

   // 頂点配列
   VERTEX* v = NULL;
   // 頂点インデックス配列
   UINT*   Index = NULL;

   // ボール作成
   D3DXVECTOR2 texelScale = D3DXVECTOR2( 4.0f, 4.0f );
   hr = CreateBall( &v, &Index, 5.0f, 8, &g_VertexBufferCnt, &g_IndexBufferCnt, &texelScale );
   if( FAILED( hr ) ) goto EXIT;

   // 頂点バッファを作成する
   hr = g_pD3D11User->CreateVertexBuffer( &g_pVertexBuffer, v, sizeof( VERTEX ) * g_VertexBufferCnt, 0 );
   if( FAILED( hr ) ) goto EXIT;

   // インデックスバッファを作成する。
   hr = g_pD3D11User->CreateIndexBuffer( &g_pIndexBuffer, Index, sizeof( UINT ) * g_IndexBufferCnt, 0 );
   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 = 1;
      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( g_pD3D11User->m_D3DDevice, _T("res\\01.bmp"), &info, NULL, &g_pSRView, NULL );
      if( FAILED( hr ) ) goto EXIT;
   }

   // ハーフランバートの初期化
   g_pHalfLambert = new HALFLAMBERT();
   hr = g_pHalfLambert->Init( g_pD3D11User->m_D3DDevice, _T("../../USER/HalfLambert.hlsl") );
   if( FAILED( hr ) ) goto EXIT;

   // ガウスフィルタークラスの初期化
   g_pGaussianFilter = new GAUSSIANFILTER();
   hr = g_pGaussianFilter->Init( g_pD3D11User->m_D3DDevice, _T("../../USER/GaussianFilter.hlsl"), g_Width, g_Height );
   if( FAILED( hr ) ) goto EXIT;

   // レンダーターゲットビューを作成
   {
      ID3D11Texture2D* pTex2D = NULL;
      D3D11_TEXTURE2D_DESC Tex2DDesc;
      D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;

      ::ZeroMemory( &Tex2DDesc, sizeof( D3D11_TEXTURE2D_DESC ) );
      Tex2DDesc.ArraySize        = 1;
      Tex2DDesc.BindFlags        = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
      Tex2DDesc.Usage            = D3D11_USAGE_DEFAULT;
      Tex2DDesc.Format           = DXGI_FORMAT_R8G8B8A8_UNORM;
      Tex2DDesc.Width            = g_Width;
      Tex2DDesc.Height           = g_Height;
      Tex2DDesc.MipLevels        = 1;
      Tex2DDesc.SampleDesc.Count = 1;

      ::ZeroMemory( &RTVDesc, sizeof( D3D11_RENDER_TARGET_VIEW_DESC ) );
      RTVDesc.Format = Tex2DDesc.Format;
      RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
      RTVDesc.Texture2D.MipSlice = 0;

      hr = g_pD3D11User->m_D3DDevice->CreateTexture2D( &Tex2DDesc, NULL, &pTex2D );
      if( FAILED( hr ) ) goto EXIT;

      hr = g_pD3D11User->m_D3DDevice->CreateRenderTargetView( pTex2D, &RTVDesc, &g_pRTV );
      if( FAILED( hr ) ) goto EXIT;

      SAFE_RELEASE( pTex2D );
   }

   // 深度ステンシルビューを作成
   {
      ID3D11Texture2D* pTex2D;
      D3D11_TEXTURE2D_DESC Tex2DDesc;

      ::ZeroMemory( &Tex2DDesc, sizeof( D3D11_TEXTURE2D_DESC ) );
      Tex2DDesc.ArraySize        = 1;
      Tex2DDesc.BindFlags        = D3D11_BIND_DEPTH_STENCIL;
      Tex2DDesc.Usage            = D3D11_USAGE_DEFAULT;
      Tex2DDesc.Format           = DXGI_FORMAT_D32_FLOAT;
      Tex2DDesc.Width            = g_Width;
      Tex2DDesc.Height           = g_Height;
      Tex2DDesc.MipLevels        = 1;
      Tex2DDesc.SampleDesc.Count = 1;

      D3D11_DEPTH_STENCIL_VIEW_DESC DescDS;
      ::ZeroMemory( &DescDS, sizeof(DescDS) );
      DescDS.Format = Tex2DDesc.Format;
      DescDS.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;

      hr = g_pD3D11User->m_D3DDevice->CreateTexture2D( &Tex2DDesc, NULL, &pTex2D );
      if( FAILED( hr ) ) goto EXIT;
      hr = g_pD3D11User->m_D3DDevice->CreateDepthStencilView( pTex2D, &DescDS, &g_pDSV );
      if( FAILED( hr ) ) goto EXIT;

      SAFE_RELEASE( pTex2D );
   }

   hr = S_OK;

EXIT:
   SAFE_DELETE_ARRAY( v );
   SAFE_DELETE_ARRAY( Index );

   return hr;
}

// メモリ開放
void Invalidate()
{
   SAFE_DELETE( g_pHalfLambert );
   SAFE_DELETE( g_pGaussianFilter );

   SAFE_RELEASE( g_pDSV );
   SAFE_RELEASE( g_pRTV );

   SAFE_RELEASE( g_pSRView );
   SAFE_RELEASE( g_pIndexBuffer );
   SAFE_RELEASE( g_pVertexBuffer );

   SAFE_DELETE( g_pDebugFontUser );
   SAFE_DELETE( g_pD3D11User );
}

// 描画処理
HRESULT Render()
{
   HRESULT hr = E_FAIL;

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

   // レンダーターゲットビューをクリア
   float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
   g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pRTV, ClearColor );

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

   // ビューポートを退避
   UINT pNumVierports = 1;
   D3D11_VIEWPORT OldViewport;
   g_pD3D11User->m_D3DDeviceContext->RSGetViewports( &pNumVierports, &OldViewport );
   D3D11_VIEWPORT NewViewport;
   ::CopyMemory( &NewViewport, &OldViewport, sizeof( D3D11_VIEWPORT ) );
   NewViewport.Width = (FLOAT)g_Width;
   NewViewport.Height = (FLOAT)g_Height;
   g_pD3D11User->m_D3DDeviceContext->RSSetViewports( 1, &NewViewport );

   // アルファブレンディングを無効
   D3D11_RENDER_TARGET_BLEND_DESC BlendDesc;
   BlendDesc = g_pD3D11User->GetDefaultBlendDesc();
   g_pD3D11User->SetBlendState( &BlendDesc, 1, FALSE );

   // 深度ステンシルを設定
   {
      ID3D11DepthStencilState*  pDepthStencilState = NULL;
      D3D11_DEPTH_STENCIL_DESC ddsDesc;
      UINT StencilRef;
      ::ZeroMemory( &ddsDesc, sizeof( D3D11_DEPTH_STENCIL_DESC ) );
      g_pD3D11User->m_D3DDeviceContext->OMGetDepthStencilState( &pDepthStencilState, &StencilRef );
      pDepthStencilState->GetDesc( &ddsDesc );
      ddsDesc.DepthEnable = TRUE;  // 深度テストを有効にする
      ddsDesc.StencilEnable = FALSE;
      SAFE_RELEASE( pDepthStencilState );
      hr = g_pD3D11User->m_D3DDevice->CreateDepthStencilState( &ddsDesc, &pDepthStencilState );
      if( FAILED( hr ) ) goto EXIT;   
      g_pD3D11User->m_D3DDeviceContext->OMSetDepthStencilState( pDepthStencilState, StencilRef );
      SAFE_RELEASE( pDepthStencilState );
   }

   // *********************************************************************************************
   // ハーフランバート
   // *********************************************************************************************
   {
      // 頂点関連のデータをデバイスコンテキストにセット
      {
         // 頂点バッファ設定
         UINT stride = sizeof( VERTEX );
         UINT offset = 0;
         g_pD3D11User->m_D3DDeviceContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

         // インデックスバッファ設定
         g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
      }

      D3DXMATRIX matWVP, matWorld, matView, matProj;
      D3DXVECTOR4 v;

      // ワールド × ビュー × 射影行列
      {
         D3DXMATRIX matScale, matY, matTranslation;

         // 射影行列
         D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, 4.0f / 3.0f, 1.0f, 250.0f );
         // ビュー行列
         D3DXMatrixLookAtLH( &matView,
                              &D3DXVECTOR3( 0.0f, 0.0f, -15.0f ),
                              &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
                              &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

         // ワールド行列
         D3DXMatrixScaling( &matScale, 1.0f, 1.0f, 1.0f );
     
         static float r = 0.0f;
         r += 0.01f;
         D3DXMatrixRotationY( &matY, D3DXToRadian( r ) );
         D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, 0.0f );
         matWorld = matScale * matY * matTranslation;

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

      // 平行光源の方向ベクトル
      {
         D3DXMATRIX matInv;

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

      // 定数バッファを設定する
      g_pHalfLambert->SetConstantBuffers( g_pD3D11User->m_D3DDeviceContext, &matWVP, &v );

      // テクスチャーをシェーダーリソースに設定する
      g_pD3D11User->m_D3DDeviceContext->PSSetShaderResources( 0, 1, &g_pSRView );

      // ハーフランバートシェーダーの描画準備処理
      g_pHalfLambert->BeginPass( g_pD3D11User->m_D3DDeviceContext );

      // インデックスバッファを使用した描画
      g_pD3D11User->m_D3DDeviceContext->DrawIndexed( g_IndexBufferCnt, 0, 0 );

      // ハーフランバートシェーダーの描画終了処理
      g_pHalfLambert->EndPass( g_pD3D11User->m_D3DDeviceContext );
   }

   // 深度ステンシルを設定
   {
      ID3D11DepthStencilState*  pDepthStencilState = NULL;
      D3D11_DEPTH_STENCIL_DESC ddsDesc;
      UINT StencilRef;
      ::ZeroMemory( &ddsDesc, sizeof( D3D11_DEPTH_STENCIL_DESC ) );
      g_pD3D11User->m_D3DDeviceContext->OMGetDepthStencilState( &pDepthStencilState, &StencilRef );
      pDepthStencilState->GetDesc( &ddsDesc );
      ddsDesc.DepthEnable = FALSE;  // 深度テストを無効にする
      ddsDesc.StencilEnable = FALSE;
      SAFE_RELEASE( pDepthStencilState );
      hr = g_pD3D11User->m_D3DDevice->CreateDepthStencilState( &ddsDesc, &pDepthStencilState );
      if( FAILED( hr ) ) goto EXIT;   
      g_pD3D11User->m_D3DDeviceContext->OMSetDepthStencilState( pDepthStencilState, StencilRef );
      SAFE_RELEASE( pDepthStencilState );
   }

   // ビューポートを戻す
   g_pD3D11User->m_D3DDeviceContext->RSSetViewports( 1, &OldViewport );

   // *********************************************************************************************
   // ガウスフィルター
   // *********************************************************************************************
   {
      // 定数バッファを設定
      hr = g_pGaussianFilter->SetConstantBuffers( g_pD3D11User->m_D3DDeviceContext, g_Dispersion );
      if( FAILED( hr ) ) goto EXIT;

      // ガウスファイルターを適応する
      hr = g_pGaussianFilter->Render( g_pD3D11User->m_D3DDevice, g_pD3D11User->m_D3DDeviceContext, IN g_pRTV, OUT g_pD3D11User->m_RenderTargetView );
   }

   // レンダーターゲットをバックバッファに戻す
   g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 1, &g_pD3D11User->m_RenderTargetView, g_pD3D11User->m_DepthStencilView );

   // デバッグ専用フォント描画
   if( g_pDebugFontUser )
   {
      // FPS表示
      g_pDebugFontUser->RenderFPS( g_pD3D11User->m_D3DDeviceContext, 0, 0 );

      // 分散率表示
      char Debug[256];
      sprintf_s( Debug, "Dispersion:%f", g_Dispersion );
      g_pDebugFontUser->RenderDebugText( g_pD3D11User->m_D3DDeviceContext, Debug, 0, 0.1f );
   }

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

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

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:
      // ボケ率を弱くする
      if( wParam == VK_RIGHT )
      {
         g_Dispersion += 0.001f;
         if( g_Dispersion > 1.0f )
            g_Dispersion = 1.0f;
      }
      // ボケ率を強くする
      if( wParam == VK_LEFT )
      {
         g_Dispersion -= 0.001f;
         if( g_Dispersion < 0.001f )
            g_Dispersion = 0.001f;
      }
      break;

   case WM_KEYUP:
      // アプリ終了
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );

      // F2キーを押すと、ウィンドウモードを切り替える。
      // 自動的にウィンドウモードを切り替える機能もあるが、ウィンドウスタイルを自由に変更するために自分で実装することにした。
      if( wParam == VK_F2 )
      {
         g_pD3D11User->ChangeWindowMode();
      }
      // スクリーンショットを作成する
      if( wParam == VK_SNAPSHOT )
         ScreenShot = true;
      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 /*hPrevInstance*/,
                        LPTSTR    /*lpCmpLine*/,
                        INT       /*nCmdShow*/ )
{
   // メモリリーク検出
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF);

   HRESULT hr = E_FAIL;
   MSG msg;
   ::ZeroMemory(&msg, sizeof(MSG));

   // 表示モードを記述するための構造体。
   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, FALSE, FALSE, TRUE );
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("Direct3D 11.0 初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }

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

   // リソースの初期化
   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