Microsoft Visual Studio .NET 2003
 Microsoft DirectX 9.0 SDK (December 2004)
 シェーダーモデル 2.0

■クロスフィルター Prev  Top  Next
関連ページ:ライトブルーム その2

2009/01/06: デバイスロスト対応

ドメイン

今回は、HDRの定番エフェクト、クロスフィルターです。初代XBOX対応のレースゲーム「DOUBLE-S.T.E.A.L」 で鬼のようにやってるエフェクトです。つってもプレイしたことないけどね。今ではほとんどのゲームで見かける珍しくもなんともないエフェクトですな。 今更紹介するのもどうかと思うが気にしないように。


怖っ!!。まあいいや(笑)。クロスフィルターは、こんな感じで光源から十字状に光の筋が伸びる現象のことです。 自動車のヘッドライトを撮影するとこんな現象が発生します。

では簡単に処理フローを説明します。基本的に前回やったライトブルーム その2と同じです。

1.シーンをレンダリングする。
2.Zバッファはそのまま使用し、色情報を格納するサーフェイスを切り替え、クロスフィルターを適応する光源をレンダリングする。
3.2をクロスフィルター処理。
4.1 と 3を加算合成

以上です。 さてソースです。

---CrossFilter1.fx---


float m_TU[9];   //X方向の隣のテクセル位置
float m_TV[9];   //Y方向の隣のテクセル位置
float m_Power;   //明度の調整値

sampler s0 : register(s0);

struct VS_OUTPUT
{
   float4 Pos    : POSITION;
   float2 Tex    : TEXCOORD0;
};

VS_OUTPUT VS( float4 Pos    : POSITION,
              float2 Tex    : TEXCOORD0 )
{
   VS_OUTPUT Out;
   
   Out.Pos = Pos;
   Out.Tex = Tex;
   
   return Out;
}

//重みにより周辺のピクセルのカラー情報を合成しブラー処理する
float4 GetPixelColor( float2 Texel[10] )
{
   //取得したテクセル位置のカラー情報を取得する。
   //それぞれのカラー値に重みをかけている。この重みは適当。
   float4 p0  = tex2D( s0, Texel[0] ) * 0.19f;
   float4 p1  = tex2D( s0, Texel[1] ) * 0.17f;
   float4 p2  = tex2D( s0, Texel[2] ) * 0.15f;
   float4 p3  = tex2D( s0, Texel[3] ) * 0.13f;
   float4 p4  = tex2D( s0, Texel[4] ) * 0.11f;
   float4 p5  = tex2D( s0, Texel[5] ) * 0.09f;
   float4 p6  = tex2D( s0, Texel[6] ) * 0.07f;
   float4 p7  = tex2D( s0, Texel[7] ) * 0.05f;
   float4 p8  = tex2D( s0, Texel[8] ) * 0.03f;
   float4 p9  = tex2D( s0, Texel[9] ) * 0.01f;

   //カラーを合成する
   return ( p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 ) * m_Power;
}

//右方向にブラー
float4 PS1( VS_OUTPUT In ) : COLOR0
{
   float2 Texel[10];
   
   Texel[0] = In.Tex;   
   Texel[1] = In.Tex + float2( m_TU[0], 0.0f );
   Texel[2] = In.Tex + float2( m_TU[1], 0.0f );
   Texel[3] = In.Tex + float2( m_TU[2], 0.0f );
   Texel[4] = In.Tex + float2( m_TU[3], 0.0f );
   Texel[5] = In.Tex + float2( m_TU[4], 0.0f );
   Texel[6] = In.Tex + float2( m_TU[5], 0.0f );
   Texel[7] = In.Tex + float2( m_TU[6], 0.0f );
   Texel[8] = In.Tex + float2( m_TU[7], 0.0f );
   Texel[9] = In.Tex + float2( m_TU[8], 0.0f );

   return GetPixelColor( Texel );
}

//左方向にブラー
float4 PS2( VS_OUTPUT In ) : COLOR0
{
   float2 Texel[10];
   
   Texel[0] = In.Tex;   
   Texel[1] = In.Tex + float2( -m_TU[0], 0.0f );
   Texel[2] = In.Tex + float2( -m_TU[1], 0.0f );
   Texel[3] = In.Tex + float2( -m_TU[2], 0.0f );
   Texel[4] = In.Tex + float2( -m_TU[3], 0.0f );
   Texel[5] = In.Tex + float2( -m_TU[4], 0.0f );
   Texel[6] = In.Tex + float2( -m_TU[5], 0.0f );
   Texel[7] = In.Tex + float2( -m_TU[6], 0.0f );
   Texel[8] = In.Tex + float2( -m_TU[7], 0.0f );
   Texel[9] = In.Tex + float2( -m_TU[8], 0.0f );

   return GetPixelColor( Texel );
}

//上方向にブラー
float4 PS3( VS_OUTPUT In ) : COLOR0
{
   float2 Texel[10];
   
   Texel[0] = In.Tex;   
   Texel[1] = In.Tex + float2( 0.0f, m_TV[0] );
   Texel[2] = In.Tex + float2( 0.0f, m_TV[1] );
   Texel[3] = In.Tex + float2( 0.0f, m_TV[2] );
   Texel[4] = In.Tex + float2( 0.0f, m_TV[3] );
   Texel[5] = In.Tex + float2( 0.0f, m_TV[4] );
   Texel[6] = In.Tex + float2( 0.0f, m_TV[5] );
   Texel[7] = In.Tex + float2( 0.0f, m_TV[6] );
   Texel[8] = In.Tex + float2( 0.0f, m_TV[7] );
   Texel[9] = In.Tex + float2( 0.0f, m_TV[8] );

   return GetPixelColor( Texel );
}

//下方向にブラー
float4 PS4( VS_OUTPUT In ) : COLOR0
{
   float2 Texel[10];
   
   Texel[0] = In.Tex;   
   Texel[1] = In.Tex + float2( 0.0f, -m_TV[0] );
   Texel[2] = In.Tex + float2( 0.0f, -m_TV[1] );
   Texel[3] = In.Tex + float2( 0.0f, -m_TV[2] );
   Texel[4] = In.Tex + float2( 0.0f, -m_TV[3] );
   Texel[5] = In.Tex + float2( 0.0f, -m_TV[4] );
   Texel[6] = In.Tex + float2( 0.0f, -m_TV[5] );
   Texel[7] = In.Tex + float2( 0.0f, -m_TV[6] );
   Texel[8] = In.Tex + float2( 0.0f, -m_TV[7] );
   Texel[9] = In.Tex + float2( 0.0f, -m_TV[8] );

   return GetPixelColor( Texel );
}

technique TShader
{
   pass P0
   {
      VertexShader = compile vs_1_1 VS();
      PixelShader  = compile ps_2_0 PS1();
   }
   
   pass P1
   {
      VertexShader = compile vs_1_1 VS();
      PixelShader  = compile ps_2_0 PS2();
   }   

   pass P3
   {
      VertexShader = compile vs_1_1 VS();
      PixelShader  = compile ps_2_0 PS3();
   }   
   
   pass P4
   {
      VertexShader = compile vs_1_1 VS();
      PixelShader  = compile ps_2_0 PS4();
   }
}

クロスフィルターといってもやってることはただのブラー処理です。ただ前に紹介した方法よりさらに強くブラーをかけるために上下左右それぞれ10ピクセルずつ合成し、ブラー処理を行います。

---CrossFilter1.h---


//D3D2DSQUAREはスクリーン全体をおおう2Dオブジェクト(表面化散乱(Subsurface Scattering) ページ参照)
class CROSSFILTER1 : public D3D2DSQUARE
{
private:
   LPD3DXEFFECT m_pEffect;
   D3DXHANDLE m_pTechnique, m_pTU, m_pTV, m_pPower;
   LPDIRECT3DDEVICE9 m_pd3dDevice;

public:
   CROSSFILTER1( LPDIRECT3DDEVICE9 pd3dDevice, D3DPRESENT_PARAMETERS* pd3dParameters );
   CROSSFILTER1( LPDIRECT3DDEVICE9 pd3dDevice, UINT Width, UINT Height );
   ~CROSSFILTER1();
   void Invalidate();
   void Restore();
   HRESULT Load();
   void SetPower( float Power );
   void Render( int Pass );
   BOOL IsOK();
   LPD3DXEFFECT GetEffect(){ return m_pEffect; };
};

---CrossFilter1.cpp---


CROSSFILTER1::CROSSFILTER1( LPDIRECT3DDEVICE9 pd3dDevice, D3DPRESENT_PARAMETERS* pd3dParameters ) : D3D2DSQUARE( pd3dDevice, pd3dParameters )
{
   m_pd3dDevice = pd3dDevice;
   m_pEffect = NULL;
}

CROSSFILTER1::CROSSFILTER1( LPDIRECT3DDEVICE9 pd3dDevice, UINT Width, UINT Height ) : D3D2DSQUARE( pd3dDevice, Width, Height )
{
   m_pd3dDevice = pd3dDevice;
   m_pEffect = NULL;
}

CROSSFILTER1::~CROSSFILTER1()
{
   SafeRelease( m_pEffect );
}

void CROSSFILTER1::Invalidate()
{
   if( m_pEffect )
      m_pEffect->OnLostDevice();
}

void CROSSFILTER1::Restore()
{
   if( m_pEffect )
      m_pEffect->OnResetDevice();
}

HRESULT CROSSFILTER1::Load()
{
   D3DCAPS9 caps;
   HRESULT hr;

   m_pd3dDevice->GetDeviceCaps( &caps );
   if( caps.VertexShaderVersion >= D3DVS_VERSION( 1, 1 ) && caps.PixelShaderVersion >= D3DPS_VERSION( 2, 0 ) )
   {
      hr = D3D2DSQUARE::Load();
      if( FAILED( hr ) )
         return -1;

      //シェーダーの初期化
      LPD3DXBUFFER pErr = NULL;
      hr = D3DXCreateEffectFromFile( m_pd3dDevice, _T("CrossFilter1.fx"), NULL, NULL, 0, NULL, &m_pEffect, &pErr );
      if( FAILED( hr ) )
         return -2;

      m_pTechnique = m_pEffect->GetTechniqueByName( "TShader" );
      m_pTU        = m_pEffect->GetParameterByName( NULL, "m_TU" );
      m_pTV        = m_pEffect->GetParameterByName( NULL, "m_TV" );
      m_pPower     = m_pEffect->GetParameterByName( NULL, "m_Power" );

      //1テクセルの大きさをセット
      float TU = 1.0f / D3D2DSQUARE::GetWidth();
      float TV = 1.0f / D3D2DSQUARE::GetHeight();

      const int Array = 9;

      float u[Array];
      float v[Array];
      for( int i=0; i<Array; i++ )
      {
         u[i] = TU * ( i + 1 );
         v[i] = TV * ( i + 1 );
      }

      m_pEffect->SetFloatArray( m_pTU, u, Array );
      m_pEffect->SetFloatArray( m_pTV, v, Array );

      m_pEffect->SetTechnique( m_pTechnique );
   }

   else
   {
      return -3;
   }

   return S_OK;
}

void CROSSFILTER1::SetPower( float Power )
{
   if( m_pEffect )
   {
      m_pEffect->SetFloat( m_pPower, Power );
   }
}

void CROSSFILTER1::Render( int Pass )
{
   if( m_pEffect )
   {
      m_pEffect->Begin( NULL, 0 );
      m_pEffect->BeginPass( Pass );

      D3D2DSQUARE::Render();

      m_pEffect->EndPass();
      m_pEffect->End();
   }
}

BOOL CROSSFILTER1::IsOK()
{
   if( m_pEffect == NULL )
      return FALSE;

   return TRUE;
}

クロスフィルターシェーダーの制御クラスです。

---Main.cpp---


LPDIRECT3DDEVICE9 m_pd3dDevice = NULL;
D3DPRESENT_PARAMETERS m_d3dParameters;

D3DCAPS9 Caps;

//シーンのメッシュ
//DirectX SDK(December 2004) に添付されているDXUTMesh.cppファイルにあるヘルパークラス群
//背景
CDXUTMesh* m_pMeshBack1        = NULL;
//トラ
CDXUTMesh* m_pMeshTiger        = NULL;
//怪光線?
CDXUTMesh* m_pMeshHDR          = NULL;

//D3D2DSQUAREはスクリーン全体をおおう2Dオブジェクト(表面化散乱(Subsurface Scattering) ページ参照)
D3D2DSQUARE* m_pSquObj = NULL;

//ランバート拡散照明クラスの宣言
LAMBERT1* m_pLambert1 = NULL;

//クロスフィルタークラスの宣言
CROSSFILTER1* m_pCrossFilter1 = NULL;

//怪光線をレンダリングするためのサーフェイス
LPDIRECT3DTEXTURE9    m_pHDRTexture;
LPDIRECT3DSURFACE9    m_pHDRSurface;

//クロスフィルター用サーフェイス
LPDIRECT3DTEXTURE9    m_pBlurTexture[4];
LPDIRECT3DSURFACE9    m_pBlurSurface[4];

UINT nWidth = 1024;
UINT nHeight = 768;

D3DXVECTOR4 LightPos = D3DXVECTOR4( 72.0f, 100.0f, -20.0f, 0.0f );
D3DXVECTOR4 LightDir;
D3DXVECTOR4 EyePos   = D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f );

bool RenderOK = false;

int APIENTRY WinMain( HINSTANCE hInstance,
                      HINSTANCE /*hPrevInstance*/,
                      LPSTR     /*lpCmpLine*/,
                      INT       /*nCmdShow*/)
{  
   char* AppName = "Tutrial";

   MSG msg;
   ZeroMemory(&msg, sizeof(MSG));
   HWND hWnd = NULL;

   WNDCLASSEX wc;
   wc.cbSize      = sizeof(WNDCLASSEX);
   wc.style      = CS_VREDRAW | CS_HREDRAW;
   wc.lpfnWndProc   = (WNDPROC)WndProc;
   wc.cbClsExtra   = 0;
   wc.cbWndExtra   = sizeof(DWORD);
   wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
   wc.hIcon      = NULL;
   wc.hIconSm      = NULL;
   wc.lpszMenuName    = NULL;
   wc.lpszClassName = AppName;
   wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
   wc.hInstance    = hInstance;
   ::RegisterClassEx(&wc);


   //****************************************************************
   //ここでウィンドウの作成処理
   //****************************************************************


   //****************************************************************
   //ここでDirect3Dの初期化を行う。
   //****************************************************************


   //メッシュのロード
   m_pMeshBack1 = new CDXUTMesh();
   m_pMeshBack1->Create( m_pd3dDevice, _T("res\\01.x") );
   m_pMeshBack1->SetFVF( m_pd3dDevice, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 );

   m_pMeshTiger = new CDXUTMesh();
   m_pMeshTiger->Create( m_pd3dDevice, _T("res\\tiger.x") );
   m_pMeshTiger->SetFVF( m_pd3dDevice, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 );

   //太陽
   m_pMeshHDR = new CDXUTMesh();
   m_pMeshHDR->Create( m_pd3dDevice, _T("res\\HDR.x") );
   m_pMeshHDR->SetFVF( m_pd3dDevice, D3DFVF_XYZ | D3DFVF_TEX1 );

   m_pSquObj = new D3D2DSQUARE( m_pd3dDevice, &m_d3dParameters );
   m_pSquObj->Load();

   //ランバート拡散照明クラスの初期化
   m_pLambert1 = new LAMBERT1( m_pd3dDevice );
   m_pLambert1->Load();

   //クロスフィルタークラスの初期化
   m_pCrossFilter1 = new CROSSFILTER1( m_pd3dDevice, nWidth / 4, nHeight / 4 );
   m_pCrossFilter1->Load();

   //平行光源の位置ベクトルから方向ベクトルを計算する
   LightDir = D3DXVECTOR4( -LightPos.x, -LightPos.y, -LightPos.z, 0.0f );
   D3DXVec3Normalize( (D3DXVECTOR3*)&LightDir, (D3DXVECTOR3*)&LightDir );

   RenderOK = true;
   
   //デバイス消失後にリストアする必要があるオブジェクトの初期化
   Restore();

   ::ShowWindow(hWnd, SW_SHOW);
   ::UpdateWindow(hWnd);

   do
   { 
      if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
      {
         ::TranslateMessage(&msg); 
         ::DispatchMessage(&msg); 
      }
      else
      {
         if( MainLoop(hWnd) == FALSE )
            ::DestroyWindow( hWnd );
      }
   }while( msg.message != WM_QUIT );

   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

void Invalidate()
{
   m_pLambert1->Invalidate();
   m_pCrossFilter1->Invalidate();

   for( int i=0; i<4; i++ )
   {
      SafeRelease( m_pBlurSurface[i] );
      SafeRelease( m_pBlurTexture[i] );
   }

   SafeRelease( m_pHDRSurface );
   SafeRelease( m_pHDRTexture );
}

void Restore()
{
   m_pLambert1->Restore();
   m_pCrossFilter1->Restore();

   //ブラーフィルターサーフェイス
   for( int i=0; i<4; i++ )
   {
      m_pd3dDevice->CreateTexture( m_pCrossFilter1->GetWidth(),
                                   m_pCrossFilter1->GetHeight(),
                                   1,
                                   D3DUSAGE_RENDERTARGET,
                                   D3DFMT_A8R8G8B8,
                                   D3DPOOL_DEFAULT,
                                   &m_pBlurTexture[i],
                                   NULL );
      m_pBlurTexture[i]->GetSurfaceLevel( 0, &m_pBlurSurface[i] );
   }

   m_pd3dDevice->CreateTexture( nWidth,
                                nHeight,
                                1,
                                D3DUSAGE_RENDERTARGET,
                                D3DFMT_A8R8G8B8,
                                D3DPOOL_DEFAULT,
                                &m_pHDRTexture,
                                NULL );
   m_pHDRTexture->GetSurfaceLevel( 0, &m_pHDRSurface );


   //固定機能パイプラインライティングを設定する
   D3DLIGHT9 Light;
   ZeroMemory(&Light, sizeof(D3DLIGHT9));
   Light.Type = D3DLIGHT_DIRECTIONAL;
   Light.Direction = D3DXVECTOR3( LightDir.x, LightDir.y, LightDir.z );
   Light.Ambient   = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
   Light.Diffuse   = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
   Light.Specular  = D3DXCOLOR( 0.0f, 0.0f, 0.0f, 0.0f );
   m_pd3dDevice->SetLight(0, &Light);
   m_pd3dDevice->LightEnable(0, TRUE);

   D3DMATERIAL9 Material;
   ZeroMemory( &Material, sizeof( Material ) );
   Material.Diffuse.r = 1.0f;
   Material.Diffuse.g = 1.0f;
   Material.Diffuse.b = 1.0f;
   Material.Diffuse.a = 1.0f;
   m_pd3dDevice->SetMaterial( &Material );
}

//メッセージループからコールされる関数
BOOL MainLoop()
{
   HRESULT hr;
   
   //レンダリング不可能
   if( RenderOK == false )
   {
      hr = m_pd3dDevice->TestCooperativeLevel();
      switch( hr )
      {
      //デバイスは消失しているがReset可能
      case D3DERR_DEVICENOTRESET:

         //開放
         Invalidate();

         //デバイスをリセットする
         hr = m_pd3dDevice->Reset( &m_d3dParameters );
         
         switch( hr )
         {
         //デバイスロスト
         case D3DERR_DEVICELOST:
            break;

         //内部ドライバーエラー
         case D3DERR_DRIVERINTERNALERROR:
            return FALSE;
            break;

         //メソッドの呼び出しが無効です
         case D3DERR_INVALIDCALL:
            return FALSE;
            break;

         case S_OK:

            //初期化
            Restore();

            RenderOK = true;
         }
         break;
      }
   }

   //レンダリング可能
   else
   {
      //シーンのクリア
      m_pd3dDevice->Clear( 0L, 
                           NULL,
                           D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                           0x0, 
                           1.0f,
                           0L );
   
      m_pd3dDevice->BeginScene();
   
      D3DXMATRIX matProj, matView, matWorld;
   
      //パースあり射影行列
      D3DXMatrixPerspectiveFovLH( &matProj,
                                  D3DX_PI/4.0f,
                                  4.0f / 3.0f,
                                  11.0f,
                                  220.0f );
      m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
                        
      //ビュー座標変換
      D3DXMatrixIdentity( &matView );   
      m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
      
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );


      //****************************************************************
      //ステップ1 : シーンのレンダリング
      //****************************************************************

      //背景のレンダリング
      m_pLambert1->Begin();
      D3DXMatrixIdentity( &matWorld );
      m_pLambert1->SetMatrix( &matWorld, &LightDir );
      m_pLambert1->SetAmbient( 0.0f );
      m_pd3dDevice->SetTexture( 0, m_pMeshBack1->m_pTextures[0] );
      m_pLambert1->BeginPass();
      m_pMeshBack1->m_pLocalMesh->DrawSubset(0);
      m_pLambert1->EndPass();
      m_pLambert1->End();

      //トラをレンダリング
      D3DXMATRIX matScaling, matTranslation;
      D3DXMatrixScaling( &matScaling, 6.0f, 6.0f, 6.0f );
      D3DXMatrixTranslation( &matTranslation, 0.0f, -1.0f, 40.0 );
      matWorld = matScaling * matTranslation;
      m_pLambert1->Begin();
      m_pLambert1->SetMatrix( &matWorld, &LightDir );
      m_pLambert1->SetAmbient( 0.0f );
      m_pd3dDevice->SetTexture( 0, m_pMeshTiger->m_pTextures[0] );
      m_pLambert1->BeginPass();
      m_pMeshTiger->m_pLocalMesh->DrawSubset(0);
      m_pLambert1->EndPass();
      m_pLambert1->End();         
         
         
      //****************************************************************
      //ステップ2 : クロスフィルターの種をレンダリング
      //****************************************************************
      
      //加算合成
      m_pd3dDevice->SetRenderState( D3DRS_BLENDOP,   D3DBLENDOP_ADD );
      m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
      m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
      //αブレンドを有効にする
      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
      //ライティングを無効にする
      m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
      //Zバッファへの書き込みを無効にする
      m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );

      //レンダーターゲットを変更
      LPDIRECT3DSURFACE9 OldSurface = NULL;
      m_pd3dDevice->GetRenderTarget( 0, &OldSurface );
      m_pd3dDevice->SetRenderTarget( 0, m_pHDRSurface );

      //レンダーターゲットをクリアする
      //ただしZバッファは背景のZ値をそのまま使用するためクリアしない
      m_pd3dDevice->Clear( 0L, NULL,
                           D3DCLEAR_TARGET,
                           0x0, 
                           1.0f,
                           0L );

      //トラの怪光線を固定機能パイプラインでレンダリング
      D3DXMatrixScaling( &matScaling, 0.002f, 0.002f, 1.0f );
      D3DXMatrixTranslation( &matTranslation, 0.9f, 2.0f, 31.8f );
      matWorld = matScaling * matTranslation;
      //ビルボードマトリックスを取得(ビルボード ページ参照)
      matWorld = GetBillBoardMatrix( m_pd3dDevice, &matWorld );
      m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
      m_pd3dDevice->SetTexture( 0, m_pMeshHDR->m_pTextures[0] );
      m_pMeshHDR->m_pLocalMesh->DrawSubset(0);

      D3DXMatrixScaling( &matScaling, 0.002f, 0.002f, 1.0f );
      D3DXMatrixTranslation( &matTranslation, -0.9f, 2.0f, 31.8f );
      matWorld = matScaling * matTranslation;
      //ビルボードマトリックスを取得(ビルボード ページ参照)
      matWorld = GetBillBoardMatrix( m_pd3dDevice, &matWorld );
      m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
      m_pd3dDevice->SetTexture( 0, m_pMeshHDR->m_pTextures[0] );
      m_pMeshHDR->m_pLocalMesh->DrawSubset(0);
      
      
      //****************************************************************
      //ステップ3 : クロスフィルターを適応
      //****************************************************************
      
      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
      m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
      
      //縮小サーフェイスにレンダリングするのでビューポートを切り替える
      D3DVIEWPORT9 OldViewport, NewViewport;
      m_pd3dDevice->GetViewport( &OldViewport );
      NewViewport.Width  = m_pCrossFilter1->GetWidth();
      NewViewport.Height = m_pCrossFilter1->GetHeight();
      NewViewport.X = 0;
      NewViewport.Y = 0;
      NewViewport.MinZ = 0.0f;
      NewViewport.MaxZ = 1.0f;
      m_pd3dDevice->SetViewport( &NewViewport );

      //ブラーをかけるのでクランプに変更
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
      
      //Zバッファは使用しない
      m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );

      m_pd3dDevice->SetTexture( 0, m_pHDRTexture );

      //明度を強くする
      m_pCrossFilter1->SetPower( 5.0f );
      
      //クロスフィルターを適応
      for( int i=0; i<4; i++ )
      {
         m_pd3dDevice->SetRenderTarget( 0, m_pBlurSurface[i] );
         m_pd3dDevice->Clear( 0L, NULL,
                              D3DCLEAR_TARGET,
                              0x0, 
                              1.0f,
                              0L );
         m_pCrossFilter1->Render( i );
      }

      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );

      //レンダーターゲットをバックバッファに戻す
      m_pd3dDevice->SetRenderTarget( 0, OldSurface );
      SafeRelease( OldSurface );

      m_pd3dDevice->SetViewport( &OldViewport );

      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
      
      //4方向に適応したクロスフィルターを加算合成する
      for( int i=0; i<4; i++ )
      {
         m_pd3dDevice->SetTexture( 0, m_pBlurTexture[i] );
         m_pSquObj->Render();
      }

      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
      m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
      m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );

      m_pd3dDevice->EndScene();

      hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
      
      //デバイスロストのチェック
      switch( hr )
      {
      //デバイスロスト
      case D3DERR_DEVICELOST:
         RenderOK = false;
         break;

      //内部ドライバーエラー
      case D3DERR_DRIVERINTERNALERROR:
         return FALSE;
         break;

      //メソッドの呼び出しが無効です
      case D3DERR_INVALIDCALL:
         return FALSE;
         break;
      }
   }
      
   return TRUE;
}

以上です。前回よりも簡単でした。特に面倒なこともやってないと思います。

さて今回はあらかじめ決められた光源に対してクロスフィルターを適応しましたが、フォンシェーディング で発生するハイライトに適応することもできます。簡単に解説すると

1.レンダーターゲットを2枚のマルチレンダーターゲットで設定する。
2.オブジェクトをレンダリングし、レンダーターゲットの1枚目に普通に色情報を格納し、2枚目に 1.0f を減算した値(ハイライト部分のみを抽出した色情報)を格納する。
3.2枚目のレンダーターゲットサーフェイスにクロスフィルターを適応する。
4.1枚目のレンダーターゲットサーフェイスに3の結果を加算合成する。

ってな感じになります。興味のある方は、やってみてください。

Prev  Top  Next
inserted by FC2 system