浮動小数点数バッファ影


~ IEEE format shadow map ~






■はじめに

DirectX9 の新しい機能を使ってみましょう。
今回使ったのは、D3DFMT_R32F で、赤色成分に32ビット浮動小数点数を使います。
このフォーマットを使って固定機能でテクスチャを表示すると、他の成分には255が入って表示されます(左上の画像がそれです)。
シャドウマップでテクスチャフォーマットを浮動小数点数にしてみました。
結果からいうと、今回は失敗です。R8G8B8A8 と見た目が変わりませんでした。 ATI のデモのように、マルチサンプリングしてソフトシャドウにしていかないと違いが出ないかもしれません。
今回の見た目がきれいなのはシャドウマップのサイズが大きいからです。2048x2048x2(FB+Z)の32メガバイトのメモリを使っています。 これだけ使うと、パフォーマンスが非常に下がりますね。512x512 だと、270 FPS でたところが、2048x2048 だと、136 FPS に下がりました。

下のファイルがソースと実行ファイルです。
カーソルキーで上下左右に動かせますし、Z,Xでズームイン、アウトができます。

まぁ、いつものように適当にファイルが入っています。
ほとんどが APP WIZARD から出力されるファイルです。
以下のファイルの上から3つのファイル以外は無視してください。

shadowmap.fxシェーダの入ったエフェクトファイル
main.hアプリケーションのヘッダ
main.cppアプリケーションのソース
 
d3dapp.hアプリケーションの基底クラス
d3dapp.cppアプリケーションの基底クラス
dxutil.hSAFE_RELEASE とかの便利関数
dxutil.cppSAFE_RELEASE とかの便利関数
d3dutil.hカメラとかの便利クラス
d3dutil.cppカメラとかの便利クラス
d3denumeration.hデバイス管理の補助
d3denumeration.cppデバイス管理の補助
d3dfile.hメッシュの読み込み
d3dfile.cppメッシュの読み込み
d3dfont.hフォントの描画
d3dfont.cppフォントの描画
d3dsettings.hメニューによる設定
d3dsettings.cppメニューによる設定
diutil.h入力管理
diutil.cpp入力管理
dmutil.h音楽管理
dmutil.cpp音楽管理

あと、実行ファイル、表示用モデル及び、プロジェクトファイルが入っています。

■シェーダ

テクスチャフォーマット以外はシャドウマップそのままなので、 適当に解説を進めていきましょう。
シャドウマップは2パスのアルゴリズムなので、エフェクトファイルにパスごとのシェーダの設定をします。

shadowmap.fx
0112: // -------------------------------------------------------------
0113: // テクニック
0114: // -------------------------------------------------------------
0115: technique TShader
0116: {
0117:     pass P0
0118:     {
0119:         // シェーダ
0120:         VertexShader = compile vs_1_1 VS_pass0();
0121:         PixelShader  = <PS_pass0>;
0122:     }
0123:     pass P1
0124:     {
0125:         // シェーダ
0126:         VertexShader = compile vs_1_1 VS_pass1();
0127:         PixelShader  = compile ps_2_0 PS_pass1();
0128:         
0129:         Sampler[0] = (ShadowMapSamp);
0130:     }
0131: }

1パス目のピクセルシェーダは、アセンブリを使うことにしました。
2パス目に、いよいよシェーダ2.0の登場です。といっても、赤色成分だけを使うのが、 ピクセルシェーダ1.1では、できないからです。 テクスチャフォーマット的を、D3DFMT_R32Fじゃ無くて D3DFMT_A32F にしてくれれば何も問題なかったのに…。

あと、2パス目ではシャドウマップのテクスチャを使うので、 サンプリングステートの設定が必要になります。
必要なことは、テクスチャの名前(ここでは、ShadowMap)と、 あとは、拡大縮小フィルターなどのサンプリング法と、 範囲外のテクスチャ座標の時にクランプするかどうかなどです。

shadowmap.fx
0016: // -------------------------------------------------------------
0017: // テクスチャ
0018: // -------------------------------------------------------------
0019: texture ShadowMap;
0020: sampler ShadowMapSamp = sampler_state
0021: {
0022:     Texture = <ShadowMap>;
0023:     MinFilter = LINEAR;
0024:     MagFilter = LINEAR;
0025:     MipFilter = NONE;
0026: 
0027:     AddressU = Clamp;
0028:     AddressV = Clamp;
0029: };

では、シェーダプログラムを見ていきましょう。
頂点シェーダの出力構造体を次のようにします。

shadowmap.fx
0030: // -------------------------------------------------------------
0031: // 頂点シェーダからピクセルシェーダに渡すデータ
0032: // -------------------------------------------------------------
0033: struct VS_OUTPUT
0034: {
0035:     float4 Pos          : POSITION;
0036:     float4 Diffuse      : COLOR0;
0037:     float4 Ambient      : COLOR1;
0038:     float4 ShadowMapUV  : TEXCOORD0;
0039:     float4 Depth        : TEXCOORD1;
0040: };

どうも、VS_OUTPUT しか作れなかったので、2つのパスでの出力を同じ構造体にしています。
もしも、複数の構造体が作れないなら、同じ物体を記述するエフェクトファイルでも、 いくつかに分離するほうが良いかもしれません。

1パス目の頂点シェーダでは、ライトから見たカメラ座標系で座標変換して、 その位置を出力構造体の座標として出力すると共に、 スクリーン座標のZ値をテクスチャに埋め込むために、テクスチャ座標に出力します。

shadowmap.fx
0042: // -------------------------------------------------------------
0043: // 1パス目:頂点シェーダプログラム
0044: // -------------------------------------------------------------
0045: VS_OUTPUT VS_pass0(
0046:       float4 Pos    : POSITION,          // モデルの頂点
0047:       float3 Normal : NORMAL             // モデルの法線
0048: ){
0049:     VS_OUTPUT Out = (VS_OUTPUT)0;        // 出力データ
0050:     
0051:     // 座標変換
0052:     float4 pos = mul( Pos, mWLP );
0053:     
0054:     // 位置座標
0055:     Out.Pos = pos;
0056:     
0057:     // カメラ座標系での深度をテクスチャに入れる
0058:     Out.ShadowMapUV = pos.z / pos.w;
0059: 
0060:     return Out;
0061: }

ピクセルシェーダでは、受け取ったテクスチャ座標を texcoord 命令を使って、そのままレジスタに格納して、 その値を出力レジスタである、r0にいれます。
asm で始まるコードに、シェーダアセンブラをそのまま書くことができます。

shadowmap.fx
0062: // -------------------------------------------------------------
0063: // 1パス目:ピクセルシェーダプログラム
0064: // -------------------------------------------------------------
0065: PIXELSHADER PS_pass0 = 
0066: asm
0067: {
0068:     ps.1.1
0069:     
0070:     texcoord t0
0071:     
0072:     mov r0, t0  // テクスチャ座標を色として出力する
0073: };

2パス目では、シャドウマップをオブジェクトに貼り付けます。
今度の座用変換は、普通の座標変換です。
光源計算は、Lambert 拡散で、影になった部分を環境色にしますので、 ピクセルシェーダに環境色を拡散色を別々に送ります。
後は、先ほどのテクスチャを張るための座標変換を行い、求めたシャドウマップのテクスチャ座標と、 比較のために、先ほどと同じ様に求めた深度を(縞縞模様を防ぐバイアスをかませて)ピクセルシェーダに送ります。
このバイアスが浮動小数点数フォーマットの時には減らせるかなと思ったのですが、 やってみると、フォーマットの違いはありませんでした。

shadowmap.fx
0074: // -------------------------------------------------------------
0075: // 2パス目:頂点シェーダプログラム
0076: // -------------------------------------------------------------
0077: VS_OUTPUT VS_pass1(
0078:       float4 Pos    : POSITION,          // モデルの頂点
0079:       float3 Normal : NORMAL             // モデルの法線
0080: ){
0081:     VS_OUTPUT Out = (VS_OUTPUT)0;        // 出力データ
0082:     float4  uv;
0083:     
0084:     // 座標変換
0085:     Out.Pos = mul(Pos, mWVP);
0086:     // 色
0087:     Out.Diffuse = vCol * max( dot(vLightDir, Normal), 0);// 拡散色
0088:     Out.Ambient = vCol * 0.3f;                     // 環境色
0089:     
0090:     // テクスチャ座標
0091:     uv = mul(Pos, mWLPB);
0092:     Out.ShadowMapUV = uv;
0093:     uv = mul(Pos, mWLP);
0094:     Out.Depth       = uv.z / uv.w-0.003;
0095:         
0096:     return Out;
0097: }

ピクセルシェーダでは、透視変換しつつテクスチャの読み込みをして(これもシェーダ2.0の機能ですね)。
3項演算子?:で、影になっているか判定して、最後の色として出力します。

shadowmap.fx
0098: // -------------------------------------------------------------
0099: // 2パス目:ピクセルシェーダプログラム
0100: // -------------------------------------------------------------
0101: float4 PS_pass1(VS_OUTPUT In) : COLOR
0102: {   
0103:     float4 Color = In.Ambient;
0104:     float4 zero = {0,0,0,0};
0105:     
0106:     float  shadow_map = tex2Dproj( ShadowMapSamp, In.ShadowMapUV ).x;
0107:     
0108:     Color += (shadow_map < In.Depth.z) ? zero : In.Diffuse;
0109: 
0110:     return Color;
0111: }  

あと、書き忘れましたが、グローバル変数

shadowmap.fx
0010: float4x4 mWVP;      // ローカルから射影空間への座標変換
0011: float4x4 mWLP;      // ローカルから射影空間への座標変換
0012: float4x4 mWLPB;     // テクスチャ座標系への射影
0013: float4   vCol;      // メッシュの色
0014: float4   vLightDir; // ライトの方向

を使いました。

■オブジェクト

シャドウマップ使うためのオブジェクトは、エフェクトファイルのオブジェクトおよび、 グローバル変数のハンドルオブジェクトが必要になります。
実際のレンダリングには、それ以外にも、モデルを表示するメッシュのクラス(d3dfile.hのものを使用)や、 シャドウマップのためのテクスチャや深度バッファが必要になります。 座標変換のための行列やライトの位置も持ちます。

main.h
0032: //-----------------------------------------------------------------------------
0033: // Name: class CMyD3DApplication
0034: // Desc: Application class. The base class (CD3DApplication) provides the 
0035: //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
0036: //       adds functionality specific to this sample program.
0037: //-----------------------------------------------------------------------------
0038: class CMyD3DApplication : public CD3DApplication
0039: {
0040:     CD3DMesh                *m_pMeshCar;
0041:     CD3DMesh                *m_pMeshChess;
0042:             
0043:     // シェーダ
0044:     LPD3DXEFFECT     m_pFx;     // シェーダが書かれたエフェクト
0045:     D3DXHANDLE       m_hmWVP;   // ワールド×ビュー×射影行列
0046:     D3DXHANDLE       m_hmWLP;   // ライト方向からの変換行列
0047:     D3DXHANDLE       m_hmWLPB;  // ライト方向からの変換行列
0048:     D3DXHANDLE       m_hvCol;   // メッシュの色
0049:     D3DXHANDLE       m_hvDir;   // ライトの方向
0050: 
0051: 
0052:     // シャドウマップ
0053:     LPDIRECT3DTEXTURE9      m_pShadowMap;
0054:     LPDIRECT3DSURFACE9      m_pShadowMapSurf;
0055:     LPDIRECT3DSURFACE9      m_pShadowMapZ;
0056: 
0057:     // 通常の座標変換行列
0058:     D3DXMATRIX              m_mWorld;
0059:     D3DXMATRIX              m_mView;
0060:     D3DXMATRIX              m_mProj;
0061:     D3DXMATRIX              m_mLightVP;
0062: 
0063:     D3DXVECTOR3             m_LighPos;      // 光源の方向
中略
0073: 
0074:     VOID DrawModel( int pass ); // 各パスで呼ばれるモデルの描画
後略

■能力チェック

頂点シェーダやピクセルシェーダを使うときには、 シェーダのバージョンを気にする必要があります。
今回は、頂点シェーダ1.1と、ピクセルシェーダ2.0をつかうので、 それらの条件を満たしているか調べます。
AppWizard を使ったときには、ConfirmDevice が、能力を調べるときなので、 この関数にチェックルーチンを仕込みます。

main.cpp
0154: //-----------------------------------------------------------------------------
0155: // Name: ConfirmDevice()
0156: // Desc: Called during device initialization, this code checks the display device
0157: //       for some minimum set of capabilities
0158: //-----------------------------------------------------------------------------
0159: HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS9* pCaps, DWORD dwBehavior,
0160:                                           D3DFORMAT Format )
0161: {
0162:     UNREFERENCED_PARAMETER( Format );
0163:     UNREFERENCED_PARAMETER( dwBehavior );
0164:     UNREFERENCED_PARAMETER( pCaps );
0165:     
0166:     BOOL bCapsAcceptable;
0167: 
0168:     // TODO: Perform checks to see if these display caps are acceptable.
0169:     bCapsAcceptable = TRUE;
0170: 
0171:     // ピクセルシェーダバージョンチェック
0172:     if( pCaps->PixelShaderVersion < D3DPS_VERSION(2,0) )
0173:         bCapsAcceptable = FALSE;
0174: 
0175:     // 頂点シェーダバージョンが上位かソフトウェア頂点処理
0176:     if( pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
0177:         if( (dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING ) == 0 )
0178:             bCapsAcceptable = FALSE;
0179: 
0180:     if( bCapsAcceptable )         
0181:         return S_OK;
0182:     else
0183:         return E_FAIL;
0184: }

■初期化

デバイスが使えることが分かったら、いよいよ初期化して使います。
最初だけ初期化すればいいものに、メッシュやエフェクトファイルの読み込みがあります。
メッシュの初期化は、フレームワークの方に読み込みメソッドがあるので、そちらを使用します。
シェーダは、D3DXCreateEffectFromFile で読み込みます。
シェーダ内のグローバル変数は、GetParameterByName で、名前を使ってハンドルが得られるようなので、 そちらを使いました。

main.cpp
0221: HRESULT CMyD3DApplication::InitDeviceObjects()
0222: {
0223:     HRESULT hr;
0224: 
0225:     // 車の読み込み
0226:     if( FAILED( hr = m_pMeshCar->Create( m_pd3dDevice, _T("car.x") )))
0227:         return DXTRACE_ERR( "LoadCar", hr );
0228:     m_pMeshCar->UseMeshMaterials(FALSE);// レンダリング時にテクスチャの設定をしない
0229:     // 地面の読み込み
0230:     if( FAILED( hr = m_pMeshChess->Create( m_pd3dDevice, _T("chess.x") )))
0231:         return DXTRACE_ERR( "LoadChess", hr );
0232:     m_pMeshChess->UseMeshMaterials(FALSE);// レンダリング時にテクスチャの設定をしない
0233: 
0237:     // シェーダの読み込み
0238:     if( FAILED( D3DXCreateEffectFromFile( m_pd3dDevice, "shadowmap.fx", NULL, NULL, 
0239:                                         0, NULL, &m_pFx, NULL ) ) ) return E_FAIL;
0240:     m_hmWVP = m_pFx->GetParameterByName( NULL, "mWVP" );
0241:     m_hmWLP = m_pFx->GetParameterByName( NULL, "mWLP" );
0242:     m_hmWLPB= m_pFx->GetParameterByName( NULL, "mWLPB" );
0243:     m_hvCol = m_pFx->GetParameterByName( NULL, "vCol" );
0244:     m_hvDir = m_pFx->GetParameterByName( NULL, "vLightDir" );
0245: 
0246:     return S_OK;
0247: }

あと、シャドウマップの初期化も必要です。
CreateTexture で、生成したり、この辺は、DirectX8 と同じです。

main.cpp
0026: #define SHADOW_MAP_FORMAT D3DFMT_R32F
0028: #define SHADOW_MAP_SIZE   2048
0308:     // シャドウマップの生成
0309:     if (FAILED(m_pd3dDevice->CreateTexture(SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, 
0310:         D3DUSAGE_RENDERTARGET, SHADOW_MAP_FORMAT, D3DPOOL_DEFAULT, &m_pShadowMap, NULL)))
0311:         return E_FAIL;
0312:     if (FAILED(m_pShadowMap->GetSurfaceLevel(0, &m_pShadowMapSurf)))
0313:         return E_FAIL;
0314:     if (FAILED(m_pd3dDevice->CreateDepthStencilSurface(SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 
0315:         D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pShadowMapZ, NULL)))
0316:         return E_FAIL;

■描画

さて、いよいよ描画です。
最初にライトからみた射影空間への行列を作ります。
それ以外の行列は、ほかであらかじめ作っておきます。

main.cpp
0497: HRESULT CMyD3DApplication::Render()
0498: {
0499:     D3DXMATRIX mLP, mView, mProj;
0500:     LPDIRECT3DSURFACE9 pOldBackBuffer, pOldZBuffer;
0501:     D3DVIEWPORT9 oldViewport;
0502: 
0503:     //-------------------------------------------------------------------------
0504:     // 行列の作成
0505:     //-------------------------------------------------------------------------
0506:     // ライト方向から見た射影空間への行列
0507:     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
0508:     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0509:     D3DXMatrixLookAtLH( &mView, &m_LighPos, &vLookatPt, &vUpVec );
0510:     D3DXMatrixPerspectiveFovLH( &mProj
0511:                             , 0.21f*D3DX_PI     // 視野角
0512:                             , 1.0f              // アスペクト比
0513:                             , 5.0f, 12.0f );    // near far
0514:     m_mLightVP = mView * mProj;

次に、描画を開始します。
BeginScene の後に、エフェクトファイルによるシェーダのレンダリングに切り替えます。

main.cpp
0516:     //-------------------------------------------------------------------------
0517:     // 描画
0518:     //-------------------------------------------------------------------------
0519:     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
0520:     {
0521:         if( m_pFx != NULL ) 
0522:         {
0523:             //-------------------------------------------------------------------------
0524:             // シェーダの設定
0525:             //-------------------------------------------------------------------------
0526:             D3DXHANDLE hTechnique = m_pFx->GetTechniqueByName( "TShader" );
0527:             m_pFx->SetTechnique( hTechnique );
0528:             m_pFx->Begin( NULL, 0 );

次に、レンダリングターゲットをシャドウマップに切り替えます。
その後は、エフェクトファイルの1つめのパス m_pFx->Pass(0) でモデルを描画します。

main.cpp
0530:             //-------------------------------------------------------------------------
0531:             // レンダリングターゲットの保存
0532:             //--------------------------------------------------------------------------
0533:             m_pd3dDevice->GetRenderTarget(0, &pOldBackBuffer);
0534:             m_pd3dDevice->GetDepthStencilSurface(&pOldZBuffer);
0535:             m_pd3dDevice->GetViewport(&oldViewport);
0536: 
0537:             //-------------------------------------------------------------------------
0538:             // レンダリングターゲットの変更
0539:             //--------------------------------------------------------------------------
0540:             m_pd3dDevice->SetRenderTarget(0, m_pShadowMapSurf);
0541:             m_pd3dDevice->SetDepthStencilSurface(m_pShadowMapZ);
0542:             // ビューポートの変更    x y       width         height       minz maxz
0543:             D3DVIEWPORT9 viewport = {0,0, SHADOW_MAP_SIZE,SHADOW_MAP_SIZE,0.0f,1.0f};
0544:             m_pd3dDevice->SetViewport(&viewport);
0545: 
0546:             // シャドウマップのクリア
0547:             m_pd3dDevice->Clear(0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0548:                                 0xFFFFFFFF, 1.0f, 0L);
0549: 
0550:             //-----------------------------------------------------------------------------
0551:             // 1パス目:シャドウマップの作成
0552:             //-----------------------------------------------------------------------------
0553:             m_pFx->Pass( 0 );
0554:             DrawModel( 0 );

2パス目では、レンダリングターゲットをフレームバッファに戻した後に、 テクスチャを設定してから、2パス目のm_pFx->Pass( 1 )で描画します。

main.cpp
0556:             //-------------------------------------------------------------------------
0557:             // レンダリングターゲットを元に戻す
0558:             //--------------------------------------------------------------------------
0559:             m_pd3dDevice->SetRenderTarget(0, pOldBackBuffer);
0560:             m_pd3dDevice->SetDepthStencilSurface(pOldZBuffer);
0561:             m_pd3dDevice->SetViewport(&oldViewport);
0562:             pOldBackBuffer->Release();
0563:             pOldZBuffer->Release();
0564: 
0565:             //-----------------------------------------------------------------------------
0566:             // 2パス目:シーンの描画
0567:             //-----------------------------------------------------------------------------
0568:             // バッファのクリア
0569:             m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
0570:                                 0x00404080, 1.0f, 0L );
0571: 
0572:             //-------------------------------------------------------------------------
0573:             // 描画
0574:             //--------------------------------------------------------------------------
0575:             m_pFx->SetTexture("ShadowMap", m_pShadowMap);// テクスチャの設定
0576:             m_pFx->Pass( 1 );
0577:             DrawModel( 1 );

最後に、エフェクトファイルによるレンダリングを終了して、EndScene で閉じます。

main.cpp
0579:             m_pFx->End();
0580:         }
0581: 
0606:         // 描画の終了
0607:         m_pd3dDevice->EndScene();
0608:     }
0609: 
0610:     return S_OK;
0611: }

■オブジェクトのレンダリング

モデルの描画では、シャドウマップを張るために、射影空間からへクスチャ座標に変換するための行列 mScaleBias を作って、モデルを描画します。

main.cpp
0388: //-----------------------------------------------------------------------------
0389: // 各モデルの描画
0390: //-----------------------------------------------------------------------------
0391: VOID CMyD3DApplication::DrawModel( int pass )
0392: {
0393:     D3DXMATRIX m, mL, mS, mT, mR;
0394:     D3DXVECTOR3 vDir;
0395:     D3DXVECTOR4 v;
0396:     D3DMATERIAL9 *pMtrl;
0397:     DWORD i;
0398:     
0399:     //-------------------------------------------------------------------------
0400:     // 行列の生成
0401:     //-------------------------------------------------------------------------
0402:     D3DXMATRIX mVP = m_mWorld * m_mView * m_mProj;
0403:     
0404:     // 射影空間から、テクスチャーの空間に変換する
0405:     float fOffsetX = 0.5f + (0.5f / (float)SHADOW_MAP_SIZE);
0406:     float fOffsetY = 0.5f + (0.5f / (float)SHADOW_MAP_SIZE);
0407:     D3DXMATRIX mScaleBias(  0.5f,     0.0f,     0.0f,   0.0f,
0408:                             0.0f,    -0.5f,     0.0f,   0.0f,
0409:                             0.0f,     0.0f,     0.0f,   0.0f,
0410:                             fOffsetX, fOffsetY, 0.0f,   1.0f );

モデルの描画には、パスごとに必要な行列やベクトルを設定して描画します。
メッシュの部位ごとに色を塗るので、DrawSubset を別々に呼びます。

main.cpp
0412:     //-------------------------------------------------------------------------
0413:     // 車
0414:     //-------------------------------------------------------------------------
0415:     // ワールド行列の生成
0416:     D3DXMatrixScaling( &mS, 0.05f, 0.05f, 0.05f );
0417:     D3DXMatrixTranslation( &mT, 1.0f, 0.0f ,0.0f );
0419:     D3DXMatrixRotationY( &mR, m_fTime );
0420:     mL = mS * mT * mR;
0421:     switch(pass){
0422:     case 0:// シャドウマップの作成
0423:         m = mL * m_mLightVP;
0424:         if( m_hmWLP != NULL ) m_pFx->SetMatrix( m_hmWLP, &m );
0425:         m_pMeshCar  ->Render( m_pd3dDevice );// 描画
0426:         break;
0427:     default:// シーンの描画
0428:         m = mL * mVP;
0429:         if( m_hmWVP != NULL ) m_pFx->SetMatrix( m_hmWVP, &m );
0430:         m = mL * m_mLightVP;
0431:         if( m_hmWLP != NULL ) m_pFx->SetMatrix( m_hmWLP, &m );
0432:         m = m * mScaleBias;
0433:         if( m_hmWLPB != NULL ) m_pFx->SetMatrix( m_hmWLPB, &m );
0434:         D3DXMatrixInverse( &m, NULL, &mL);
0435:         D3DXVec3Transform( &v, &m_LighPos, &m );
0436:         D3DXVec4Normalize( &v, &v );v.w = 0;
0437:         if( m_hvDir != NULL ) m_pFx->SetVector( m_hvDir, &v );
0438: 
0439:         pMtrl = m_pMeshCar->m_pMaterials;
0440:         for( i=0; i<m_pMeshCar->m_dwNumMaterials; i++ ) {
0441:             v.x = pMtrl->Diffuse.r;
0442:             v.y = pMtrl->Diffuse.g;
0443:             v.z = pMtrl->Diffuse.b;
0444:             v.w = pMtrl->Diffuse.a;
0445:             if( m_hvCol != NULL ) m_pFx->SetVector( m_hvCol, &v );
0446:             m_pMeshCar->m_pLocalMesh->DrawSubset( i );  // 描画
0447:             pMtrl++;
0448:         }
0449:         break;
0450:     }
0451: 
0452:     //-------------------------------------------------------------------------
0453:     // 地形
0454:     //-------------------------------------------------------------------------
中略
0488: }

■最後に

うーん、違いが出なかったところが残念でした。
今回はテクスチャの解像度が画質に大きく影響しました。
それにしても、256ビットでも綺麗に出たのは不思議ですね。
昔はもっとバイアスを大きくしないと上手くいかなかった気がするのですが…





もどる

imagire@gmail.com