「スキンメッシュアニメーション」の編集履歴(バックアップ)一覧はこちら
「スキンメッシュアニメーション」(2009/05/10 (日) 14:49:07) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
<p>DirectXの最初の難関、スキンメッシュアニメーション。<br />
学習方法は人それぞれですがSDKサンプルのSkinnedMesh.cppからヘルパーライブラリDXUTの関数を外していく<br />
方向でソースファイルを短くすると解りやすいかも知れません。</p>
<p><img alt="" src="http://www36.atwiki.jp/directx?cmd=upload&act=open&pageid=33&file=dxs.PNG" /></p>
<p>SkinnedMesh.cpp</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//スキンメッシュアニメーション<br />
//--------------------------------------------------------------------------------------<br />
#include "d3dx9.h"<br />
#include "SkinnedMesh.h"<br />
LPDIRECT3D9 g_pD3D = NULL;//Direct3D9<br />
LPDIRECT3DDEVICE9 pd3dDevice = NULL;//レンダリングデバイス</font></p>
<p><br /><font size="2">HWND hWnd;<br />
#define MESHFILENAME L"soldier.x"</font></p>
<p><font size="2">float timef=0.0f;<br /></font></p>
<p><font size="2">HRESULT Init()<br />
{<br />
//Direct3Dを生成する<br />
if(NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))){return E_FAIL;}</font></p>
<p><font size="2"> //デバイス生成用のパラメーター<br />
D3DPRESENT_PARAMETERS d3dpp;//パラメーター構造体<br />
ZeroMemory( &d3dpp, sizeof(d3dpp) );//ゼロで初期化<br />
d3dpp.Windowed = TRUE;//ウインドウモードで起動<br />
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//バックバッファのスワップエフェクト
Direct3Dにスワップエフェクトをまかせる<br />
d3dpp.BackBufferFormat =
D3DFMT_UNKNOWN;//バックバッファのフォーマット今表示されているモニタの設定と同じ<br />
d3dpp.BackBufferCount = 1;//バックバッファの数<br />
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;//マルチサンプリングは行わない<br />
d3dpp.MultiSampleQuality = 0;//マルチサンプリングは行わないので0<br />
d3dpp.EnableAutoDepthStencil = TRUE;//Direct3Dに深度バッファの管理をまかせる<br />
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//深度バッファのフォーマット(通常はこの値で問題ない)<br />
d3dpp.hDeviceWindow = hWnd;//カバーウィンドウ=アプリケーションのウィンドウ<br />
d3dpp.Flags = 0;//フラグは使わない<br />
d3dpp.FullScreen_RefreshRateInHz =
D3DPRESENT_RATE_DEFAULT;//今のリフレッシュレートをそのまま使う<br />
d3dpp.PresentationInterval =
D3DPRESENT_INTERVAL_DEFAULT;//モニタの垂直回帰を待つ</font></p>
<p><font size="2"> //Direct3Dデバイスの生成 HAL(ハードウェアアクセラレーション)<br />
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){<br />
//HALが駄目ならHEL(ソフトウェアエミュレーション)<br />
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){<br />
//駄目なら終了<br />
return(E_FAIL);<br />
}<br />
}<br />
// Zバッファー処理を有効にする<br />
pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );<br />
// ライトを有効にする<br />
pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );<br />
// アンビエントライト(環境光)を設定する<br />
pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00111111 );<br />
// スペキュラ(鏡面反射)を有効にする<br />
pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE,TRUE);</font></p>
<p><font size="2"> CAllocateHierarchy Alloc;</font></p>
<p><font size="2"> //シェーダーファイル読み込み</font></p>
<p><font size="2"> D3DXCreateEffectFromFileW( pd3dDevice, L"SkinnedMesh.fx",
NULL, NULL, D3DXSHADER_DEBUG,NULL, &g_pEffect, NULL );<br />
//メッシュ読み込み<br />
//WCHAR str[MAX_PATH];<br />
//MtoW(str,MESHFILENAME,MAX_PATH);</font></p>
<p><font size="2"> D3DXLoadMeshHierarchyFromXW( MESHFILENAME, D3DXMESH_MANAGED,
pd3dDevice,&Alloc, NULL, &g_pFrameRoot, &g_pAnimController );<br />
SetupBoneMatrixPointers( g_pFrameRoot );<br />
D3DXFrameCalculateBoundingSphere( g_pFrameRoot, &g_vObjectCenter,
&g_fObjectRadius );</font></p>
<p><font size="2"> //ビヘイビアフラグを得てください<br />
D3DDEVICE_CREATION_PARAMETERS cp;<br />
pd3dDevice->GetCreationParameters( &cp );<br />
g_dwBehaviorFlags = cp.BehaviorFlags;</font></p>
<p><font size="2"> //セットアップ レンダーステート<br />
pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );<br />
pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );<br />
pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );<br />
pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );<br />
pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR
);</font></p>
<p><br /><font size="2"> for( DWORD iInfl = 0; iInfl < 4; ++iInfl )<br />
{<br />
LPD3DXBUFFER pCode;</font></p>
<p><font size="2"> //頂点シェーダーアセンブル<br />
D3DXAssembleShaderFromFileW( ShaderSource[iInfl], NULL, NULL,
D3DXSHADER_DEBUG, &pCode, NULL );</font></p>
<p><font size="2"> //頂点シェーダー生成<br />
pd3dDevice->CreateVertexShader(
(DWORD*)pCode->GetBufferPointer(),&g_pIndexedVertexShader[iInfl]
);</font></p>
<p><font size="2"> pCode->Release();<br />
}</font></p>
<p><font size="2"> //セットアップ プロジェクションマトリックス<br />
float fAspect = (float)640.0f / (float)480.0f;<br />
D3DXMatrixPerspectiveFovLH( &g_matProj, D3DX_PI/4, fAspect,<br />
g_fObjectRadius/64.0f, g_fObjectRadius*200.0f
);<br />
pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj );<br />
D3DXMatrixTranspose( &g_matProjT, &g_matProj );<br />
return true;<br />
}</font></p>
<p><font size="2">void MainLoop()<br />
{</font></p>
<p><font size="2"> HRESULT hr;</font></p>
<p><font size="2"> //バックバッファ<br />
pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,<br />
D3DCOLOR_ARGB(0, 255, 255, 255), 1.0f, 0L
);</font></p>
<p><font size="2"> //セットアップ ワールドマトリクス<br />
D3DXMATRIXA16 matWorld;<br />
D3DXMatrixTranslation( &matWorld, -g_vObjectCenter.x,<br />
-g_vObjectCenter.y,<br />
-g_vObjectCenter.z );<br />
pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );</font></p>
<p><font size="2"> D3DXVECTOR3 vEye( 150, 10, -2*g_fObjectRadius );<br />
D3DXVECTOR3 vAt( 0, 10, 0 );<br />
D3DXVECTOR3 vUp( 0, 1, 0 );<br />
D3DXMatrixLookAtLH( &g_matView, &vEye, &vAt,
&vUp);</font></p>
<p><font size="2"> pd3dDevice->SetTransform( D3DTS_VIEW, &g_matView
);</font></p>
<p><font size="2"> if( g_pAnimController != NULL )<br />
g_pAnimController->AdvanceTime( 0.03f, NULL );</font></p>
<p><font size="2"> UpdateFrameMatrices( g_pFrameRoot, &matWorld
);</font></p>
<p><font size="2"> //ライトセットアップ<br />
D3DLIGHT9 light;<br />
D3DXVECTOR3 vecLightDirUnnormalized(0.0f, -1.0f, 1.0f);<br />
ZeroMemory( &light, sizeof(D3DLIGHT9) );<br />
light.Type = D3DLIGHT_DIRECTIONAL;<br />
light.Diffuse.r = 1.0f;<br />
light.Diffuse.g = 1.0f;<br />
light.Diffuse.b = 1.0f;<br />
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction,
&vecLightDirUnnormalized );<br />
light.Position.x = 0.0f;<br />
light.Position.y = -1.0f;<br />
light.Position.z = 1.0f;<br />
light.Range = 1000.0f;<br />
V( pd3dDevice->SetLight(0, &light ) );<br />
V( pd3dDevice->LightEnable(0, TRUE ) );</font></p>
<p><font size="2"> //プロジェクションセット<br />
if( g_SkinningMethod == D3DINDEXEDVS )<br />
{<br />
V( pd3dDevice->SetVertexShaderConstantF( 2, (float*)&g_matProjT,
4 ) );<br />
}<br />
else<br />
if( g_SkinningMethod == D3DINDEXEDHLSLVS )<br />
{<br />
V( g_pEffect->SetMatrix( "mViewProj", &g_matProj ) );<br />
}</font></p>
<p><font size="2"> //セットライト<br />
D3DXVECTOR4 vLightDir( 0.0f, 1.0f, -1.0f, 0.0f );<br />
D3DXVec4Normalize( &vLightDir, &vLightDir );<br />
V( pd3dDevice->SetVertexShaderConstantF(1, (float*)&vLightDir, 1)
);<br />
V( g_pEffect->SetVector( "lhtDir", &vLightDir) );</font></p>
<p><font size="2"> //ビギンシーン<br />
if( SUCCEEDED( pd3dDevice->BeginScene() ) )<br />
{<br />
DrawFrame( pd3dDevice, g_pFrameRoot );</font></p>
<p><font size="2"> //シーンエンド<br />
pd3dDevice->EndScene();<br />
}<br />
pd3dDevice->Present( NULL, NULL, NULL, NULL );<br />
Sleep(10);<br />
}</font></p>
<p><font size="2">//メッセージプロシージャ<br />
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )<br />
{<br />
switch( msg )<br />
{<br />
case WM_DESTROY://終了時<br />
PostQuitMessage(0);<br />
return 0;<br />
case WM_PAINT://ウインドウ描画時<br />
MainLoop();<br />
return 0;<br />
case WM_SIZE://ウインドウサイズ変更時<br />
InvalidateRect(hWnd,NULL,true);//画面更新<br />
return 0;<br />
}</font></p>
<p><font size="2"> return DefWindowProc( hWnd, msg, wParam, lParam );<br />
}<br />
//--------------------------------------------------------------------------------------<br />
//メイン<br />
//--------------------------------------------------------------------------------------<br />
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )<br />
{<br />
//ウインドウクラスの登録<br />
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,<br />
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,<br />
"Window1", NULL };<br />
RegisterClassEx( &wc );</font></p>
<p><font size="2"> //タイトルバーとウインドウ枠の分を含めてウインドウサイズを設定<br />
RECT rect;<br />
SetRect(&rect,0,0,640,480);<br />
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);<br />
rect.right=rect.right-rect.left;<br />
rect.bottom=rect.bottom-rect.top;<br />
rect.top=0;<br />
rect.left=0;</font></p>
<p><font size="2"> //ウインドウの生成<br />
hWnd = CreateWindow( "Window1", "Hello DirectX9 World !!",<br />
WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, rect.right, rect.bottom,<br />
NULL, NULL, wc.hInstance, NULL );</font></p>
<p><font size="2"> Init();<br />
//頂点シェーダー解放<br />
for( DWORD iInfl = 0; iInfl < 4; ++iInfl )<br />
SAFE_RELEASE( g_pIndexedVertexShader[iInfl] );</font></p>
<p><font size="2"> ShowWindow(hWnd,SW_SHOWDEFAULT);<br />
UpdateWindow(hWnd);</font></p>
<p><font size="2"> //メッセージループ<br />
MSG msg;<br />
while( GetMessage(&msg,NULL,0,0))<br />
{<br />
TranslateMessage(&msg);<br />
DispatchMessage(&msg);<br />
}</font></p>
<p><br /><font size="2"> UnregisterClass("Window1",wc.hInstance);</font></p>
<p><font size="2"> ReleaseAttributeTable( g_pFrameRoot );<br />
delete[] g_pBoneMatrices;</font></p>
<p><font size="2"> SAFE_RELEASE( g_pEffect );</font></p>
<p><font size="2"> CAllocateHierarchy Alloc;<br />
D3DXFrameDestroy( g_pFrameRoot, &Alloc );<br />
SAFE_RELEASE( g_pAnimController );<br />
return 0;<br />
}</font></p>
</td>
</tr></tbody></table><p> </p>
<p><font size="2">SkinnedMesh.h</font></p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">#define V(x) { hr = (x); }<br />
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }<br />
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }<br />
#define
SAFE_RELEASE(p) {if(p){(p)->Release();(p)=NULL;}}//安全に解放する</font></p>
<p><font size="2">// 様々なスキニングモードを可能にするための列挙<br />
enum METHOD<br />
{<br />
D3DNONINDEXED,//ノンインデックス<br />
D3DINDEXED,//インデックス<br />
SOFTWARE,//ソフトウェア<br />
D3DINDEXEDVS,//インデックスVS<br />
D3DINDEXEDHLSLVS,//インデックスHLSLVS<br />
NONE//スキニング無し<br />
};</font></p>
<p><font size="2">//フレーム構造体<br />
struct D3DXFRAME_DERIVED: public D3DXFRAME<br />
{<br />
D3DXMATRIXA16 CombinedTransformationMatrix;<br />
};</font></p>
<p><font size="2">//メッシュコンテナ構造体<br />
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER<br />
{<br />
LPDIRECT3DTEXTURE9* ppTextures;//テクスチャーの配列、テクスチャーがなかったらNULL <br />
<br />
//スキンメッシュ情報 <br />
LPD3DXMESH pOrigMesh;//メッシュ<br />
LPD3DXATTRIBUTERANGE pAttributeTable;//属性<br />
DWORD NumAttributeGroups;//属性のグループ<br />
DWORD NumInfl;<br />
LPD3DXBUFFER pBoneCombinationBuf;//ボーンの組み合わせバッファ<br />
D3DXMATRIX** ppBoneMatrixPtrs;//ボーンマトリクスポインタ<br />
D3DXMATRIX* pBoneOffsetMatrices;//ボーンオフセットマトリクス<br />
DWORD NumPaletteEntries;//パレットエントリー<br />
bool UseSoftwareVP;//ソフトウェアVPを使う<br />
DWORD
iAttributeSW;//ノンインデックススキニングならソフトウェアとハードウェアで分けて指定する必要がある<br />
};</font></p>
<p><font size="2">//階層割り当てクラス<br />
class CAllocateHierarchy: public ID3DXAllocateHierarchy<br />
{<br />
public:<br />
STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME
*ppNewFrame);//フレーム作成<br />
STDMETHOD(CreateMeshContainer)(THIS_ //メッシュコンテナ作成<br />
LPCSTR Name, //名前<br />
CONST D3DXMESHDATA *pMeshData,//メッシュデータ<br />
CONST D3DXMATERIAL *pMaterials, //マテリアル<br />
CONST D3DXEFFECTINSTANCE *pEffectInstances, //エフェクトの実体<br />
DWORD NumMaterials, //マテリアル数<br />
CONST DWORD *pAdjacency, //隣接関係<br />
LPD3DXSKININFO pSkinInfo, //スキン情報<br />
LPD3DXMESHCONTAINER *ppNewMeshContainer);//メッシュコンテナのポインタ<br />
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);//フレーム削除<br />
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER
pMeshContainerBase);//メッシュコンテナ削除</font></p>
<p><font size="2"> CAllocateHierarchy() {}<br />
};</font></p>
<p><font size="2">WCHAR ShaderSource[4][30] =<br />
{<br />
L"skinmesh1.vsh",<br />
L"skinmesh2.vsh",<br />
L"skinmesh3.vsh",<br />
L"skinmesh4.vsh"<br />
};</font></p>
<p><br /><font size="2">//グローバル変数<br />
ID3DXEffect* g_pEffect = NULL; //エフェクトインターフェース<br />
LPD3DXFRAME g_pFrameRoot = NULL; //フレームルート<br />
ID3DXAnimationController* g_pAnimController = NULL;//アニメーションコントローラー<br />
D3DXVECTOR3 g_vObjectCenter; //オブジェクトのバウンディングスフィアの中心<br />
FLOAT g_fObjectRadius; //オブジェクトのバウンディングスフィアの半径<br />
METHOD g_SkinningMethod = D3DNONINDEXED;
//現在のスキニングメソッド、ノンインデックス<br />
D3DXMATRIXA16* g_pBoneMatrices = NULL;//ボーンマトリックス<br />
UINT g_NumBoneMatricesMax = 0;//ボーンマトリックスの最大数<br />
IDirect3DVertexShader9* g_pIndexedVertexShader[4];//頂点シェーダー<br />
D3DXMATRIXA16 g_matView; //ビュー行列<br />
D3DXMATRIXA16 g_matProj; //プロジェクション行列<br />
D3DXMATRIXA16 g_matProjT; //asmシェーダー用<br />
DWORD g_dwBehaviorFlags; //ビヘイビアフラグ<br />
bool g_bUseSoftwareVP;
//ソフトウェアVPフラグ、ハードウェアが無かった時のために必要</font></p>
<p><font size="2">HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR*
strFileName, ID3DXMesh** ppMesh );//メッシュロード<br />
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase );//メッシュコンテナー描画<br />
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame
);//フレーム描画<br />
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainer
);//メッシュコンテナのボーンマトリクスポインター<br />
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );//フレームのボーンマトリクスポインター<br />
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
);//フレームマトリクスの更新<br />
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice,LPD3DXFRAME
pFrameBase );//スキニングメソッドの更新<br />
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer );//スキニングメッシュの生成<br />
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase
);//アトリビュートテーブルの解放</font></p>
<p><font size="2">void MtoW(WCHAR * lpuni, LPSTR lpsjis, int buffersize)<br />
{<br />
int len =
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpsjis,-1,NULL,0);</font></p>
<p><font size="2"> if (buffersize) {<br />
//必要な文字数がバッファサイズより大きい場合はバッファイサイズ分を返還<br />
if (len > buffersize-1) len = buffersize-1;<br />
}</font></p>
<p><font size="2"> MultiByteToWideChar(<br />
CP_ACP, // ANSI Code Page (MBCS/マルチバイト文字)<br />
MB_PRECOMPOSED, // 既定変換方法<br />
lpsjis, // 変換元文字列<br />
-1, // 変換元文字列サイズ(-1指定で自動計算)(pInはゼロ終端であること)<br />
lpuni, // 変換先バッファ<br />
len); // 変換先バッファサイズ<br />
}</font></p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//割り当て名:フレームかメッシュ<br />
//--------------------------------------------------------------------------------------<br />
HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName )<br />
{<br />
UINT cbLength;</font></p>
<p><font size="2"> if( Name != NULL )//名前が存在するなら<br />
{<br />
cbLength = (UINT)strlen(Name) + 1;//名前の文字数+1<br />
*pNewName = new CHAR[cbLength];//名前用メモリ確保<br />
if (*pNewName == NULL)//確保できなかったら<br />
return E_OUTOFMEMORY;//エラー<br />
memcpy( *pNewName, Name, cbLength*sizeof(CHAR) );//Nameをコピー<br />
}<br />
else//名前が存在しなかったらNULL<br />
{<br />
*pNewName = NULL;<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//階層割り当て:フレーム作成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME *ppNewFrame
)<br />
{<br />
HRESULT hr = S_OK;<br />
D3DXFRAME_DERIVED *pFrame;//フレーム</font></p>
<p><font size="2"> *ppNewFrame = NULL;</font></p>
<p><font size="2"> pFrame = new D3DXFRAME_DERIVED;<br />
if (pFrame == NULL)//フレームが作成できなかったら<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> hr = AllocateName(Name,
&pFrame->Name);//割り当て名を設定<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //フレームの部品を初期化<br />
D3DXMatrixIdentity(&pFrame->TransformationMatrix);<br />
D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);</font></p>
<p><font size="2"> pFrame->pMeshContainer = NULL;<br />
pFrame->pFrameSibling = NULL;<br />
pFrame->pFrameFirstChild = NULL;</font></p>
<p><font size="2"> *ppNewFrame = pFrame;<br />
pFrame = NULL;</font></p>
<p><font size="2">e_Exit:<br />
delete pFrame;<br />
return hr;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ作成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::CreateMeshContainer(<br />
LPCSTR Name,//名前<br />
CONST D3DXMESHDATA *pMeshData,//メッシュデータ<br />
CONST D3DXMATERIAL *pMaterials,//マテリアル<br />
CONST D3DXEFFECTINSTANCE *pEffectInstances,//エフェクトの実体<br />
DWORD NumMaterials,//マテリアル数<br />
CONST DWORD *pAdjacency,//隣接関係<br />
LPD3DXSKININFO pSkinInfo,//スキン情報<br />
LPD3DXMESHCONTAINER *ppNewMeshContainer)//メッシュコンテナのポインタ<br />
{<br />
HRESULT hr;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;<br />
UINT NumFaces;//面の数<br />
UINT iMaterial;//マテリアルの数<br />
UINT iBone, cBones;//ボーンの数<br />
LPDIRECT3DDEVICE9 pd3dDevice = NULL;</font></p>
<p><font size="2"> LPD3DXMESH pMesh = NULL;</font></p>
<p><font size="2"> *ppNewMeshContainer = NULL;</font></p>
<p><font size="2"> //パッチメッシュは扱えないので見つかったら終了<br />
if (pMeshData->Type != D3DXMESHTYPE_MESH)<br />
{<br />
hr = E_FAIL;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> // メッシュポインタをメッシュデータ構造体から得る<br />
pMesh = pMeshData->pMesh;</font></p>
<p><font size="2"> //FVFコンパチブルメッシュは扱えないので見つかったら終了<br />
if (pMesh->GetFVF() == 0)<br />
{<br />
hr = E_FAIL;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> //D3DXMESHCONTAINERとしてリターンするためにオーバーロード状態の構造体を設定する<br />
pMeshContainer = new D3DXMESHCONTAINER_DERIVED;<br />
if (pMeshContainer == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));</font></p>
<p><font size="2"> //名前を設定する<br />
hr = AllocateName(Name, &pMeshContainer->Name);<br />
if (FAILED(hr))<br />
goto e_Exit; </font></p>
<p><font size="2"> pMesh->GetDevice(&pd3dDevice);<br />
NumFaces = pMesh->GetNumFaces();</font></p>
<p><font size="2"> //法線がメッシュにないなら、法線を設定する<br />
if (!(pMesh->GetFVF() & D3DFVF_NORMAL))<br />
{<br />
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;</font></p>
<p><font size="2"> //メッシュのクローンを作って法線の場所を空ける<br />
hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),<br />
pMesh->GetFVF() | D3DFVF_NORMAL,<br />
pd3dDevice,
&pMeshContainer->MeshData.pMesh );<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //使用するメッシュコンテナからメッシュポインタを取り戻す<br />
//注意:それの参照がまだないので解放はしない<br />
pMesh = pMeshContainer->MeshData.pMesh;</font></p>
<p><font size="2"> //メッシュポインタに法線を作る<br />
D3DXComputeNormals( pMesh, NULL );<br />
}<br />
else //法線が無ければ、ただメッシュにメッシュコンテナの参照をセットする<br />
{<br />
pMeshContainer->MeshData.pMesh = pMesh;<br />
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;</font></p>
<p><font size="2"> pMesh->AddRef();<br />
}<br />
<br />
//メモリを割り当てマテリアル情報を設定する<br />
//シェーダーの代わりにD3D9のマテリアルとテクスチャ<br />
pMeshContainer->NumMaterials = max(1, NumMaterials);<br />
pMeshContainer->pMaterials = new
D3DXMATERIAL[pMeshContainer->NumMaterials];<br />
pMeshContainer->ppTextures = new
LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];<br />
pMeshContainer->pAdjacency = new DWORD[NumFaces*3];<br />
if ((pMeshContainer->pAdjacency == NULL) ||
(pMeshContainer->pMaterials == NULL))<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> memcpy(pMeshContainer->pAdjacency, pAdjacency,
sizeof(DWORD) * NumFaces*3);<br />
memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) *
pMeshContainer->NumMaterials);</font></p>
<p><font size="2"> //マテリアルが設定されたらそれをコピーする<br />
if (NumMaterials > 0) <br />
{<br />
memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL)
* NumMaterials);</font></p>
<p><font size="2"> for (iMaterial = 0; iMaterial < NumMaterials;
iMaterial++)<br />
{<br />
if (pMeshContainer->pMaterials[iMaterial].pTextureFilename !=
NULL)<br />
{<br />
WCHAR str[MAX_PATH];<br />
<br />
MtoW(
str,pMeshContainer->pMaterials[iMaterial].pTextureFilename, MAX_PATH );<br />
if( FAILED( D3DXCreateTextureFromFileW( pd3dDevice, str,<br />
&pMeshContainer->ppTextures[iMaterial] ) ) )<br />
pMeshContainer->ppTextures[iMaterial] = NULL;<br />
</font></p>
<p><font size="2"> //ポインタをダイナミックメモリに確保しない事、テクスチャ名はNULLにする<br />
pMeshContainer->pMaterials[iMaterial].pTextureFilename =
NULL;<br />
}<br />
}<br />
}<br />
else //もし、マテリアルが無かったらデフォルトの材質を<br />
{<br />
pMeshContainer->pMaterials[0].pTextureFilename = NULL;<br />
memset(&pMeshContainer->pMaterials[0].MatD3D, 0,
sizeof(D3DMATERIAL9));<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Specular =
pMeshContainer->pMaterials[0].MatD3D.Diffuse;<br />
}</font></p>
<p><font size="2"> //スキン情報があれば、ハードウェアスキニングのためにそれを使う<br />
if (pSkinInfo != NULL)<br />
{<br />
//まず最初にデータはスキン情報とメッシュに保存される<br />
pMeshContainer->pSkinInfo = pSkinInfo;<br />
pSkinInfo->AddRef();</font></p>
<p><font size="2"> pMeshContainer->pOrigMesh = pMesh;<br />
pMesh->AddRef();</font></p>
<p><font size="2"> //フィギュアスペースからボーンスペースへの頂点を移すためにオフセットマトリクスの配列が必要<br />
cBones = pSkinInfo->GetNumBones();<br />
pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];<br />
if (pMeshContainer->pBoneOffsetMatrices == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> //ここでボーンマトリクスを得て後で取得する必要を無くする<br />
for (iBone = 0; iBone < cBones; iBone++)<br />
{<br />
pMeshContainer->pBoneOffsetMatrices[iBone] =
*(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));<br />
}</font></p>
<p><font size="2"> //GenerateSkinnedMeshはハードウェアスキニングに最適なバージョンに変える<br />
hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer );<br />
if (FAILED(hr))<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> *ppNewMeshContainer = pMeshContainer;<br />
pMeshContainer = NULL;</font></p>
<p><font size="2">e_Exit:<br />
SAFE_RELEASE(pd3dDevice);</font></p>
<p><font size="2"> //適当に割り当てられたデータをきれいにする<br />
if (pMeshContainer != NULL)<br />
{<br />
DestroyMeshContainer(pMeshContainer);<br />
}</font></p>
<p><font size="2"> return hr;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレーム削除<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)<br />
{<br />
SAFE_DELETE_ARRAY( pFrameToFree->Name );<br />
SAFE_DELETE( pFrameToFree );<br />
return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ削除<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER
pMeshContainerBase)<br />
{<br />
UINT iMaterial;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;</font></p>
<p><font size="2"> SAFE_DELETE_ARRAY( pMeshContainer->Name );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );</font></p>
<p><font size="2"> //割り当てられた全てのテクスチャを解放する<br />
if (pMeshContainer->ppTextures != NULL)<br />
{<br />
for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials;
iMaterial++)<br />
{<br />
SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );<br />
}<br />
}</font></p>
<p><font size="2"> SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );<br />
SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );<br />
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );<br />
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );<br />
SAFE_RELEASE( pMeshContainer->pSkinInfo );<br />
SAFE_RELEASE( pMeshContainer->pOrigMesh );<br />
SAFE_DELETE( pMeshContainer );<br />
return S_OK;<br />
}</font></p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//スキンメッシュ生成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer )<br />
{<br />
HRESULT hr = S_OK;<br />
D3DCAPS9 d3dCaps;<br />
pd3dDevice->GetDeviceCaps( &d3dCaps );</font></p>
<p><font size="2"> if( pMeshContainer->pSkinInfo == NULL )<br />
return hr;</font></p>
<p><font size="2"> g_bUseSoftwareVP = false;</font></p>
<p><font size="2"> SAFE_RELEASE( pMeshContainer->MeshData.pMesh );<br />
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );</font></p>
<p><font size="2">
//ノンインデックススキンモードが選択されて、ConvertToBlendedMeshを使用して、描画可能メッシュを発生させなさいという場合<br />
if( g_SkinningMethod == D3DNONINDEXED )<br />
{</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL, NULL,<br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh<br />
);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><br /><font size="2">
//デバイスが2つのマトリクスブレンドしかできないなら、ConvertToBlendedMeshは近似できません。<br />
//1番目は、装置のHW頂点処理を使用することで描かれます、そして、残りは、SW頂点処理を使用することで描かれます。<br />
LPD3DXBONECOMBINATION rgBoneCombinations =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());</font></p>
<p><font size="2"> //キャップスに合わないどんなセットのボーンの組み合わせも探してください。<br />
for (pMeshContainer->iAttributeSW = 0;
pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups;
pMeshContainer->iAttributeSW++)<br />
{<br />
DWORD cInfl = 0;</font></p>
<p><font size="2"> for (DWORD iInfl = 0; iInfl <
pMeshContainer->NumInfl; iInfl++)<br />
{<br />
if
(rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] !=
UINT_MAX)<br />
{<br />
++cInfl;<br />
}<br />
}</font></p>
<p><font size="2"> if (cInfl >
d3dCaps.MaxVertexBlendMatrices)<br />
{<br />
break;<br />
}<br />
}</font></p>
<p><font size="2"> //HWとSWの両方があれば、Software Processingフラグを加えてください。<br />
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)<br />
{<br />
LPD3DXMESH pMeshTmp;</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),<br />
pMeshContainer->MeshData.pMesh->GetFVF(),<br />
pd3dDevice, &pMeshTmp);<br />
if (FAILED(hr))<br />
{<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2">
pMeshContainer->MeshData.pMesh->Release();<br />
pMeshContainer->MeshData.pMesh = pMeshTmp;<br />
pMeshTmp = NULL;<br />
}<br />
}<br />
//選択されたモードにスキンインデックスをつけられるなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。<br />
else if( g_SkinningMethod == D3DINDEXED )<br />
{<br />
DWORD NumMaxFaceInfl;<br />
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;</font></p>
<p><font size="2"> LPDIRECT3DINDEXBUFFER9 pIB;<br />
hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB,
pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl);<br />
pIB->Release();<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //12のエントリーパレット保証
どんな三角形(3つの頂点あたり4つの独立している影響)も扱うことができる<br />
NumMaxFaceInfl = min(NumMaxFaceInfl, 12);</font></p>
<p><font size="2"> if( d3dCaps.MaxVertexBlendMatrixIndex + 1 <
NumMaxFaceInfl )<br />
{<br />
//HWはインデックスをつけられた頂点ブレンドを支持しません。 代わりにSWを使用してください。<br />
pMeshContainer->NumPaletteEntries = min(256,
pMeshContainer->pSkinInfo->GetNumBones());<br />
pMeshContainer->UseSoftwareVP = true;<br />
g_bUseSoftwareVP = true;<br />
Flags |= D3DXMESH_SYSTEMMEM;<br />
}<br />
else<br />
{<br />
//ハードウェアはボーンのキャップと数からパレットサイズを決定するのを使用する<br />
//法線はライトのためにブレンドされる必要があり頂点データに存在しています<br />
//マトリクスの数はMaxVertexBlendMatrixIndexによって指定された半数です。<br />
pMeshContainer->NumPaletteEntries = min( (
d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,<br />
pMeshContainer->pSkinInfo->GetNumBones() );<br />
pMeshContainer->UseSoftwareVP = false;<br />
Flags |= D3DXMESH_MANAGED;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
Flags,<br />
pMeshContainer->NumPaletteEntries,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL, NULL,<br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;<br />
}<br />
//頂点シェーダがインデックススキンモードを選択したなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。<br />
else if( ( g_SkinningMethod == D3DINDEXEDVS ) || ( g_SkinningMethod ==
D3DINDEXEDHLSLVS ) )<br />
{<br />
//パレットサイズを得る<br />
//最初の9つの定数が他のデータに使用されます。 それぞれの4×3マトリクスは3つの定数を持っている。<br />
//(96 - 9) /3 すなわち、Maximumの一定のカウント-- 中古の定数<br />
UINT MaxMatrices = 26;<br />
pMeshContainer->NumPaletteEntries = min(MaxMatrices,
pMeshContainer->pSkinInfo->GetNumBones());</font></p>
<p><font size="2"> DWORD Flags = D3DXMESHOPT_VERTEXCACHE;<br />
if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))<br />
{<br />
pMeshContainer->UseSoftwareVP = false;<br />
Flags |= D3DXMESH_MANAGED;<br />
}<br />
else<br />
{<br />
pMeshContainer->UseSoftwareVP = true;<br />
g_bUseSoftwareVP = true;<br />
Flags |= D3DXMESH_SYSTEMMEM;<br />
}</font></p>
<p><font size="2">
SAFE_RELEASE(pMeshContainer->MeshData.pMesh);</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
Flags,<br />
pMeshContainer->NumPaletteEntries,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL,
NULL, <br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><br /><font size="2"> //FVFは当プログラムの宣言に合わなければなりません。
頂点シェーダはFFパイプラインほど寛大ではありません。<br />
DWORD NewFVF = (pMeshContainer->MeshData.pMesh->GetFVF() &
D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 |
D3DFVF_LASTBETA_UBYTE4;<br />
if (NewFVF != pMeshContainer->MeshData.pMesh->GetFVF())<br />
{<br />
LPD3DXMESH pMesh;<br />
hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(pMeshContainer->MeshData.pMesh->GetOptions(),
NewFVF, pd3dDevice, &pMesh);<br />
if (!FAILED(hr))<br />
{<br />
pMeshContainer->MeshData.pMesh->Release();<br />
pMeshContainer->MeshData.pMesh = pMesh;<br />
pMesh = NULL;<br />
}<br />
}</font></p>
<p><font size="2"> D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];<br />
LPD3DVERTEXELEMENT9 pDeclCur;<br />
hr = pMeshContainer->MeshData.pMesh->GetDeclaration(pDecl);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//頂点シェーダが、D3DCOLORとしてUBYTE4を解釈するので、タイプをアップデートしてください。<br />
//メモ:CloneMeshと共にこれができません、そして、それは、floatにUBYTE4データを変換するでしょう。D3DCOLORにキャスト操作。<br />
pDeclCur = pDecl;<br />
while (pDeclCur->Stream != 0xff)<br />
{<br />
if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) &&
(pDeclCur->UsageIndex == 0))<br />
pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;<br />
pDeclCur++;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->UpdateSemantics(pDecl);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。<br />
if( g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones() )<br />
{<br />
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> //ブレンドマトリクスのためのスペースを割り当て<br />
delete[] g_pBoneMatrices;<br />
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];<br />
if( g_pBoneMatrices == NULL )<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
}</font></p>
<p><font size="2"> }<br />
//ソフトウェアスキンが選択されて、GenerateSkinnedMeshを使用して、UpdateSkinnedMeshと共に使用できるメッシュを作成する場合<br />
else if( g_SkinningMethod == SOFTWARE )<br />
{<br />
hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED,
pMeshContainer->pOrigMesh->GetFVF(),<br />
pd3dDevice,
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL,
&pMeshContainer->NumAttributeGroups);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> delete[] pMeshContainer->pAttributeTable;<br />
pMeshContainer->pAttributeTable = new
D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];<br />
if (pMeshContainer->pAttributeTable == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable,
NULL);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。<br />
if (g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones())<br />
{<br />
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> //ブレンドマトリクスのためのスペースを割り当て<br />
delete[] g_pBoneMatrices;<br />
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];<br />
if( g_pBoneMatrices == NULL )<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
}<br />
}<br />
else //無効のg_SkinningMethod値<br />
{ <br />
//メソッド値のスキニングエラーによるリターン失敗<br />
hr = E_INVALIDARG;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2">e_Exit:<br />
return hr;<br />
}</font></p>
<p> </p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ描画<br />
//--------------------------------------------------------------------------------------<br />
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase )<br />
{<br />
HRESULT hr;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
UINT iMaterial;<br />
UINT NumBlend;<br />
UINT iAttrib;<br />
DWORD AttribIdPrev;<br />
LPD3DXBONECOMBINATION pBoneComb;</font></p>
<p><font size="2"> UINT iMatrixIndex;<br />
UINT iPaletteEntry;<br />
D3DXMATRIXA16 matTemp;<br />
D3DCAPS9 d3dCaps;<br />
pd3dDevice->GetDeviceCaps( &d3dCaps );</font></p>
<p><font size="2"> //最初にスキン情報が無いかチェックする<br />
if (pMeshContainer->pSkinInfo != NULL)<br />
{<br />
if( g_SkinningMethod == D3DNONINDEXED )<br />
{<br />
AttribIdPrev = UNUSED32;<br />
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());</font></p>
<p><font size="2"> //デバイス(通常HW)のデフォルトvtx処理を使用して、描いてください。<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
NumBlend = 0;<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)<br />
{<br />
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)<br />
{<br />
NumBlend = i;<br />
}<br />
}</font></p>
<p><font size="2"> if( d3dCaps.MaxVertexBlendMatrices >=
NumBlend + 1 )<br />
{<br />
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
i ), &matTemp ) );<br />
}<br />
}</font></p>
<p><font size="2"> V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );</font></p>
<p><font size="2"> //マテリアルが面のサブセットに使用したルックアップ<br />
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );<br />
AttribIdPrev = pBoneComb[iAttrib].AttribId;<br />
}</font></p>
<p><font size="2">
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );<br />
}<br />
}</font></p>
<p><font size="2"> //必要なら、SWを使用することでHWが扱うことができなかったサブセットを描いてください。<br />
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)<br />
{<br />
AttribIdPrev = UNUSED32;<br />
V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
for (iAttrib = pMeshContainer->iAttributeSW; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
NumBlend = 0;<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)<br />
{<br />
NumBlend = i;<br />
}<br />
}</font></p>
<p><font size="2"> if (d3dCaps.MaxVertexBlendMatrices <
NumBlend + 1)<br />
{<br />
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform(
D3DTS_WORLDMATRIX( i ), &matTemp ) );<br />
}<br />
}</font></p>
<p><font size="2"> V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );</font></p>
<p><font size="2"> //マテリアルが面のサブセットに使用したルックアップ<br />
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );<br />
AttribIdPrev = pBoneComb[iAttrib].AttribId;<br />
}</font></p>
<p><font size="2">
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );<br />
}<br />
}<br />
V( pd3dDevice->SetSoftwareVertexProcessing( FALSE ) );<br />
}</font></p>
<p><font size="2"> V( pd3dDevice->SetRenderState(
D3DRS_VERTEXBLEND, 0) );<br />
}<br />
else if (g_SkinningMethod == D3DINDEXED)<br />
{<br />
//HWがインデックスをつけられた頂点処理をサポートしないなら、ソフトウェア頂点処理に切り替わってください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> //頂点ブレンドインデックスリストの数にブレンドされるように設定してください。<br />
if (pMeshContainer->NumInfl == 1)<br />
{<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
D3DVBF_0WEIGHTS) );<br />
}<br />
else<br />
{<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
pMeshContainer->NumInfl - 1) );<br />
}</font></p>
<p><font size="2"> if (pMeshContainer->NumInfl)<br />
V(
pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE)
);</font></p>
<p><font size="2">
//メッシュの各属性グループは、パレットでマトリクスのセットについて計算してください、そして、次に、メッシュサブセットを描いてください。<br />
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
iPaletteEntry ), &matTemp ) );<br />
}<br />
}<br />
<br />
//メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );</font></p>
<p><font size="2">
//最終的に現在のワールドマトリクスパレットとマテリアルステートとサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);<br />
}</font></p>
<p><font size="2"> //リセット ブレンディングステート<br />
V( pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE,
FALSE) );<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0)
);</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
}<br />
else if (g_SkinningMethod == D3DINDEXEDVS)<br />
{<br />
//UBYTE4の代わりにCOLORを使用してください。Geforce3がそれを支持しないので。<br />
D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );</font></p>
<p><font size="2"> if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> V( pd3dDevice->SetVertexShader(
g_pIndexedVertexShader[pMeshContainer->NumInfl - 1] ) );</font></p>
<p><font size="2"> pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);<br />
D3DXMatrixMultiplyTranspose(&matTemp, &matTemp,
&g_matView);<br />
V(
pd3dDevice->SetVertexShaderConstantF(iPaletteEntry*3 + 9,
(float*)&matTemp, 3) );<br />
}<br />
}</font></p>
<p><font size="2"> //全てのアンビエントとエミッシブの合計<br />
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);<br />
D3DXCOLOR color2(.25, .25, .25, 1.0);<br />
D3DXCOLOR ambEmm;<br />
D3DXColorModulate(&ambEmm, &color1, &color2);<br />
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);</font></p>
<p><font size="2"> //マテリアルカラープロパティーセット<br />
V( pd3dDevice->SetVertexShaderConstantF(8,
(float*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse),
1) );<br />
V( pd3dDevice->SetVertexShaderConstantF(7,
(float*)&ambEmm, 1) );<br />
vConst.y =
pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Power;<br />
V( pd3dDevice->SetVertexShaderConstantF(0,
(float*)&vConst, 1) );</font></p>
<p><font size="2"> V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId]) );</font></p>
<p><font size="2">
//最終的に現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);<br />
}</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
V( pd3dDevice->SetVertexShader( NULL ) );<br />
}<br />
else if (g_SkinningMethod == D3DINDEXEDHLSLVS)<br />
{<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);<br />
D3DXMatrixMultiply(&g_pBoneMatrices[iPaletteEntry],
&matTemp, &g_matView);<br />
}<br />
}<br />
V( g_pEffect->SetMatrixArray( "mWorldMatrixArray",
g_pBoneMatrices, pMeshContainer->NumPaletteEntries) );</font></p>
<p><font size="2"> //全てのアンビエントとエミッシブの合計<br />
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);<br />
D3DXCOLOR color2(.25, .25, .25, 1.0);<br />
D3DXCOLOR ambEmm;<br />
D3DXColorModulate(&ambEmm, &color1, &color2);<br />
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);</font></p>
<p><font size="2"> //マテリアルカラープロパティーセット<br />
V( g_pEffect->SetVector("MaterialDiffuse",
(D3DXVECTOR4*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse))
);<br />
V( g_pEffect->SetVector("MaterialAmbient",
(D3DXVECTOR4*)&ambEmm) );</font></p>
<p><font size="2"> //メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );</font></p>
<p><font size="2">
//CurNumBonesにボーンの数のための正しい頂点シェーダを選択するように設定してください。<br />
V( g_pEffect->SetInt( "CurNumBones",
pMeshContainer->NumInfl -1) );</font></p>
<p><font size="2"> //現在のすべてのパラメータをアップデートしたシェーダーをスタートしてください。<br />
UINT numPasses;<br />
V( g_pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE )
);<br />
for( UINT iPass = 0; iPass < numPasses; iPass++ )<br />
{<br />
V( g_pEffect->BeginPass( iPass ) );</font></p>
<p><font size="2">
//現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset(
iAttrib ) );</font></p>
<p><font size="2"> V( g_pEffect->EndPass() );<br />
}</font></p>
<p><font size="2"> V( g_pEffect->End() );</font></p>
<p><font size="2"> V( pd3dDevice->SetVertexShader(NULL)
);<br />
}</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
}<br />
else if (g_SkinningMethod == SOFTWARE)<br />
{<br />
D3DXMATRIX Identity;<br />
DWORD cBones =
pMeshContainer->pSkinInfo->GetNumBones();<br />
DWORD iBone;<br />
PBYTE pbVerticesSrc;<br />
PBYTE pbVerticesDest;</font></p>
<p><font size="2"> //ボーントランスフォームセットアップ<br />
for (iBone = 0; iBone < cBones; ++iBone)<br />
{<br />
D3DXMatrixMultiply<br />
(<br />
&g_pBoneMatrices[iBone], // output<br />
&pMeshContainer->pBoneOffsetMatrices[iBone],<br />
pMeshContainer->ppBoneMatrixPtrs[iBone]<br />
);<br />
}</font></p>
<p><font size="2"> //ワールドトランスフォームセットアップ<br />
D3DXMatrixIdentity(&Identity);<br />
V( pd3dDevice->SetTransform(D3DTS_WORLD, &Identity)
);</font></p>
<p><font size="2"> V(
pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY,
(LPVOID*)&pbVerticesSrc) );<br />
V( pMeshContainer->MeshData.pMesh->LockVertexBuffer(0,
(LPVOID*)&pbVerticesDest) );</font></p>
<p><font size="2"> //スキンメッシュ生成<br />
pMeshContainer->pSkinInfo->UpdateSkinnedMesh(g_pBoneMatrices,
NULL, pbVerticesSrc, pbVerticesDest);</font></p>
<p><font size="2"> V(
pMeshContainer->pOrigMesh->UnlockVertexBuffer() );<br />
V( pMeshContainer->MeshData.pMesh->UnlockVertexBuffer()
);</font></p>
<p><font size="2"> for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
V(
pd3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D))
);<br />
V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId])
);<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId)
);<br />
}<br />
}<br />
else //バグアウト サポート外のメッシュ<br />
{<br />
return;<br />
}<br />
}<br />
else //スタンダードメッシュに、マテリアルプロパティーを設定した後に、ただそれを描いてください。<br />
{<br />
V( pd3dDevice->SetTransform(D3DTS_WORLD,
&pFrame->CombinedTransformationMatrix) );</font></p>
<p><font size="2"> for (iMaterial = 0; iMaterial <
pMeshContainer->NumMaterials; iMaterial++)<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[iMaterial].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[iMaterial] ) );<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial)
);<br />
}<br />
}<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレーム描画<br />
//--------------------------------------------------------------------------------------<br />
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame )<br />
{<br />
LPD3DXMESHCONTAINER pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = pFrame->pMeshContainer;<br />
while (pMeshContainer != NULL)<br />
{<br />
DrawMeshContainer( pd3dDevice, pMeshContainer, pFrame );</font></p>
<p><font size="2"> pMeshContainer =
pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
DrawFrame( pd3dDevice, pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
DrawFrame( pd3dDevice, pFrame->pFrameFirstChild );<br />
}<br />
}</font></p>
<p> </p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュ上のボーンマトリクスポインターをセット<br />
//--------------------------------------------------------------------------------------<br />
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase
)<br />
{<br />
UINT iBone, cBones;<br />
D3DXFRAME_DERIVED *pFrame;</font></p>
<p><font size="2"> D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;</font></p>
<p><font size="2"> //skinmeshがあれば、ボーンのマトリクスをセットアップしてください。<br />
if (pMeshContainer->pSkinInfo != NULL)<br />
{<br />
cBones = pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> pMeshContainer->ppBoneMatrixPtrs = new
D3DXMATRIX*[cBones];<br />
if (pMeshContainer->ppBoneMatrixPtrs == NULL)<br />
return E_OUTOFMEMORY;</font></p>
<p><font size="2"> for (iBone = 0; iBone < cBones; iBone++)<br />
{<br />
pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind( g_pFrameRoot,
pMeshContainer->pSkinInfo->GetBoneName(iBone) );<br />
if (pFrame == NULL)<br />
return E_FAIL;</font></p>
<p><font size="2"> pMeshContainer->ppBoneMatrixPtrs[iBone] =
&pFrame->CombinedTransformationMatrix;<br />
}<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//ボーンマトリクスポインターセット<br />
//--------------------------------------------------------------------------------------<br />
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )<br />
{<br />
HRESULT hr;</font></p>
<p><font size="2"> if (pFrame->pMeshContainer != NULL)<br />
{<br />
hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレームマトリクス更新<br />
//--------------------------------------------------------------------------------------<br />
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
)<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;</font></p>
<p><font size="2"> if (pParentMatrix != NULL)<br />
D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix,
&pFrame->TransformationMatrix, pParentMatrix);<br />
else<br />
pFrame->CombinedTransformationMatrix =
pFrame->TransformationMatrix;</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
UpdateFrameMatrices(pFrame->pFrameFirstChild,
&pFrame->CombinedTransformationMatrix);<br />
}<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//スキニングメソッド更新<br />
//--------------------------------------------------------------------------------------<br />
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrameBase
)<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;</font></p>
<p><font size="2"> while( pMeshContainer != NULL )<br />
{<br />
GenerateSkinnedMesh( pd3dDevice, pMeshContainer );</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameFirstChild);<br />
}<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//アトリビュートテーブルの解放<br />
//--------------------------------------------------------------------------------------<br />
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase )<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;</font></p>
<p><font size="2"> while( pMeshContainer != NULL )<br />
{<br />
delete[] pMeshContainer->pAttributeTable;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
ReleaseAttributeTable(pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
ReleaseAttributeTable(pFrame->pFrameFirstChild);<br />
}<br />
}</font></p>
</td>
</tr></tbody></table>
<p>DirectXの最初の難関、スキンメッシュアニメーション。<br />
学習方法は人それぞれですがSDKサンプルのSkinnedMesh.cppからヘルパーライブラリDXUTの関数を外していく<br />
方向でソースファイルを短くすると解りやすいかも知れません。</p>
<p><img alt="" src="http://www36.atwiki.jp/directx?cmd=upload&act=open&pageid=33&file=dxs.PNG" /></p>
<p>SkinnedMesh.cpp</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//スキンメッシュアニメーション<br />
//--------------------------------------------------------------------------------------<br />
#include "d3dx9.h"<br />
#include "SkinnedMesh.h"<br />
LPDIRECT3D9 g_pD3D = NULL;//Direct3D9<br />
LPDIRECT3DDEVICE9 pd3dDevice = NULL;//レンダリングデバイス</font></p>
<p><br /><font size="2">HWND hWnd;<br />
#define MESHFILENAME L"soldier.x"</font></p>
<p><font size="2">float timef=0.0f;<br /></font></p>
<p><font size="2">HRESULT Init()<br />
{<br />
//Direct3Dを生成する<br />
if(NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))){return E_FAIL;}</font></p>
<p><font size="2"> //デバイス生成用のパラメーター<br />
D3DPRESENT_PARAMETERS d3dpp;//パラメーター構造体<br />
ZeroMemory( &d3dpp, sizeof(d3dpp) );//ゼロで初期化<br />
d3dpp.Windowed = TRUE;//ウインドウモードで起動<br />
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//バックバッファのスワップエフェクト
Direct3Dにスワップエフェクトをまかせる<br />
d3dpp.BackBufferFormat =
D3DFMT_UNKNOWN;//バックバッファのフォーマット今表示されているモニタの設定と同じ<br />
d3dpp.BackBufferCount = 1;//バックバッファの数<br />
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;//マルチサンプリングは行わない<br />
d3dpp.MultiSampleQuality = 0;//マルチサンプリングは行わないので0<br />
d3dpp.EnableAutoDepthStencil = TRUE;//Direct3Dに深度バッファの管理をまかせる<br />
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//深度バッファのフォーマット(通常はこの値で問題ない)<br />
d3dpp.hDeviceWindow = hWnd;//カバーウィンドウ=アプリケーションのウィンドウ<br />
d3dpp.Flags = 0;//フラグは使わない<br />
d3dpp.FullScreen_RefreshRateInHz =
D3DPRESENT_RATE_DEFAULT;//今のリフレッシュレートをそのまま使う<br />
d3dpp.PresentationInterval =
D3DPRESENT_INTERVAL_DEFAULT;//モニタの垂直回帰を待つ</font></p>
<p><font size="2"> //Direct3Dデバイスの生成 HAL(ハードウェアアクセラレーション)<br />
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){<br />
//HALが駄目ならHEL(ソフトウェアエミュレーション)<br />
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){<br />
//駄目なら終了<br />
return(E_FAIL);<br />
}<br />
}<br />
// Zバッファー処理を有効にする<br />
pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );<br />
// ライトを有効にする<br />
pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );<br />
// アンビエントライト(環境光)を設定する<br />
pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00111111 );<br />
// スペキュラ(鏡面反射)を有効にする<br />
pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE,TRUE);</font></p>
<p><font size="2"> CAllocateHierarchy Alloc;</font></p>
<p><font size="2"> //シェーダーファイル読み込み</font></p>
<p><font size="2"> D3DXCreateEffectFromFileW( pd3dDevice, L"SkinnedMesh.fx",
NULL, NULL, D3DXSHADER_DEBUG,NULL, &g_pEffect, NULL );<br />
//メッシュ読み込み<br />
//WCHAR str[MAX_PATH];<br />
//MtoW(str,MESHFILENAME,MAX_PATH);</font></p>
<p><font size="2"> D3DXLoadMeshHierarchyFromXW( MESHFILENAME, D3DXMESH_MANAGED,
pd3dDevice,&Alloc, NULL, &g_pFrameRoot, &g_pAnimController );<br />
SetupBoneMatrixPointers( g_pFrameRoot );<br />
D3DXFrameCalculateBoundingSphere( g_pFrameRoot, &g_vObjectCenter,
&g_fObjectRadius );</font></p>
<p><font size="2"> //ビヘイビアフラグを得てください<br />
D3DDEVICE_CREATION_PARAMETERS cp;<br />
pd3dDevice->GetCreationParameters( &cp );<br />
g_dwBehaviorFlags = cp.BehaviorFlags;</font></p>
<p><font size="2"> //セットアップ レンダーステート<br />
pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );<br />
pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );<br />
pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );<br />
pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );<br />
pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );<br />
pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR
);</font></p>
<p><br /><font size="2"> for( DWORD iInfl = 0; iInfl < 4; ++iInfl )<br />
{<br />
LPD3DXBUFFER pCode;</font></p>
<p><font size="2"> //頂点シェーダーアセンブル<br />
D3DXAssembleShaderFromFileW( ShaderSource[iInfl], NULL, NULL,
D3DXSHADER_DEBUG, &pCode, NULL );</font></p>
<p><font size="2"> //頂点シェーダー生成<br />
pd3dDevice->CreateVertexShader(
(DWORD*)pCode->GetBufferPointer(),&g_pIndexedVertexShader[iInfl]
);</font></p>
<p><font size="2"> pCode->Release();<br />
}</font></p>
<p><font size="2"> //セットアップ プロジェクションマトリックス<br />
float fAspect = (float)640.0f / (float)480.0f;<br />
D3DXMatrixPerspectiveFovLH( &g_matProj, D3DX_PI/4, fAspect,<br />
g_fObjectRadius/64.0f, g_fObjectRadius*200.0f
);<br />
pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj );<br />
D3DXMatrixTranspose( &g_matProjT, &g_matProj );<br />
return true;<br />
}</font></p>
<p><font size="2">void MainLoop()<br />
{</font></p>
<p><font size="2"> HRESULT hr;</font></p>
<p><font size="2"> //バックバッファ<br />
pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,<br />
D3DCOLOR_ARGB(0, 255, 255, 255), 1.0f, 0L
);</font></p>
<p><font size="2"> //セットアップ ワールドマトリクス<br />
D3DXMATRIXA16 matWorld;<br />
D3DXMatrixTranslation( &matWorld, -g_vObjectCenter.x,<br />
-g_vObjectCenter.y,<br />
-g_vObjectCenter.z );<br />
pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );</font></p>
<p><font size="2"> D3DXVECTOR3 vEye( 150, 10, -2*g_fObjectRadius );<br />
D3DXVECTOR3 vAt( 0, 10, 0 );<br />
D3DXVECTOR3 vUp( 0, 1, 0 );<br />
D3DXMatrixLookAtLH( &g_matView, &vEye, &vAt,
&vUp);</font></p>
<p><font size="2"> pd3dDevice->SetTransform( D3DTS_VIEW, &g_matView
);</font></p>
<p><font size="2"> if( g_pAnimController != NULL )<br />
g_pAnimController->AdvanceTime( 0.03f, NULL );</font></p>
<p><font size="2"> UpdateFrameMatrices( g_pFrameRoot, &matWorld
);</font></p>
<p><font size="2"> //ライトセットアップ<br />
D3DLIGHT9 light;<br />
D3DXVECTOR3 vecLightDirUnnormalized(0.0f, -1.0f, 1.0f);<br />
ZeroMemory( &light, sizeof(D3DLIGHT9) );<br />
light.Type = D3DLIGHT_DIRECTIONAL;<br />
light.Diffuse.r = 1.0f;<br />
light.Diffuse.g = 1.0f;<br />
light.Diffuse.b = 1.0f;<br />
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction,
&vecLightDirUnnormalized );<br />
light.Position.x = 0.0f;<br />
light.Position.y = -1.0f;<br />
light.Position.z = 1.0f;<br />
light.Range = 1000.0f;<br />
V( pd3dDevice->SetLight(0, &light ) );<br />
V( pd3dDevice->LightEnable(0, TRUE ) );</font></p>
<p><font size="2"> //プロジェクションセット<br />
if( g_SkinningMethod == D3DINDEXEDVS )<br />
{<br />
V( pd3dDevice->SetVertexShaderConstantF( 2, (float*)&g_matProjT,
4 ) );<br />
}<br />
else<br />
if( g_SkinningMethod == D3DINDEXEDHLSLVS )<br />
{<br />
V( g_pEffect->SetMatrix( "mViewProj", &g_matProj ) );<br />
}</font></p>
<p><font size="2"> //セットライト<br />
D3DXVECTOR4 vLightDir( 0.0f, 1.0f, -1.0f, 0.0f );<br />
D3DXVec4Normalize( &vLightDir, &vLightDir );<br />
V( pd3dDevice->SetVertexShaderConstantF(1, (float*)&vLightDir, 1)
);<br />
V( g_pEffect->SetVector( "lhtDir", &vLightDir) );</font></p>
<p><font size="2"> //ビギンシーン<br />
if( SUCCEEDED( pd3dDevice->BeginScene() ) )<br />
{<br />
DrawFrame( pd3dDevice, g_pFrameRoot );</font></p>
<p><font size="2"> //シーンエンド<br />
pd3dDevice->EndScene();<br />
}<br />
pd3dDevice->Present( NULL, NULL, NULL, NULL );<br />
Sleep(10);<br />
}</font></p>
<p><font size="2">//メッセージプロシージャ<br />
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )<br />
{<br />
switch( msg )<br />
{<br />
case WM_DESTROY://終了時<br />
PostQuitMessage(0);<br />
return 0;<br />
case WM_PAINT://ウインドウ描画時<br />
MainLoop();<br />
return 0;<br />
case WM_SIZE://ウインドウサイズ変更時<br />
InvalidateRect(hWnd,NULL,true);//画面更新<br />
return 0;<br />
}</font></p>
<p><font size="2"> return DefWindowProc( hWnd, msg, wParam, lParam );<br />
}<br />
//--------------------------------------------------------------------------------------<br />
//メイン<br />
//--------------------------------------------------------------------------------------<br />
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )<br />
{<br />
//ウインドウクラスの登録<br />
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,<br />
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,<br />
"Window1", NULL };<br />
RegisterClassEx( &wc );</font></p>
<p><font size="2"> //タイトルバーとウインドウ枠の分を含めてウインドウサイズを設定<br />
RECT rect;<br />
SetRect(&rect,0,0,640,480);<br />
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);<br />
rect.right=rect.right-rect.left;<br />
rect.bottom=rect.bottom-rect.top;<br />
rect.top=0;<br />
rect.left=0;</font></p>
<p><font size="2"> //ウインドウの生成<br />
hWnd = CreateWindow( "Window1", "Hello DirectX9 World !!",<br />
WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, rect.right, rect.bottom,<br />
NULL, NULL, wc.hInstance, NULL );</font></p>
<p><font size="2"> Init();<br />
//頂点シェーダー解放<br />
for( DWORD iInfl = 0; iInfl < 4; ++iInfl )<br />
SAFE_RELEASE( g_pIndexedVertexShader[iInfl] );</font></p>
<p><font size="2"> ShowWindow(hWnd,SW_SHOWDEFAULT);<br />
UpdateWindow(hWnd);</font></p>
<p><font size="2"> //メッセージループ<br />
MSG msg;<br />
while( GetMessage(&msg,NULL,0,0))<br />
{<br />
TranslateMessage(&msg);<br />
DispatchMessage(&msg);<br />
}</font></p>
<p><br /><font size="2"> UnregisterClass("Window1",wc.hInstance);</font></p>
<p><font size="2"> ReleaseAttributeTable( g_pFrameRoot );<br />
delete[] g_pBoneMatrices;</font></p>
<p><font size="2"> SAFE_RELEASE( g_pEffect );</font></p>
<p><font size="2"> CAllocateHierarchy Alloc;<br />
D3DXFrameDestroy( g_pFrameRoot, &Alloc );<br />
SAFE_RELEASE( g_pAnimController );<br />
return 0;<br />
}</font></p>
</td>
</tr></tbody></table><p> </p>
<p><font size="2">SkinnedMesh.h</font></p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">#define V(x) { hr = (x); }<br />
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }<br />
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }<br />
#define
SAFE_RELEASE(p) {if(p){(p)->Release();(p)=NULL;}}//安全に解放する</font></p>
<p><font size="2">// 様々なスキニングモードを可能にするための列挙<br />
enum METHOD<br />
{<br />
D3DNONINDEXED,//ノンインデックス<br />
D3DINDEXED,//インデックス<br />
SOFTWARE,//ソフトウェア<br />
D3DINDEXEDVS,//インデックスVS<br />
D3DINDEXEDHLSLVS,//インデックスHLSLVS<br />
NONE//スキニング無し<br />
};</font></p>
<p><font size="2">//フレーム構造体<br />
struct D3DXFRAME_DERIVED: public D3DXFRAME<br />
{<br />
D3DXMATRIXA16 CombinedTransformationMatrix;<br />
};</font></p>
<p><font size="2">//メッシュコンテナ構造体<br />
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER<br />
{<br />
LPDIRECT3DTEXTURE9* ppTextures;//テクスチャーの配列、テクスチャーがなかったらNULL <br />
<br />
//スキンメッシュ情報 <br />
LPD3DXMESH pOrigMesh;//メッシュ<br />
LPD3DXATTRIBUTERANGE pAttributeTable;//属性<br />
DWORD NumAttributeGroups;//属性のグループ<br />
DWORD NumInfl;<br />
LPD3DXBUFFER pBoneCombinationBuf;//ボーンの組み合わせバッファ<br />
D3DXMATRIX** ppBoneMatrixPtrs;//ボーンマトリクスポインタ<br />
D3DXMATRIX* pBoneOffsetMatrices;//ボーンオフセットマトリクス<br />
DWORD NumPaletteEntries;//パレットエントリー<br />
bool UseSoftwareVP;//ソフトウェアVPを使う<br />
DWORD
iAttributeSW;//ノンインデックススキニングならソフトウェアとハードウェアで分けて指定する必要がある<br />
};</font></p>
<p><font size="2">//階層割り当てクラス<br />
class CAllocateHierarchy: public ID3DXAllocateHierarchy<br />
{<br />
public:<br />
STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME
*ppNewFrame);//フレーム作成<br />
STDMETHOD(CreateMeshContainer)(THIS_ //メッシュコンテナ作成<br />
LPCSTR Name, //名前<br />
CONST D3DXMESHDATA *pMeshData,//メッシュデータ<br />
CONST D3DXMATERIAL *pMaterials, //マテリアル<br />
CONST D3DXEFFECTINSTANCE *pEffectInstances, //エフェクトの実体<br />
DWORD NumMaterials, //マテリアル数<br />
CONST DWORD *pAdjacency, //隣接関係<br />
LPD3DXSKININFO pSkinInfo, //スキン情報<br />
LPD3DXMESHCONTAINER *ppNewMeshContainer);//メッシュコンテナのポインタ<br />
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);//フレーム削除<br />
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER
pMeshContainerBase);//メッシュコンテナ削除</font></p>
<p><font size="2"> CAllocateHierarchy() {}<br />
};</font></p>
<p><font size="2">WCHAR ShaderSource[4][30] =<br />
{<br />
L"skinmesh1.vsh",<br />
L"skinmesh2.vsh",<br />
L"skinmesh3.vsh",<br />
L"skinmesh4.vsh"<br />
};</font></p>
<p><br /><font size="2">//グローバル変数<br />
ID3DXEffect* g_pEffect = NULL; //エフェクトインターフェース<br />
LPD3DXFRAME g_pFrameRoot = NULL; //フレームルート<br />
ID3DXAnimationController* g_pAnimController = NULL;//アニメーションコントローラー<br />
D3DXVECTOR3 g_vObjectCenter; //オブジェクトのバウンディングスフィアの中心<br />
FLOAT g_fObjectRadius; //オブジェクトのバウンディングスフィアの半径<br />
METHOD g_SkinningMethod = D3DNONINDEXED;
//現在のスキニングメソッド、ノンインデックス<br />
D3DXMATRIXA16* g_pBoneMatrices = NULL;//ボーンマトリックス<br />
UINT g_NumBoneMatricesMax = 0;//ボーンマトリックスの最大数<br />
IDirect3DVertexShader9* g_pIndexedVertexShader[4];//頂点シェーダー<br />
D3DXMATRIXA16 g_matView; //ビュー行列<br />
D3DXMATRIXA16 g_matProj; //プロジェクション行列<br />
D3DXMATRIXA16 g_matProjT; //asmシェーダー用<br />
DWORD g_dwBehaviorFlags; //ビヘイビアフラグ<br />
bool g_bUseSoftwareVP;
//ソフトウェアVPフラグ、ハードウェアが無かった時のために必要</font></p>
<p><font size="2">HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR*
strFileName, ID3DXMesh** ppMesh );//メッシュロード<br />
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase );//メッシュコンテナー描画<br />
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame
);//フレーム描画<br />
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainer
);//メッシュコンテナのボーンマトリクスポインター<br />
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );//フレームのボーンマトリクスポインター<br />
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
);//フレームマトリクスの更新<br />
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice,LPD3DXFRAME
pFrameBase );//スキニングメソッドの更新<br />
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer );//スキニングメッシュの生成<br />
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase
);//アトリビュートテーブルの解放</font></p>
<p><font size="2">void MtoW(WCHAR * lpuni, LPSTR lpsjis, int buffersize)<br />
{<br />
int len =
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpsjis,-1,NULL,0);</font></p>
<p><font size="2"> if (buffersize) {<br />
//必要な文字数がバッファサイズより大きい場合はバッファイサイズ分を返還<br />
if (len > buffersize-1) len = buffersize-1;<br />
}</font></p>
<p><font size="2"> MultiByteToWideChar(<br />
CP_ACP, // ANSI Code Page (MBCS/マルチバイト文字)<br />
MB_PRECOMPOSED, // 既定変換方法<br />
lpsjis, // 変換元文字列<br />
-1, // 変換元文字列サイズ(-1指定で自動計算)(pInはゼロ終端であること)<br />
lpuni, // 変換先バッファ<br />
len); // 変換先バッファサイズ<br />
}</font></p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//割り当て名:フレームかメッシュ<br />
//--------------------------------------------------------------------------------------<br />
HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName )<br />
{<br />
UINT cbLength;</font></p>
<p><font size="2"> if( Name != NULL )//名前が存在するなら<br />
{<br />
cbLength = (UINT)strlen(Name) + 1;//名前の文字数+1<br />
*pNewName = new CHAR[cbLength];//名前用メモリ確保<br />
if (*pNewName == NULL)//確保できなかったら<br />
return E_OUTOFMEMORY;//エラー<br />
memcpy( *pNewName, Name, cbLength*sizeof(CHAR) );//Nameをコピー<br />
}<br />
else//名前が存在しなかったらNULL<br />
{<br />
*pNewName = NULL;<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//階層割り当て:フレーム作成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME *ppNewFrame
)<br />
{<br />
HRESULT hr = S_OK;<br />
D3DXFRAME_DERIVED *pFrame;//フレーム</font></p>
<p><font size="2"> *ppNewFrame = NULL;</font></p>
<p><font size="2"> pFrame = new D3DXFRAME_DERIVED;<br />
if (pFrame == NULL)//フレームが作成できなかったら<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> hr = AllocateName(Name,
&pFrame->Name);//割り当て名を設定<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //フレームの部品を初期化<br />
D3DXMatrixIdentity(&pFrame->TransformationMatrix);<br />
D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);</font></p>
<p><font size="2"> pFrame->pMeshContainer = NULL;<br />
pFrame->pFrameSibling = NULL;<br />
pFrame->pFrameFirstChild = NULL;</font></p>
<p><font size="2"> *ppNewFrame = pFrame;<br />
pFrame = NULL;</font></p>
<p><font size="2">e_Exit:<br />
delete pFrame;<br />
return hr;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ作成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::CreateMeshContainer(<br />
LPCSTR Name,//名前<br />
CONST D3DXMESHDATA *pMeshData,//メッシュデータ<br />
CONST D3DXMATERIAL *pMaterials,//マテリアル<br />
CONST D3DXEFFECTINSTANCE *pEffectInstances,//エフェクトの実体<br />
DWORD NumMaterials,//マテリアル数<br />
CONST DWORD *pAdjacency,//隣接関係<br />
LPD3DXSKININFO pSkinInfo,//スキン情報<br />
LPD3DXMESHCONTAINER *ppNewMeshContainer)//メッシュコンテナのポインタ<br />
{<br />
HRESULT hr;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;<br />
UINT NumFaces;//面の数<br />
UINT iMaterial;//マテリアルの数<br />
UINT iBone, cBones;//ボーンの数<br />
LPDIRECT3DDEVICE9 pd3dDevice = NULL;</font></p>
<p><font size="2"> LPD3DXMESH pMesh = NULL;</font></p>
<p><font size="2"> *ppNewMeshContainer = NULL;</font></p>
<p><font size="2"> //パッチメッシュは扱えないので見つかったら終了<br />
if (pMeshData->Type != D3DXMESHTYPE_MESH)<br />
{<br />
hr = E_FAIL;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> // メッシュポインタをメッシュデータ構造体から得る<br />
pMesh = pMeshData->pMesh;</font></p>
<p><font size="2"> //FVFコンパチブルメッシュは扱えないので見つかったら終了<br />
if (pMesh->GetFVF() == 0)<br />
{<br />
hr = E_FAIL;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> //D3DXMESHCONTAINERとしてリターンするためにオーバーロード状態の構造体を設定する<br />
pMeshContainer = new D3DXMESHCONTAINER_DERIVED;<br />
if (pMeshContainer == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));</font></p>
<p><font size="2"> //名前を設定する<br />
hr = AllocateName(Name, &pMeshContainer->Name);<br />
if (FAILED(hr))<br />
goto e_Exit; </font></p>
<p><font size="2"> pMesh->GetDevice(&pd3dDevice);<br />
NumFaces = pMesh->GetNumFaces();</font></p>
<p><font size="2"> //法線がメッシュにないなら、法線を設定する<br />
if (!(pMesh->GetFVF() & D3DFVF_NORMAL))<br />
{<br />
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;</font></p>
<p><font size="2"> //メッシュのクローンを作って法線の場所を空ける<br />
hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),<br />
pMesh->GetFVF() | D3DFVF_NORMAL,<br />
pd3dDevice,
&pMeshContainer->MeshData.pMesh );<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //使用するメッシュコンテナからメッシュポインタを取り戻す<br />
//注意:それの参照がまだないので解放はしない<br />
pMesh = pMeshContainer->MeshData.pMesh;</font></p>
<p><font size="2"> //メッシュポインタに法線を作る<br />
D3DXComputeNormals( pMesh, NULL );<br />
}<br />
else //法線が無ければ、ただメッシュにメッシュコンテナの参照をセットする<br />
{<br />
pMeshContainer->MeshData.pMesh = pMesh;<br />
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;</font></p>
<p><font size="2"> pMesh->AddRef();<br />
}<br />
<br />
//メモリを割り当てマテリアル情報を設定する<br />
//シェーダーの代わりにD3D9のマテリアルとテクスチャ<br />
pMeshContainer->NumMaterials = max(1, NumMaterials);<br />
pMeshContainer->pMaterials = new
D3DXMATERIAL[pMeshContainer->NumMaterials];<br />
pMeshContainer->ppTextures = new
LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];<br />
pMeshContainer->pAdjacency = new DWORD[NumFaces*3];<br />
if ((pMeshContainer->pAdjacency == NULL) ||
(pMeshContainer->pMaterials == NULL))<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> memcpy(pMeshContainer->pAdjacency, pAdjacency,
sizeof(DWORD) * NumFaces*3);<br />
memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) *
pMeshContainer->NumMaterials);</font></p>
<p><font size="2"> //マテリアルが設定されたらそれをコピーする<br />
if (NumMaterials > 0) <br />
{<br />
memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL)
* NumMaterials);</font></p>
<p><font size="2"> for (iMaterial = 0; iMaterial < NumMaterials;
iMaterial++)<br />
{<br />
if (pMeshContainer->pMaterials[iMaterial].pTextureFilename !=
NULL)<br />
{<br />
WCHAR str[MAX_PATH];<br />
<br />
MtoW(
str,pMeshContainer->pMaterials[iMaterial].pTextureFilename, MAX_PATH );<br />
if( FAILED( D3DXCreateTextureFromFileW( pd3dDevice, str,<br />
&pMeshContainer->ppTextures[iMaterial] ) ) )<br />
pMeshContainer->ppTextures[iMaterial] = NULL;<br />
</font></p>
<p><font size="2"> //ポインタをダイナミックメモリに確保しない事、テクスチャ名はNULLにする<br />
pMeshContainer->pMaterials[iMaterial].pTextureFilename =
NULL;<br />
}<br />
}<br />
}<br />
else //もし、マテリアルが無かったらデフォルトの材質を<br />
{<br />
pMeshContainer->pMaterials[0].pTextureFilename = NULL;<br />
memset(&pMeshContainer->pMaterials[0].MatD3D, 0,
sizeof(D3DMATERIAL9));<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;<br />
pMeshContainer->pMaterials[0].MatD3D.Specular =
pMeshContainer->pMaterials[0].MatD3D.Diffuse;<br />
}</font></p>
<p><font size="2"> //スキン情報があれば、ハードウェアスキニングのためにそれを使う<br />
if (pSkinInfo != NULL)<br />
{<br />
//まず最初にデータはスキン情報とメッシュに保存される<br />
pMeshContainer->pSkinInfo = pSkinInfo;<br />
pSkinInfo->AddRef();</font></p>
<p><font size="2"> pMeshContainer->pOrigMesh = pMesh;<br />
pMesh->AddRef();</font></p>
<p><font size="2"> //フィギュアスペースからボーンスペースへの頂点を移すためにオフセットマトリクスの配列が必要<br />
cBones = pSkinInfo->GetNumBones();<br />
pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];<br />
if (pMeshContainer->pBoneOffsetMatrices == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> //ここでボーンマトリクスを得て後で取得する必要を無くする<br />
for (iBone = 0; iBone < cBones; iBone++)<br />
{<br />
pMeshContainer->pBoneOffsetMatrices[iBone] =
*(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));<br />
}</font></p>
<p><font size="2"> //GenerateSkinnedMeshはハードウェアスキニングに最適なバージョンに変える<br />
hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer );<br />
if (FAILED(hr))<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> *ppNewMeshContainer = pMeshContainer;<br />
pMeshContainer = NULL;</font></p>
<p><font size="2">e_Exit:<br />
SAFE_RELEASE(pd3dDevice);</font></p>
<p><font size="2"> //適当に割り当てられたデータをきれいにする<br />
if (pMeshContainer != NULL)<br />
{<br />
DestroyMeshContainer(pMeshContainer);<br />
}</font></p>
<p><font size="2"> return hr;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレーム削除<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)<br />
{<br />
SAFE_DELETE_ARRAY( pFrameToFree->Name );<br />
SAFE_DELETE( pFrameToFree );<br />
return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ削除<br />
//--------------------------------------------------------------------------------------<br />
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER
pMeshContainerBase)<br />
{<br />
UINT iMaterial;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;</font></p>
<p><font size="2"> SAFE_DELETE_ARRAY( pMeshContainer->Name );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );<br />
SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );</font></p>
<p><font size="2"> //割り当てられた全てのテクスチャを解放する<br />
if (pMeshContainer->ppTextures != NULL)<br />
{<br />
for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials;
iMaterial++)<br />
{<br />
SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );<br />
}<br />
}</font></p>
<p><font size="2"> SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );<br />
SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );<br />
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );<br />
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );<br />
SAFE_RELEASE( pMeshContainer->pSkinInfo );<br />
SAFE_RELEASE( pMeshContainer->pOrigMesh );<br />
SAFE_DELETE( pMeshContainer );<br />
return S_OK;<br />
}</font></p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//スキンメッシュ生成<br />
//--------------------------------------------------------------------------------------<br />
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer )<br />
{<br />
HRESULT hr = S_OK;<br />
D3DCAPS9 d3dCaps;<br />
pd3dDevice->GetDeviceCaps( &d3dCaps );</font></p>
<p><font size="2"> if( pMeshContainer->pSkinInfo == NULL )<br />
return hr;</font></p>
<p><font size="2"> g_bUseSoftwareVP = false;</font></p>
<p><font size="2"> SAFE_RELEASE( pMeshContainer->MeshData.pMesh );<br />
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );</font></p>
<p><font size="2">
//ノンインデックススキンモードが選択されて、ConvertToBlendedMeshを使用して、描画可能メッシュを発生させなさいという場合<br />
if( g_SkinningMethod == D3DNONINDEXED )<br />
{</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL, NULL,<br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh<br />
);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><br /><font size="2">
//デバイスが2つのマトリクスブレンドしかできないなら、ConvertToBlendedMeshは近似できません。<br />
//1番目は、装置のHW頂点処理を使用することで描かれます、そして、残りは、SW頂点処理を使用することで描かれます。<br />
LPD3DXBONECOMBINATION rgBoneCombinations =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());</font></p>
<p><font size="2"> //キャップスに合わないどんなセットのボーンの組み合わせも探してください。<br />
for (pMeshContainer->iAttributeSW = 0;
pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups;
pMeshContainer->iAttributeSW++)<br />
{<br />
DWORD cInfl = 0;</font></p>
<p><font size="2"> for (DWORD iInfl = 0; iInfl <
pMeshContainer->NumInfl; iInfl++)<br />
{<br />
if
(rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] !=
UINT_MAX)<br />
{<br />
++cInfl;<br />
}<br />
}</font></p>
<p><font size="2"> if (cInfl >
d3dCaps.MaxVertexBlendMatrices)<br />
{<br />
break;<br />
}<br />
}</font></p>
<p><font size="2"> //HWとSWの両方があれば、Software Processingフラグを加えてください。<br />
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)<br />
{<br />
LPD3DXMESH pMeshTmp;</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),<br />
pMeshContainer->MeshData.pMesh->GetFVF(),<br />
pd3dDevice, &pMeshTmp);<br />
if (FAILED(hr))<br />
{<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2">
pMeshContainer->MeshData.pMesh->Release();<br />
pMeshContainer->MeshData.pMesh = pMeshTmp;<br />
pMeshTmp = NULL;<br />
}<br />
}<br />
//選択されたモードにスキンインデックスをつけられるなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。<br />
else if( g_SkinningMethod == D3DINDEXED )<br />
{<br />
DWORD NumMaxFaceInfl;<br />
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;</font></p>
<p><font size="2"> LPDIRECT3DINDEXBUFFER9 pIB;<br />
hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB,
pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl);<br />
pIB->Release();<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> //12のエントリーパレット保証
どんな三角形(3つの頂点あたり4つの独立している影響)も扱うことができる<br />
NumMaxFaceInfl = min(NumMaxFaceInfl, 12);</font></p>
<p><font size="2"> if( d3dCaps.MaxVertexBlendMatrixIndex + 1 <
NumMaxFaceInfl )<br />
{<br />
//HWはインデックスをつけられた頂点ブレンドを支持しません。 代わりにSWを使用してください。<br />
pMeshContainer->NumPaletteEntries = min(256,
pMeshContainer->pSkinInfo->GetNumBones());<br />
pMeshContainer->UseSoftwareVP = true;<br />
g_bUseSoftwareVP = true;<br />
Flags |= D3DXMESH_SYSTEMMEM;<br />
}<br />
else<br />
{<br />
//ハードウェアはボーンのキャップと数からパレットサイズを決定するのを使用する<br />
//法線はライトのためにブレンドされる必要があり頂点データに存在しています<br />
//マトリクスの数はMaxVertexBlendMatrixIndexによって指定された半数です。<br />
pMeshContainer->NumPaletteEntries = min( (
d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,<br />
pMeshContainer->pSkinInfo->GetNumBones() );<br />
pMeshContainer->UseSoftwareVP = false;<br />
Flags |= D3DXMESH_MANAGED;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
Flags,<br />
pMeshContainer->NumPaletteEntries,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL, NULL,<br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;<br />
}<br />
//頂点シェーダがインデックススキンモードを選択したなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。<br />
else if( ( g_SkinningMethod == D3DINDEXEDVS ) || ( g_SkinningMethod ==
D3DINDEXEDHLSLVS ) )<br />
{<br />
//パレットサイズを得る<br />
//最初の9つの定数が他のデータに使用されます。 それぞれの4×3マトリクスは3つの定数を持っている。<br />
//(96 - 9) /3 すなわち、Maximumの一定のカウント-- 中古の定数<br />
UINT MaxMatrices = 26;<br />
pMeshContainer->NumPaletteEntries = min(MaxMatrices,
pMeshContainer->pSkinInfo->GetNumBones());</font></p>
<p><font size="2"> DWORD Flags = D3DXMESHOPT_VERTEXCACHE;<br />
if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))<br />
{<br />
pMeshContainer->UseSoftwareVP = false;<br />
Flags |= D3DXMESH_MANAGED;<br />
}<br />
else<br />
{<br />
pMeshContainer->UseSoftwareVP = true;<br />
g_bUseSoftwareVP = true;<br />
Flags |= D3DXMESH_SYSTEMMEM;<br />
}</font></p>
<p><font size="2">
SAFE_RELEASE(pMeshContainer->MeshData.pMesh);</font></p>
<p><font size="2"> hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh<br />
(<br />
pMeshContainer->pOrigMesh,<br />
Flags,<br />
pMeshContainer->NumPaletteEntries,<br />
pMeshContainer->pAdjacency,<br />
NULL, NULL,
NULL, <br />
&pMeshContainer->NumInfl,<br />
&pMeshContainer->NumAttributeGroups,<br />
&pMeshContainer->pBoneCombinationBuf,<br />
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><br /><font size="2"> //FVFは当プログラムの宣言に合わなければなりません。
頂点シェーダはFFパイプラインほど寛大ではありません。<br />
DWORD NewFVF = (pMeshContainer->MeshData.pMesh->GetFVF() &
D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 |
D3DFVF_LASTBETA_UBYTE4;<br />
if (NewFVF != pMeshContainer->MeshData.pMesh->GetFVF())<br />
{<br />
LPD3DXMESH pMesh;<br />
hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(pMeshContainer->MeshData.pMesh->GetOptions(),
NewFVF, pd3dDevice, &pMesh);<br />
if (!FAILED(hr))<br />
{<br />
pMeshContainer->MeshData.pMesh->Release();<br />
pMeshContainer->MeshData.pMesh = pMesh;<br />
pMesh = NULL;<br />
}<br />
}</font></p>
<p><font size="2"> D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];<br />
LPD3DVERTEXELEMENT9 pDeclCur;<br />
hr = pMeshContainer->MeshData.pMesh->GetDeclaration(pDecl);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//頂点シェーダが、D3DCOLORとしてUBYTE4を解釈するので、タイプをアップデートしてください。<br />
//メモ:CloneMeshと共にこれができません、そして、それは、floatにUBYTE4データを変換するでしょう。D3DCOLORにキャスト操作。<br />
pDeclCur = pDecl;<br />
while (pDeclCur->Stream != 0xff)<br />
{<br />
if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) &&
(pDeclCur->UsageIndex == 0))<br />
pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;<br />
pDeclCur++;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->UpdateSemantics(pDecl);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。<br />
if( g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones() )<br />
{<br />
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> //ブレンドマトリクスのためのスペースを割り当て<br />
delete[] g_pBoneMatrices;<br />
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];<br />
if( g_pBoneMatrices == NULL )<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
}</font></p>
<p><font size="2"> }<br />
//ソフトウェアスキンが選択されて、GenerateSkinnedMeshを使用して、UpdateSkinnedMeshと共に使用できるメッシュを作成する場合<br />
else if( g_SkinningMethod == SOFTWARE )<br />
{<br />
hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED,
pMeshContainer->pOrigMesh->GetFVF(),<br />
pd3dDevice,
&pMeshContainer->MeshData.pMesh);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL,
&pMeshContainer->NumAttributeGroups);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2"> delete[] pMeshContainer->pAttributeTable;<br />
pMeshContainer->pAttributeTable = new
D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];<br />
if (pMeshContainer->pAttributeTable == NULL)<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2"> hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable,
NULL);<br />
if (FAILED(hr))<br />
goto e_Exit;</font></p>
<p><font size="2">
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。<br />
if (g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones())<br />
{<br />
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> //ブレンドマトリクスのためのスペースを割り当て<br />
delete[] g_pBoneMatrices;<br />
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];<br />
if( g_pBoneMatrices == NULL )<br />
{<br />
hr = E_OUTOFMEMORY;<br />
goto e_Exit;<br />
}<br />
}<br />
}<br />
else //無効のg_SkinningMethod値<br />
{ <br />
//メソッド値のスキニングエラーによるリターン失敗<br />
hr = E_INVALIDARG;<br />
goto e_Exit;<br />
}</font></p>
<p><font size="2">e_Exit:<br />
return hr;<br />
}</font></p>
<p> </p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュコンテナ描画<br />
//--------------------------------------------------------------------------------------<br />
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase )<br />
{<br />
HRESULT hr;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
UINT iMaterial;<br />
UINT NumBlend;<br />
UINT iAttrib;<br />
DWORD AttribIdPrev;<br />
LPD3DXBONECOMBINATION pBoneComb;</font></p>
<p><font size="2"> UINT iMatrixIndex;<br />
UINT iPaletteEntry;<br />
D3DXMATRIXA16 matTemp;<br />
D3DCAPS9 d3dCaps;<br />
pd3dDevice->GetDeviceCaps( &d3dCaps );</font></p>
<p><font size="2"> //最初にスキン情報が無いかチェックする<br />
if (pMeshContainer->pSkinInfo != NULL)<br />
{<br />
if( g_SkinningMethod == D3DNONINDEXED )<br />
{<br />
AttribIdPrev = UNUSED32;<br />
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());</font></p>
<p><font size="2"> //デバイス(通常HW)のデフォルトvtx処理を使用して、描いてください。<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
NumBlend = 0;<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)<br />
{<br />
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)<br />
{<br />
NumBlend = i;<br />
}<br />
}</font></p>
<p><font size="2"> if( d3dCaps.MaxVertexBlendMatrices >=
NumBlend + 1 )<br />
{<br />
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
i ), &matTemp ) );<br />
}<br />
}</font></p>
<p><font size="2"> V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );</font></p>
<p><font size="2"> //マテリアルが面のサブセットに使用したルックアップ<br />
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );<br />
AttribIdPrev = pBoneComb[iAttrib].AttribId;<br />
}</font></p>
<p><font size="2">
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );<br />
}<br />
}</font></p>
<p><font size="2"> //必要なら、SWを使用することでHWが扱うことができなかったサブセットを描いてください。<br />
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)<br />
{<br />
AttribIdPrev = UNUSED32;<br />
V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
for (iAttrib = pMeshContainer->iAttributeSW; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
NumBlend = 0;<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)<br />
{<br />
NumBlend = i;<br />
}<br />
}</font></p>
<p><font size="2"> if (d3dCaps.MaxVertexBlendMatrices <
NumBlend + 1)<br />
{<br />
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。<br />
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)<br />
{<br />
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform(
D3DTS_WORLDMATRIX( i ), &matTemp ) );<br />
}<br />
}</font></p>
<p><font size="2"> V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );</font></p>
<p><font size="2"> //マテリアルが面のサブセットに使用したルックアップ<br />
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );<br />
AttribIdPrev = pBoneComb[iAttrib].AttribId;<br />
}</font></p>
<p><font size="2">
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );<br />
}<br />
}<br />
V( pd3dDevice->SetSoftwareVertexProcessing( FALSE ) );<br />
}</font></p>
<p><font size="2"> V( pd3dDevice->SetRenderState(
D3DRS_VERTEXBLEND, 0) );<br />
}<br />
else if (g_SkinningMethod == D3DINDEXED)<br />
{<br />
//HWがインデックスをつけられた頂点処理をサポートしないなら、ソフトウェア頂点処理に切り替わってください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> //頂点ブレンドインデックスリストの数にブレンドされるように設定してください。<br />
if (pMeshContainer->NumInfl == 1)<br />
{<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
D3DVBF_0WEIGHTS) );<br />
}<br />
else<br />
{<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
pMeshContainer->NumInfl - 1) );<br />
}</font></p>
<p><font size="2"> if (pMeshContainer->NumInfl)<br />
V(
pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE)
);</font></p>
<p><font size="2">
//メッシュの各属性グループは、パレットでマトリクスのセットについて計算してください、そして、次に、メッシュサブセットを描いてください。<br />
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );<br />
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
iPaletteEntry ), &matTemp ) );<br />
}<br />
}<br />
<br />
//メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );</font></p>
<p><font size="2">
//最終的に現在のワールドマトリクスパレットとマテリアルステートとサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);<br />
}</font></p>
<p><font size="2"> //リセット ブレンディングステート<br />
V( pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE,
FALSE) );<br />
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0)
);</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
}<br />
else if (g_SkinningMethod == D3DINDEXEDVS)<br />
{<br />
//UBYTE4の代わりにCOLORを使用してください。Geforce3がそれを支持しないので。<br />
D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );</font></p>
<p><font size="2"> if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> V( pd3dDevice->SetVertexShader(
g_pIndexedVertexShader[pMeshContainer->NumInfl - 1] ) );</font></p>
<p><font size="2"> pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);<br />
D3DXMatrixMultiplyTranspose(&matTemp, &matTemp,
&g_matView);<br />
V(
pd3dDevice->SetVertexShaderConstantF(iPaletteEntry*3 + 9,
(float*)&matTemp, 3) );<br />
}<br />
}</font></p>
<p><font size="2"> //全てのアンビエントとエミッシブの合計<br />
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);<br />
D3DXCOLOR color2(.25, .25, .25, 1.0);<br />
D3DXCOLOR ambEmm;<br />
D3DXColorModulate(&ambEmm, &color1, &color2);<br />
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);</font></p>
<p><font size="2"> //マテリアルカラープロパティーセット<br />
V( pd3dDevice->SetVertexShaderConstantF(8,
(float*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse),
1) );<br />
V( pd3dDevice->SetVertexShaderConstantF(7,
(float*)&ambEmm, 1) );<br />
vConst.y =
pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Power;<br />
V( pd3dDevice->SetVertexShaderConstantF(0,
(float*)&vConst, 1) );</font></p>
<p><font size="2"> V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId]) );</font></p>
<p><font size="2">
//最終的に現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);<br />
}</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
V( pd3dDevice->SetVertexShader( NULL ) );<br />
}<br />
else if (g_SkinningMethod == D3DINDEXEDHLSLVS)<br />
{<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。<br />
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。<br />
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)<br />
return;</font></p>
<p><font size="2"> V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );<br />
}</font></p>
<p><font size="2"> pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());<br />
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
//まず最初にワールドマトリクスを計算する<br />
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)<br />
{<br />
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];<br />
if (iMatrixIndex != UINT_MAX)<br />
{<br />
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);<br />
D3DXMatrixMultiply(&g_pBoneMatrices[iPaletteEntry],
&matTemp, &g_matView);<br />
}<br />
}<br />
V( g_pEffect->SetMatrixArray( "mWorldMatrixArray",
g_pBoneMatrices, pMeshContainer->NumPaletteEntries) );</font></p>
<p><font size="2"> //全てのアンビエントとエミッシブの合計<br />
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);<br />
D3DXCOLOR color2(.25, .25, .25, 1.0);<br />
D3DXCOLOR ambEmm;<br />
D3DXColorModulate(&ambEmm, &color1, &color2);<br />
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);</font></p>
<p><font size="2"> //マテリアルカラープロパティーセット<br />
V( g_pEffect->SetVector("MaterialDiffuse",
(D3DXVECTOR4*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse))
);<br />
V( g_pEffect->SetVector("MaterialAmbient",
(D3DXVECTOR4*)&ambEmm) );</font></p>
<p><font size="2"> //メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );</font></p>
<p><font size="2">
//CurNumBonesにボーンの数のための正しい頂点シェーダを選択するように設定してください。<br />
V( g_pEffect->SetInt( "CurNumBones",
pMeshContainer->NumInfl -1) );</font></p>
<p><font size="2"> //現在のすべてのパラメータをアップデートしたシェーダーをスタートしてください。<br />
UINT numPasses;<br />
V( g_pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE )
);<br />
for( UINT iPass = 0; iPass < numPasses; iPass++ )<br />
{<br />
V( g_pEffect->BeginPass( iPass ) );</font></p>
<p><font size="2">
//現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset(
iAttrib ) );</font></p>
<p><font size="2"> V( g_pEffect->EndPass() );<br />
}</font></p>
<p><font size="2"> V( g_pEffect->End() );</font></p>
<p><font size="2"> V( pd3dDevice->SetVertexShader(NULL)
);<br />
}</font></p>
<p><font size="2"> //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。<br />
if (pMeshContainer->UseSoftwareVP)<br />
{<br />
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );<br />
}<br />
}<br />
else if (g_SkinningMethod == SOFTWARE)<br />
{<br />
D3DXMATRIX Identity;<br />
DWORD cBones =
pMeshContainer->pSkinInfo->GetNumBones();<br />
DWORD iBone;<br />
PBYTE pbVerticesSrc;<br />
PBYTE pbVerticesDest;</font></p>
<p><font size="2"> //ボーントランスフォームセットアップ<br />
for (iBone = 0; iBone < cBones; ++iBone)<br />
{<br />
D3DXMatrixMultiply<br />
(<br />
&g_pBoneMatrices[iBone], // output<br />
&pMeshContainer->pBoneOffsetMatrices[iBone],<br />
pMeshContainer->ppBoneMatrixPtrs[iBone]<br />
);<br />
}</font></p>
<p><font size="2"> //ワールドトランスフォームセットアップ<br />
D3DXMatrixIdentity(&Identity);<br />
V( pd3dDevice->SetTransform(D3DTS_WORLD, &Identity)
);</font></p>
<p><font size="2"> V(
pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY,
(LPVOID*)&pbVerticesSrc) );<br />
V( pMeshContainer->MeshData.pMesh->LockVertexBuffer(0,
(LPVOID*)&pbVerticesDest) );</font></p>
<p><font size="2"> //スキンメッシュ生成<br />
pMeshContainer->pSkinInfo->UpdateSkinnedMesh(g_pBoneMatrices,
NULL, pbVerticesSrc, pbVerticesDest);</font></p>
<p><font size="2"> V(
pMeshContainer->pOrigMesh->UnlockVertexBuffer() );<br />
V( pMeshContainer->MeshData.pMesh->UnlockVertexBuffer()
);</font></p>
<p><font size="2"> for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)<br />
{<br />
V(
pd3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D))
);<br />
V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId])
);<br />
V(
pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId)
);<br />
}<br />
}<br />
else //バグアウト サポート外のメッシュ<br />
{<br />
return;<br />
}<br />
}<br />
else //スタンダードメッシュに、マテリアルプロパティーを設定した後に、ただそれを描いてください。<br />
{<br />
V( pd3dDevice->SetTransform(D3DTS_WORLD,
&pFrame->CombinedTransformationMatrix) );</font></p>
<p><font size="2"> for (iMaterial = 0; iMaterial <
pMeshContainer->NumMaterials; iMaterial++)<br />
{<br />
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[iMaterial].MatD3D ) );<br />
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[iMaterial] ) );<br />
V( pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial)
);<br />
}<br />
}<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレーム描画<br />
//--------------------------------------------------------------------------------------<br />
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame )<br />
{<br />
LPD3DXMESHCONTAINER pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = pFrame->pMeshContainer;<br />
while (pMeshContainer != NULL)<br />
{<br />
DrawMeshContainer( pd3dDevice, pMeshContainer, pFrame );</font></p>
<p><font size="2"> pMeshContainer =
pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
DrawFrame( pd3dDevice, pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
DrawFrame( pd3dDevice, pFrame->pFrameFirstChild );<br />
}<br />
}</font></p>
<p> </p>
<p><font size="2">//--------------------------------------------------------------------------------------<br />
//メッシュ上のボーンマトリクスポインターをセット<br />
//--------------------------------------------------------------------------------------<br />
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase
)<br />
{<br />
UINT iBone, cBones;<br />
D3DXFRAME_DERIVED *pFrame;</font></p>
<p><font size="2"> D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;</font></p>
<p><font size="2"> //skinmeshがあれば、ボーンのマトリクスをセットアップしてください。<br />
if (pMeshContainer->pSkinInfo != NULL)<br />
{<br />
cBones = pMeshContainer->pSkinInfo->GetNumBones();</font></p>
<p><font size="2"> pMeshContainer->ppBoneMatrixPtrs = new
D3DXMATRIX*[cBones];<br />
if (pMeshContainer->ppBoneMatrixPtrs == NULL)<br />
return E_OUTOFMEMORY;</font></p>
<p><font size="2"> for (iBone = 0; iBone < cBones; iBone++)<br />
{<br />
pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind( g_pFrameRoot,
pMeshContainer->pSkinInfo->GetBoneName(iBone) );<br />
if (pFrame == NULL)<br />
return E_FAIL;</font></p>
<p><font size="2"> pMeshContainer->ppBoneMatrixPtrs[iBone] =
&pFrame->CombinedTransformationMatrix;<br />
}<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//ボーンマトリクスポインターセット<br />
//--------------------------------------------------------------------------------------<br />
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )<br />
{<br />
HRESULT hr;</font></p>
<p><font size="2"> if (pFrame->pMeshContainer != NULL)<br />
{<br />
hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);<br />
if (FAILED(hr))<br />
return hr;<br />
}</font></p>
<p><font size="2"> return S_OK;<br />
}</font></p>
<p> </p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//フレームマトリクス更新<br />
//--------------------------------------------------------------------------------------<br />
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
)<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;</font></p>
<p><font size="2"> if (pParentMatrix != NULL)<br />
D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix,
&pFrame->TransformationMatrix, pParentMatrix);<br />
else<br />
pFrame->CombinedTransformationMatrix =
pFrame->TransformationMatrix;</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
UpdateFrameMatrices(pFrame->pFrameFirstChild,
&pFrame->CombinedTransformationMatrix);<br />
}<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//スキニングメソッド更新<br />
//--------------------------------------------------------------------------------------<br />
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrameBase
)<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;</font></p>
<p><font size="2"> while( pMeshContainer != NULL )<br />
{<br />
GenerateSkinnedMesh( pd3dDevice, pMeshContainer );</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameFirstChild);<br />
}<br />
}</font></p>
<p><br /><font size="2">//--------------------------------------------------------------------------------------<br />
//アトリビュートテーブルの解放<br />
//--------------------------------------------------------------------------------------<br />
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase )<br />
{<br />
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;<br />
D3DXMESHCONTAINER_DERIVED *pMeshContainer;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;</font></p>
<p><font size="2"> while( pMeshContainer != NULL )<br />
{<br />
delete[] pMeshContainer->pAttributeTable;</font></p>
<p><font size="2"> pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameSibling != NULL)<br />
{<br />
ReleaseAttributeTable(pFrame->pFrameSibling);<br />
}</font></p>
<p><font size="2"> if (pFrame->pFrameFirstChild != NULL)<br />
{<br />
ReleaseAttributeTable(pFrame->pFrameFirstChild);<br />
}<br />
}</font></p>
</td>
</tr></tbody></table><p>以下はシェーダーファイル</p>
<p>skinmesh1.vsh</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">vs.1.1</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; v0 = position<br />
; v1 = blend weights<br />
; v2 = blend indices<br />
; v3 = normal<br />
; v4 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; r0.w = Last blend weight<br />
; r1 = Blend indices<br />
; r2 = Temp position<br />
; r3 = Temp normal<br />
; r4 = Blended position in camera space<br />
; r5 = Blended normal in camera space<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; Constants specified by the app;<br />
;<br />
; c9-c95 = world-view matrix palette<br />
; c8 = diffuse * light.diffuse<br />
; c7 = ambient color<br />
; c2-c5 = projection matrix<br />
; c1 = light direction<br />
; c0 = {1, power, 0, 1020.01};<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; oPos = Output position<br />
; oD0 = Diffuse<br />
; oD1 = Specular<br />
; oT0 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">dcl_position v0;<br />
dcl_blendweight v1;<br />
dcl_blendindices v2;<br />
dcl_normal v3;<br />
dcl_texcoord0 v4;</font></p>
<p><font size="2">// Compensate for lack of UBYTE4 on Geforce3<br />
mul r1,v2.zyxw,c0.wwww<br />
//mul r1,v2,c0.wwww</font></p>
<p><br /><font size="2">//Set 1<br />
mov a0.x,r1.x<br />
m4x3 r4.xyz,v0,c[a0.x + 9];<br />
m3x3 r5.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//compute position<br />
mov r4.w,c0.x<br />
m4x4 oPos,r4,c2</font></p>
<p><font size="2">// normalize normals<br />
dp3 r5.w, r5, r5;<br />
rsq r5.w, r5.w;<br />
mul r5, r5, r5.w;</font></p>
<p><font size="2">; Do the lighting calculation<br />
dp3 r1.x, r5, c1 ; normal dot light<br />
lit r1, r1<br />
mul r0, r1.y, c8 ; Multiply with diffuse<br />
add r0, r0, c7 ; Add in ambient<br />
min oD0, r0, c0.x ; clamp if > 1<br />
mov oD1, c0.zzzz ; output specular</font></p>
<p><font size="2">; Copy texture coordinate<br />
mov oT0, v4</font></p>
</td>
</tr></tbody></table><p>skinmesh2.vsh</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">vs.1.1</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; v0 = position<br />
; v1 = blend weights<br />
; v2 = blend indices<br />
; v3 = normal<br />
; v4 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; r0.w = Last blend weight<br />
; r1 = Blend indices<br />
; r2 = Temp position<br />
; r3 = Temp normal<br />
; r4 = Blended position in camera space<br />
; r5 = Blended normal in camera space<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; Constants specified by the app;<br />
;<br />
; c9-c95 = world-view matrix palette<br />
; c8 = diffuse * light.diffuse<br />
; c7 = ambient color<br />
; c2-c5 = projection matrix<br />
; c1 = light direction<br />
; c0 = {1, power, 0, 1020.01};<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; oPos = Output position<br />
; oD0 = Diffuse<br />
; oD1 = Specular<br />
; oT0 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">dcl_position v0;<br />
dcl_blendweight v1;<br />
dcl_blendindices v2;<br />
dcl_normal v3;<br />
dcl_texcoord0 v4;</font></p>
<p><font size="2">// Compensate for lack of UBYTE4 on Geforce3<br />
mul r1,v2.zyxw,c0.wwww<br />
//mul r1,v2,c0.wwww</font></p>
<p><br /><font size="2">//first compute the last blending weight<br />
dp3 r0.w,v1.xyz,c0.xzz;<br />
add r0.w,-r0.w,c0.x</font></p>
<p><font size="2">//Set 1<br />
mov a0.x,r1.x<br />
m4x3 r4.xyz,v0,c[a0.x + 9];<br />
m3x3 r5.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//blend them<br />
mul r4.xyz,r4.xyz,v1.xxxx<br />
mul r5.xyz,r5.xyz,v1.xxxx</font></p>
<p><font size="2">//Set 2<br />
mov a0.x,r1.y<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,r0.wwww,r4;<br />
mad r5.xyz,r3.xyz,r0.wwww,r5;</font></p>
<p><font size="2">//compute position<br />
mov r4.w,c0.x<br />
m4x4 oPos,r4,c2</font></p>
<p><font size="2">// normalize normals<br />
dp3 r5.w, r5, r5;<br />
rsq r5.w, r5.w;<br />
mul r5, r5, r5.w;</font></p>
<p><font size="2">; Do the lighting calculation<br />
dp3 r1.x, r5, c1 ; normal dot light<br />
lit r1, r1<br />
mul r0, r1.y, c8 ; Multiply with diffuse<br />
add r0, r0, c7 ; Add in ambient<br />
min oD0, r0, c0.x ; clamp if > 1<br />
mov oD1, c0.zzzz ; output specular</font></p>
<p><font size="2">; Copy texture coordinate<br />
mov oT0, v4</font></p>
</td>
</tr></tbody></table><p>skinmesh3.vsh</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">vs.1.1</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; v0 = position<br />
; v1 = blend weights<br />
; v2 = blend indices<br />
; v3 = normal<br />
; v4 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; r0.w = Last blend weight<br />
; r1 = Blend indices<br />
; r2 = Temp position<br />
; r3 = Temp normal<br />
; r4 = Blended position in camera space<br />
; r5 = Blended normal in camera space<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; Constants specified by the app;<br />
;<br />
; c9-c95 = world-view matrix palette<br />
; c8 = diffuse * light.diffuse<br />
; c7 = ambient color<br />
; c2-c5 = projection matrix<br />
; c1 = light direction<br />
; c0 = {1, power, 0, 1020.01};<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; oPos = Output position<br />
; oD0 = Diffuse<br />
; oD1 = Specular<br />
; oT0 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">dcl_position v0;<br />
dcl_blendweight v1;<br />
dcl_blendindices v2;<br />
dcl_normal v3;<br />
dcl_texcoord0 v4;</font></p>
<p><font size="2">// Compensate for lack of UBYTE4 on Geforce3<br />
mul r1,v2.zyxw,c0.wwww<br />
//mul r1,v2,c0.wwww</font></p>
<p><br /><font size="2">//first compute the last blending weight<br />
dp3 r0.w,v1.xyz,c0.xxz;<br />
add r0.w,-r0.w,c0.x</font></p>
<p><font size="2">//Set 1<br />
mov a0.x,r1.x<br />
m4x3 r4.xyz,v0,c[a0.x + 9];<br />
m3x3 r5.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//blend them<br />
mul r4.xyz,r4.xyz,v1.xxxx<br />
mul r5.xyz,r5.xyz,v1.xxxx</font></p>
<p><font size="2">//Set 2<br />
mov a0.x,r1.y<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,v1.yyyy,r4;<br />
mad r5.xyz,r3.xyz,v1.yyyy,r5;<br />
<br />
//Set 3<br />
mov a0.x,r1.z<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,r0.wwww,r4;<br />
mad r5.xyz,r3.xyz,r0.wwww,r5;</font></p>
<p><font size="2">//compute position<br />
mov r4.w,c0.x<br />
m4x4 oPos,r4,c2</font></p>
<p><font size="2">// normalize normals<br />
dp3 r5.w, r5, r5;<br />
rsq r5.w, r5.w;<br />
mul r5, r5, r5.w;</font></p>
<p><font size="2">; Do the lighting calculation<br />
dp3 r1.x, r5, c1 ; normal dot light<br />
lit r1, r1<br />
mul r0, r1.y, c8 ; Multiply with diffuse<br />
add r0, r0, c7 ; Add in ambient<br />
min oD0, r0, c0.x ; clamp if > 1<br />
mov oD1, c0.zzzz ; output specular</font></p>
<p><font size="2">; Copy texture coordinate<br />
mov oT0, v4</font></p>
</td>
</tr></tbody></table><p>skinmesh4.vsh</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">vs.1.1</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; v0 = position<br />
; v1 = blend weights<br />
; v2 = blend indices<br />
; v3 = normal<br />
; v4 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; r0.w = Last blend weight<br />
; r1 = Blend indices<br />
; r2 = Temp position<br />
; r3 = Temp normal<br />
; r4 = Blended position in camera space<br />
; r5 = Blended normal in camera space<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; Constants specified by the app;<br />
;<br />
; c9-c95 = world-view matrix palette<br />
; c8 = diffuse * light.diffuse<br />
; c7 = ambient color<br />
; c2-c5 = projection matrix<br />
; c1 = light direction<br />
; c0 = {1, power, 0, 1020.01};<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">;------------------------------------------------------------------------------<br />
; oPos = Output position<br />
; oD0 = Diffuse<br />
; oD1 = Specular<br />
; oT0 = texture coordinates<br />
;------------------------------------------------------------------------------</font></p>
<p><font size="2">dcl_position v0;<br />
dcl_blendweight v1;<br />
dcl_blendindices v2;<br />
dcl_normal v3;<br />
dcl_texcoord0 v4;</font></p>
<p><font size="2">// Compensate for lack of UBYTE4 on Geforce3<br />
mul r1,v2.zyxw,c0.wwww<br />
//mul r1,v2,c0.wwww</font></p>
<p><br /><font size="2">//first compute the last blending weight<br />
dp3 r0.w,v1.xyz,c0.xxx;<br />
add r0.w,-r0.w,c0.x</font></p>
<p><font size="2">//Set 1<br />
mov a0.x,r1.x<br />
m4x3 r4.xyz,v0,c[a0.x + 9];<br />
m3x3 r5.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//blend them<br />
mul r4.xyz,r4.xyz,v1.xxxx<br />
mul r5.xyz,r5.xyz,v1.xxxx</font></p>
<p><font size="2">//Set 2<br />
mov a0.x,r1.y<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,v1.yyyy,r4;<br />
mad r5.xyz,r3.xyz,v1.yyyy,r5;<br />
<br />
//Set 3<br />
mov a0.x,r1.z<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,v1.zzzz,r4;<br />
mad r5.xyz,r3.xyz,v1.zzzz,r5;</font></p>
<p><font size="2">//Set 4<br />
mov a0.x,r1.w<br />
m4x3 r2.xyz,v0,c[a0.x + 9];<br />
m3x3 r3.xyz,v3,c[a0.x + 9];</font></p>
<p><font size="2">//add them in<br />
mad r4.xyz,r2.xyz,r0.wwww,r4;<br />
mad r5.xyz,r3.xyz,r0.wwww,r5;</font></p>
<p><font size="2">//compute position<br />
mov r4.w,c0.x<br />
m4x4 oPos,r4,c2</font></p>
<p><font size="2">// normalize normals<br />
dp3 r5.w, r5, r5;<br />
rsq r5.w, r5.w;<br />
mul r5, r5, r5.w;</font></p>
<p><font size="2">; Do the lighting calculation<br />
dp3 r1.x, r5, c1 ; normal dot light<br />
lit r1, r1<br />
mul r0, r1.y, c8 ; Multiply with diffuse<br />
add r0, r0, c7 ; Add in ambient<br />
min oD0, r0, c0.x ; clamp if > 1<br />
mov oD1, c0.zzzz ; output specular</font></p>
<p><font size="2">; Copy texture coordinate<br />
mov oT0, v4</font></p>
</td>
</tr></tbody></table><p>SkinnedMesh.fx</p>
<table cellspacing="1" cellpadding="1" width="600" border="2"><tbody><tr><td>
<p><font size="2">//<br />
// Skinned Mesh Effect file<br />
// Copyright (c) 2000-2002 Microsoft Corporation. All rights reserved.<br />
//</font></p>
<p><font size="2">float4 lhtDir = {0.0f, 0.0f, -1.0f, 1.0f}; //light
Direction<br />
float4 lightDiffuse = {0.6f, 0.6f, 0.6f, 1.0f}; // Light Diffuse<br />
float4 MaterialAmbient : MATERIALAMBIENT = {0.1f, 0.1f, 0.1f, 1.0f};<br />
float4 MaterialDiffuse : MATERIALDIFFUSE = {0.8f, 0.8f, 0.8f, 1.0f};</font></p>
<p><font size="2">// Matrix Pallette<br />
static const int MAX_MATRICES = 26;<br />
float4x3 mWorldMatrixArray[MAX_MATRICES] : WORLDMATRIXARRAY;<br />
float4x4 mViewProj : VIEWPROJECTION;</font></p>
<p><font size="2">///////////////////////////////////////////////////////<br />
struct VS_INPUT<br />
{<br />
float4 Pos : POSITION;<br />
float4 BlendWeights : BLENDWEIGHT;<br />
float4 BlendIndices : BLENDINDICES;<br />
float3 Normal : NORMAL;<br />
float3 Tex0 : TEXCOORD0;<br />
};</font></p>
<p><font size="2">struct VS_OUTPUT<br />
{<br />
float4 Pos : POSITION;<br />
float4 Diffuse : COLOR;<br />
float2 Tex0 : TEXCOORD0;<br />
};</font></p>
<p><br /><font size="2">float3 Diffuse(float3 Normal)<br />
{<br />
float CosTheta;<br />
<br />
// N.L Clamped<br />
CosTheta = max(0.0f, dot(Normal, lhtDir.xyz));<br />
<br />
// propogate scalar result to vector<br />
return (CosTheta);<br />
}</font></p>
<p><br /><font size="2">VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)<br />
{<br />
VS_OUTPUT o;<br />
float3 Pos = 0.0f;<br />
float3 Normal = 0.0f; <br />
float LastWeight = 0.0f;<br />
<br />
// Compensate for lack of UBYTE4 on Geforce3<br />
int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);</font></p>
<p><font size="2"> // cast the vectors to arrays for use in the for loop
below<br />
float BlendWeightsArray[4] = (float[4])i.BlendWeights;<br />
int IndexArray[4] = (int[4])IndexVector;<br />
<br />
// calculate the pos/normal using the "normal" weights<br />
// and accumulate the weights to calculate the last weight<br />
for (int iBone = 0; iBone < NumBones-1; iBone++)<br />
{<br />
LastWeight = LastWeight + BlendWeightsArray[iBone];<br />
<br />
Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) *
BlendWeightsArray[iBone];<br />
Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) *
BlendWeightsArray[iBone];<br />
}<br />
LastWeight = 1.0f - LastWeight;</font></p>
<p><font size="2"> // Now that we have the calculated weight, add in the
final influence<br />
Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones-1]]) *
LastWeight);<br />
Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones-1]]) *
LastWeight);<br />
<br />
// transform position from world space into view and then projection
space<br />
o.Pos = mul(float4(Pos.xyz, 1.0f), mViewProj);</font></p>
<p><font size="2"> // normalize normals<br />
Normal = normalize(Normal);</font></p>
<p><font size="2"> // Shade (Ambient + etc.)<br />
o.Diffuse.xyz = MaterialAmbient.xyz + Diffuse(Normal) *
MaterialDiffuse.xyz;<br />
o.Diffuse.w = 1.0f;</font></p>
<p><font size="2"> // copy the input texture coordinate through<br />
o.Tex0 = i.Tex0.xy;</font></p>
<p><font size="2"> return o;<br />
}</font></p>
<p><font size="2">int CurNumBones = 2;<br />
VertexShader vsArray[4] = { compile vs_2_0 VShade(1),<br />
compile vs_2_0 VShade(2),<br />
compile vs_2_0 VShade(3),<br />
compile vs_2_0 VShade(4)<br />
};</font></p>
<p><br /><font size="2">//////////////////////////////////////<br />
// Techniques specs follow<br />
//////////////////////////////////////<br />
technique t0<br />
{<br />
pass p0<br />
{<br />
VertexShader = (vsArray[CurNumBones]);<br />
}<br />
}</font></p>
</td>
</tr></tbody></table>