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

■光散乱シミュレーション Prev  Top  Next
関連ページ:指数フォグ アルファチャンネルつきDDSファイル作成

無料レンタルサーバー

今回は光散乱シミュレーションをやります。まあシミュレーションつってもそんな大層なもんじゃないです(笑)。 本来は計算式を使用するんでしょうけど、よくわからんので計算式は使用せず、カラールックアップテーブルを使用します。 そんなわけなので何も説明しない...ってのもあれなので理論について簡単に説明します。

光散乱シミュレーションは2つの自然現象により構成されます。ひとつはレイリー散乱、もうひとつはミー散乱です。

レイリー散乱は、光の波長よりも小さいサイズの粒子による光の散乱です。 空が青くみえるのは波長が短い青が赤より多く散乱されるためです。 また夕焼け、朝焼けに赤くなるのは散乱を受けやすい青が観測者に届きにくく、散乱を受けにくい赤が届くためです。

次にミー散乱は、光の波長程度以上の大きさの球形の粒子による光の散乱現象です。いわゆるフォグがこの現象に当たります。

日中です。

夕方です。太陽が正面に見えます。太陽はテクスチャーを使用しています。

夜です。

今回のサンプルでは、太陽の位置をキーとしてカラールックアップテーブルから空の色と太陽光の色を取得し、レンダリングを行います。 カラールックアップテーブルはこんな感じです。 ちなみに左側が夜に適応される色、右側が日中に適応される色となります。

 
空のカラールックアップテーブル。アルファチャンネルを含むDDSファイルです。 DDSファイルの作成はアルファチャンネルつきDDSファイル作成のページを参照してください。 左側がRGB、右側がアルファチャンネルです。 RGBは空の色になります。アルファチャンネルは雲と星のテクスチャーの合成値となります。


これは太陽光のカラールックアップテーブルです。

---LSS.fx---


float4x4 m_WVPP;                //ワールド × ビュー × 射影
float4 m_LightDir;              //平行光源の方向ベクトル
float4 m_Ambient  = 1.0f;       //環境光
float  m_CLUTTU;                //太陽の方向ベクトルと上方向ベクトル[0.0f, 1.0f, 0.0f]との内積
float4 m_FogColor;              //フォグカラー
float  m_Param1;                //フォグの計算式のパラメータ1
float  m_Param2;                //フォグの計算式のパラメータ2

sampler tex0 : register(s0);    //Pass0:空用のCLUTテーブル Pass1:ライト用CLUTテーブル
sampler tex1 : register(s1);    //Pass0:雲         Pass1:デカールマップ
sampler tex2 : register(s2);    //Pass0:星

//Pass0:空のレンダリング
struct VS0_OUTPUT
{
   float4 Pos    : POSITION;
   float2 Tex    : TEXCOORD0;
};

VS0_OUTPUT VS0( float4 Pos    : POSITION,
                float4 Normal : NORMAL,
                float2 Tex    : TEXCOORD0 )
{
   VS0_OUTPUT Out;
   
   Out.Pos = mul( Pos, m_WVPP );
   Out.Tex = Tex;
   
   return Out;
}

float4 PS0( VS0_OUTPUT In ) : COLOR0
{ 
   float4 Out;

   //空の色をCLUTテーブルから取得
   Out = tex2D( tex0, float2( m_CLUTTU, 0.0f ) );
   
   //雲テクスチャーを取得
   float4 Cloud = tex2D( tex1, In.Tex );
   
   //星テクスチャーを取得
   float4 Star  = tex2D( tex2, In.Tex );

   //雲、または星を空に適応する
   //昼間は雲を、夜は雲にさえぎられていない部分に星をレンダリングする感じ
   Out += lerp( max( 0.0f, Star - Cloud ), Cloud, Out.a );
   
   return Out;
}

//Pass1:空以外のオブジェクトのレンダリング
struct VS1_OUTPUT
{
   float4 Pos      : POSITION;
   float4 Col      : COLOR0;
   float2 Tex      : TEXCOORD0;
   float4 LocalPos : TEXCOORD1;
};

VS1_OUTPUT VS1( float4 Pos    : POSITION,
                float4 Normal : NORMAL,
                float2 Tex    : TEXCOORD0 )
{
   VS1_OUTPUT Out;
   
   Out.Pos = mul( Pos, m_WVPP );
   
   float3 L = -m_LightDir.xyz;
   float3 N = normalize( Normal.xyz );
   Out.Col = max( m_Ambient, dot(N, L) );
   Out.Tex = Tex;
   Out.LocalPos = Out.Pos;

   return Out;
}

float4 PS1( VS1_OUTPUT In ) : COLOR0
{  
   float4 Out;
   
   //ライトの色をカラールックアップテーブルから取得
   float4 LightColor = tex2D( tex0, float2( m_CLUTTU, 0.0f ) );
   
   //フォグの指数計算により「重み」を計算
   float f = pow( 1.0f - pow( In.LocalPos.z / In.LocalPos.w, m_Param1 ), m_Param2 );
   
   //フォグを適応する
   Out = tex2D( tex1, In.Tex ) * In.Col * f + m_FogColor * ( 1.0f - f );

   //ライトの色を適応する
   Out *= LightColor;
   
   return Out;
}

technique TShader
{
   //空のレンダリング
   pass P0
   {
      VertexShader = compile vs_1_1 VS0();
      PixelShader  = compile ps_2_0 PS0();
   }
   
   //空以外のオブジェクトのレンダリング
   pass P1
   {
      VertexShader = compile vs_1_1 VS1();
      PixelShader  = compile ps_2_0 PS1();
   }
}

シェーダー本体です。Pass0で空をレンダリング、Pass1で空以外のオブジェクトをレンダリングします。 Pass1ではランバート拡散照明によりライティングします。 Pass1の重みの計算は指数フォグで説明しているのでそちらを参照してください。

---LightScatteringSimulation.h---


class LSS
{
private:
   LPD3DXEFFECT m_pEffect;
   D3DXHANDLE m_pTechnique, m_pWVPP, m_pLightDir, m_pAmbient, m_pCLUTTU, m_pFogColor, m_pParam1, m_pParam2;
   D3DXMATRIX m_matView, m_matProj;
   LPDIRECT3DDEVICE9 m_pd3dDevice;
   
   LPDIRECT3DTEXTURE9 m_pCLUTTexture[2];

public:
   LSS( LPDIRECT3DDEVICE9 pd3dDevice );
   ~LSS();
   void Invalidate();
   void Restore();
   HRESULT Load( char* pCLUTSkyFileName, char* pCLUTLightPowerFileName );
   void Begin();
   void BeginPass( UINT Pass );
   void SetAmbient( float Ambient );
   void SetAmbient( D3DXVECTOR4* pAmbient );
   void SetMatrix( D3DXMATRIX* pMatWorld, D3DXVECTOR4* pLightDir );
   void EndPass();
   void End();
   //フォグの色を設定
   void SetFogColor( D3DXVECTOR4* pFogColor );
   void SetFogColor( float FogColor );
   //フォグの計算式のパラメータを設定
   void SetParameters( float Param1, float Param2 );
   void CommitChanges();
   BOOL IsOK();
   LPD3DXEFFECT GetEffect(){ return m_pEffect; };
};

フォグ関連のメソッドはPass1で使用します。

---LightScatteringSimulation.cpp---


LSS::LSS( LPDIRECT3DDEVICE9 pd3dDevice )
{
   m_pd3dDevice = pd3dDevice;
   m_pEffect = NULL;
   m_pCLUTTexture[0] = NULL;
   m_pCLUTTexture[1] = NULL;
}

LSS::~LSS()
{
   //SafeReleaseは関数ではなくマクロ
   //#define SafeRelease(x) { if(x) { (x)->Release(); (x)=NULL; } }

   SafeRelease( m_pEffect );
   SafeRelease( m_pCLUTTexture[0] );
   SafeRelease( m_pCLUTTexture[1] );
}

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

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

HRESULT LSS::Load( char* pCLUTSkyFileName, char* pCLUTLightPowerFileName )
{
   D3DCAPS9 caps;
   
   m_pd3dDevice->GetDeviceCaps( &caps );
   if( caps.VertexShaderVersion >= D3DVS_VERSION( 1, 1 ) && caps.PixelShaderVersion >= D3DPS_VERSION( 2, 0 ) )
   {
      LPD3DXBUFFER pErr = NULL;
      HRESULT hr = D3DXCreateEffectFromFile( m_pd3dDevice, _T("LSS.fx"), NULL, NULL, 0, NULL, &m_pEffect, &pErr );
      if( FAILED( hr ) )
         return -1;

      m_pTechnique = m_pEffect->GetTechniqueByName( "TShader" );
      m_pWVPP      = m_pEffect->GetParameterByName( NULL, "m_WVPP" );
      m_pLightDir  = m_pEffect->GetParameterByName( NULL, "m_LightDir" );
      m_pAmbient   = m_pEffect->GetParameterByName( NULL, "m_Ambient" );
      m_pCLUTTU    = m_pEffect->GetParameterByName( NULL, "m_CLUTTU" );
      m_pFogColor  = m_pEffect->GetParameterByName( NULL, "m_FogColor" );
      m_pParam1    = m_pEffect->GetParameterByName( NULL, "m_Param1" );
      m_pParam2    = m_pEffect->GetParameterByName( NULL, "m_Param2" );

      m_pEffect->SetTechnique( m_pTechnique );

      //空カラールックアップテーブルをロード
      hr = D3DXCreateTextureFromFileEx( m_pd3dDevice,
                                        pCLUTSkyFileName,
                                        D3DX_DEFAULT,
                                        D3DX_DEFAULT,
                                        1,
                                        0,
                                        D3DFMT_UNKNOWN,
                                        D3DPOOL_MANAGED,
                                        D3DX_DEFAULT,
                                        D3DX_DEFAULT,
                                        0x0,
                                        NULL,
                                        NULL,
                                        &m_pCLUTTexture[0] );
      if( FAILED( hr ) )
         return -2;

      //太陽光カラールックアップテーブルをロード
      hr = D3DXCreateTextureFromFileEx( m_pd3dDevice,
                                        pCLUTLightPowerFileName,
                                        D3DX_DEFAULT,
                                        D3DX_DEFAULT,
                                        1,
                                        0,
                                        D3DFMT_UNKNOWN,
                                        D3DPOOL_MANAGED,
                                        D3DX_DEFAULT,
                                        D3DX_DEFAULT,
                                        0x0,
                                        NULL,
                                        NULL,
                                        &m_pCLUTTexture[1] );
      if( FAILED( hr ) )
         return -3;
   }

   else
   {
      return -4;
   }

   return S_OK;
}

void LSS::Begin()
{
   if(  m_pEffect )
   {
      m_pd3dDevice->GetTransform( D3DTS_VIEW, &m_matView );
      m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &m_matProj );
   
      m_pEffect->Begin( NULL, 0 );
   }
}

void LSS::BeginPass( UINT Pass )
{
   if( m_pEffect )
   {
      m_pd3dDevice->SetTexture( 0, m_pCLUTTexture[Pass] );
      m_pEffect->BeginPass( Pass );
   }
}

void LSS::SetAmbient( float Ambient )
{
   if( m_pEffect )
   {
      D3DXVECTOR4 A;
      A = D3DXVECTOR4( Ambient, Ambient, Ambient, 1.0f );
      m_pEffect->SetVector( m_pAmbient, &A );
   }
}

void LSS::SetAmbient( D3DXVECTOR4* pAmbient )
{
   if( m_pEffect )
      m_pEffect->SetVector( m_pAmbient, pAmbient );
}

//ローカル座標系
void LSS::SetMatrix( D3DXMATRIX* pMatWorld, D3DXVECTOR4* pLightDir )
{
   if( m_pEffect )
   {
      D3DXMATRIX m, m1, m2;
      D3DXVECTOR4 LightDir;
      D3DXVECTOR4 v;

      //遠近射影での行列変換
      m = (*pMatWorld) * m_matView * m_matProj;
      m_pEffect->SetMatrix( m_pWVPP, &m );

      //Light
      LightDir = *pLightDir;
      D3DXMatrixInverse( &m1, NULL, pMatWorld );
      D3DXVec4Transform( &v, &LightDir, &m1 );
      D3DXVec4Normalize( &v, &v );
      m_pEffect->SetVector( m_pLightDir, &v );

      //太陽光の方向ベクトルの逆ベクトルと上方向ベクトルとの内積を計算
      //この値がカラールックアップテーブルの TU 方向の参照位置となる
      LightDir *= -1.0f;
      D3DXVECTOR3 Up = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
      float dot = D3DXVec3Dot( (D3DXVECTOR3*)&LightDir, &Up );
      //負の数にならないように調整
      dot = ( 1.0f + dot ) * 0.5f;
      m_pEffect->SetFloat( m_pCLUTTU, dot );
   }
}

void LSS::EndPass()
{
   if( m_pEffect )
   {
      m_pEffect->EndPass();
   }
}

void LSS::End()
{
   if( m_pEffect )
   {
      m_pEffect->End();
   }
}

void LSS::SetParameters( float Param1, float Param2 )
{
   if( m_pEffect )
   {
      m_pEffect->SetFloat( m_pParam1, Param1 );
      m_pEffect->SetFloat( m_pParam2, Param2 );
   }
}

void LSS::SetFogColor( float FogColor )
{
   if( m_pEffect )
   {
      D3DXVECTOR4 A;
      A = D3DXVECTOR4( FogColor, FogColor, FogColor, 1.0f );
      m_pEffect->SetVector( m_pFogColor, &A );
   }
}

void LSS::SetFogColor( D3DXVECTOR4* pFogColor )
{
   if( m_pEffect )
      m_pEffect->SetVector( m_pFogColor, pFogColor );
}

void LSS::CommitChanges()
{
   if( m_pEffect )
      m_pEffect->CommitChanges();
}

BOOL LSS::IsOK()
{
   if( m_pEffect )
      return TRUE;

   return FALSE;
}

これまでシェーダーが使用できない環境では固定機能パイプラインで実行できるように設計してましたが今回からやめます。 固定機能パイプラインで問題なく実行可能か検証してないのにいれといても意味がないので(笑)。 検証する気もないですしね。

---Main.cpp---


LPDIRECT3D9 m_pdirect3d9 = NULL;
LPDIRECT3DDEVICE9 m_pd3dDevice = NULL;
D3DPRESENT_PARAMETERS m_d3dParameters;

D3DCAPS9 Caps;

//シーンのメッシュ
//DirectX SDK(December 2004) に添付されているDXUTMesh.cppファイルにあるヘルパークラス群
CDXUTMesh* m_pMeshBack = NULL;
CDXUTMesh* m_pMeshSun = NULL;
CDXUTMesh* m_pMeshTiger = NULL;

//雲テクスチャー
LPDIRECT3DTEXTURE9 m_pCloudTexture = NULL;

//星テクスチャー
LPDIRECT3DTEXTURE9 m_pStarTexture = NULL;

//光散乱シミュレーションクラスの宣言
LSS* m_pLSS = NULL;

//スクリーンの解像度
UINT nWidth = 1024;
UINT nHeight = 768;

//太陽の角度
float SunRotation = 45.0f;

//太陽の半径
float SunRadius = 350.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_pd3dDevice->GetDeviceCaps(&Caps);


   //光散乱シミュレーションクラスの初期化
   m_pLSS = new LSS( m_pd3dDevice );
   m_pLSS->Load( _T("res\\CLUTSky.dds"), _T("res\\CLUTLight.bmp") );


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

   //太陽
   m_pMeshSun = new CDXUTMesh();
   m_pMeshSun->Create( m_pd3dDevice, _T("res\\sun.x") );
   m_pMeshSun->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 );

   D3DXCreateTextureFromFileEx( m_pd3dDevice,
                                _T("res\\Cloud.bmp"),
                                D3DX_DEFAULT,
                                D3DX_DEFAULT,
                                1,
                                0,
                                D3DFMT_UNKNOWN,
                                D3DPOOL_MANAGED,
                                D3DX_DEFAULT,
                                D3DX_DEFAULT,
                                0x0,
                                NULL,
                                NULL,
                                &m_pCloudTexture );

   D3DXCreateTextureFromFileEx( m_pd3dDevice,
                                _T("res\\Star.bmp"),
                                D3DX_DEFAULT,
                                D3DX_DEFAULT,
                                1,
                                0,
                                D3DFMT_UNKNOWN,
                                D3DPOOL_MANAGED,
                                D3DX_DEFAULT,
                                D3DX_DEFAULT,
                                0x0,
                                NULL,
                                NULL,
                                &m_pStarTexture );

   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_pLSS->Invalidate();
}

//デバイスのリセット後に初期化すべきオブジェクト
void Restore()
{
   m_pLSS->Restore();
}

//メッセージループからコールされる関数
BOOL MainLoop( HWND HWnd )
{
   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
   {
      D3DXMATRIX matWVP, matPProj, matView, matWorld, matTiger, matScaling, matTranslation, matRotation;

      //遠近射影座標変換
      //クリップ面はアプリケーションごとに調整すること
      D3DXMatrixPerspectiveFovLH( &matPProj,
                                  D3DX_PI/4.0f,
                                  4.0f / 3.0f,
                                  30.0f, 1100.0f );
      m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matPProj );


      //ビュー座標変換
      D3DXMatrixIdentity( &matView );
      m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

      //トラ
      D3DXMatrixRotationY( &matRotation, D3DXToRadian( 45.0f ) );
      D3DXMatrixScaling( &matScaling, 40.0f, 40.0f, 40.0f );
      D3DXMatrixTranslation( &matTranslation, 0.0f, 50.0f, 400.0f );
      matTiger = matScaling * matRotation * matTranslation;

      m_pd3dDevice->BeginScene();

      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
      //太陽が真上または真下にあるとき正しくレンダリングできないときがあるので CLAMP にする。
      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU,  D3DTADDRESS_CLAMP );

      m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

      m_pd3dDevice->SetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
      m_pd3dDevice->SetSamplerState( 2, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

      m_pd3dDevice->Clear( 0L,
                           NULL,
                           D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                           0x0,
                           1.0f,
                           0L
                         );

      m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );

      //空レンダリング
      D3DXMatrixIdentity( &matWorld );
      m_pLSS->Begin();
      //太陽の位置を取得
      D3DXVECTOR4 LightPos, LightDir;
      //太陽の位置を計算
      LightPos = D3DXVECTOR4( 0.0f, SunRadius * sinf( D3DXToRadian( SunRotation ) ), SunRadius * cosf( D3DXToRadian( SunRotation ) ), 0.0f );
      //太陽の方向ベクトルを計算
      LightDir = D3DXVECTOR4( -LightPos.x, -LightPos.y, -LightPos.z, LightPos.w );
      //太陽の方向ベクトルを正規化
      D3DXVec3Normalize( (D3DXVECTOR3*)&LightDir, (D3DXVECTOR3*)&LightDir );
      m_pLSS->SetMatrix( &matWorld, &LightDir );
      //雲テクスチャーをステージ1にセット
      m_pd3dDevice->SetTexture( 1, m_pCloudTexture );
      //星テクスチャーをステージ2にセット
      m_pd3dDevice->SetTexture( 2, m_pStarTexture );
      m_pLSS->BeginPass(0);
      m_pMeshBack->m_pLocalMesh->DrawSubset( 1 );
      m_pLSS->EndPass();
      m_pLSS->End();

      m_pd3dDevice->SetTexture( 1, NULL );
      m_pd3dDevice->SetTexture( 2, NULL );

      //太陽を固定機能パイプラインでレンダリング
      m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
      m_pd3dDevice->SetRenderState( D3DRS_BLENDOP,   D3DBLENDOP_ADD );
      m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
      m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
      m_pd3dDevice->SetTexture( 0, m_pMeshSun->m_pTextures[0] );

      D3DXMatrixTranslation( &matTranslation, LightPos.x, LightPos.y, LightPos.z );
      //ビルボードマトリックスを取得(ビルボード ページ参照)
      matWorld = GetBillBoardMatrix( m_pd3dDevice, &matTranslation );
      m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
      m_pMeshSun->m_pLocalMesh->DrawSubset( 0 );
      m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
      m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
      m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );

      //背景をレンダリング
      m_pLSS->Begin();
      D3DXMatrixIdentity( &matWorld );
      m_pLSS->SetMatrix( &matWorld, &LightDir );
      m_pd3dDevice->SetTexture( 1, m_pMeshBack->m_pTextures[0] );
      m_pLSS->SetAmbient( 0.1f );
      //フォグのパラメータを設定
      m_pLSS->SetParameters( 20.0f, 1.0f );
      //フォグの色を設定
      m_pLSS->SetFogColor( 1.0f );
      m_pLSS->BeginPass(1);
      m_pMeshBack->m_pLocalMesh->DrawSubset( 0 );
      m_pLSS->EndPass();
      m_pLSS->End();

      //トラをレンダリング
      m_pLSS->Begin();
      m_pLSS->SetMatrix( &matTiger, &LightDir );
      m_pd3dDevice->SetTexture( 1, m_pMeshTiger->m_pTextures[0] );
      m_pLSS->SetAmbient( 0.1f );
      m_pLSS->BeginPass(1);
      m_pMeshTiger->m_pLocalMesh->DrawSubset( 0 );
      m_pLSS->EndPass();
      m_pLSS->End();

      m_pd3dDevice->SetTexture( 1, NULL );

      m_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU,  D3DTADDRESS_WRAP );
      
      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;
}

以上です。

さーて一応できたので公開しましたが、問題がいろいろ。まず太陽の周辺のライトブルームがプロシージャルでありません。 「GAME Watch」の鬼武者3をみるとプロシージャルになるらしいですが、 まあこれは当サイトで紹介したライトブルーム その2を適応すれば対応できると思います。多分。

あと空の色が常に一色になります。実際には夕焼け時、太陽の周辺の空の色は赤くなりますが、太陽の位置から遠い場所の空の色は青っぽくなります。 これは空の厚み(大気の厚み)を考慮してないからです。これは対応すべきなんですが、方法が思いつかないです。

あと夜の空。雲が真っ黒になりますが、星の光で照らされるため真っ黒にはならないのではと思われます。 今、都心部にいるのでわからんけど、この辺も考慮すべきでしょうな。

Prev  Top  Next
inserted by FC2 system