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.h | SAFE_RELEASE とかの便利関数 |
dxutil.cpp | SAFE_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ビットでも綺麗に出たのは不思議ですね。
昔はもっとバイアスを大きくしないと上手くいかなかった気がするのですが…