#define V(x) { hr = (x); }
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#define
SAFE_RELEASE(p) {if(p){(p)->Release();(p)=NULL;}}//安全に解放する
// 様々なスキニングモードを可能にするための列挙
enum METHOD
{
D3DNONINDEXED,//ノンインデックス
D3DINDEXED,//インデックス
SOFTWARE,//ソフトウェア
D3DINDEXEDVS,//インデックスVS
D3DINDEXEDHLSLVS,//インデックスHLSLVS
NONE//スキニング無し
};
//フレーム構造体
struct D3DXFRAME_DERIVED: public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix;
};
//メッシュコンテナ構造体
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9* ppTextures;//テクスチャーの配列、テクスチャーがなかったらNULL
//スキンメッシュ情報
LPD3DXMESH pOrigMesh;//メッシュ
LPD3DXATTRIBUTERANGE pAttributeTable;//属性
DWORD NumAttributeGroups;//属性のグループ
DWORD NumInfl;
LPD3DXBUFFER pBoneCombinationBuf;//ボーンの組み合わせバッファ
D3DXMATRIX** ppBoneMatrixPtrs;//ボーンマトリクスポインタ
D3DXMATRIX* pBoneOffsetMatrices;//ボーンオフセットマトリクス
DWORD NumPaletteEntries;//パレットエントリー
bool UseSoftwareVP;//ソフトウェアVPを使う
DWORD
iAttributeSW;//ノンインデックススキニングならソフトウェアとハードウェアで分けて指定する必要がある
};
//階層割り当てクラス
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
public:
STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME
*ppNewFrame);//フレーム作成
STDMETHOD(CreateMeshContainer)(THIS_ //メッシュコンテナ作成
LPCSTR Name, //名前
CONST D3DXMESHDATA *pMeshData,//メッシュデータ
CONST D3DXMATERIAL *pMaterials, //マテリアル
CONST D3DXEFFECTINSTANCE *pEffectInstances, //エフェクトの実体
DWORD NumMaterials, //マテリアル数
CONST DWORD *pAdjacency, //隣接関係
LPD3DXSKININFO pSkinInfo, //スキン情報
LPD3DXMESHCONTAINER *ppNewMeshContainer);//メッシュコンテナのポインタ
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);//フレーム削除
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER
pMeshContainerBase);//メッシュコンテナ削除
CAllocateHierarchy() {}
};
WCHAR ShaderSource[4][30] =
{
L"skinmesh1.vsh",
L"skinmesh2.vsh",
L"skinmesh3.vsh",
L"skinmesh4.vsh"
};
//グローバル変数
ID3DXEffect* g_pEffect = NULL; //エフェクトインターフェース
LPD3DXFRAME g_pFrameRoot = NULL; //フレームルート
ID3DXAnimationController* g_pAnimController = NULL;//アニメーションコントローラー
D3DXVECTOR3 g_vObjectCenter; //オブジェクトのバウンディングスフィアの中心
FLOAT g_fObjectRadius; //オブジェクトのバウンディングスフィアの半径
METHOD g_SkinningMethod = D3DNONINDEXED;
//現在のスキニングメソッド、ノンインデックス
D3DXMATRIXA16* g_pBoneMatrices = NULL;//ボーンマトリックス
UINT g_NumBoneMatricesMax = 0;//ボーンマトリックスの最大数
IDirect3DVertexShader9* g_pIndexedVertexShader[4];//頂点シェーダー
D3DXMATRIXA16 g_matView; //ビュー行列
D3DXMATRIXA16 g_matProj; //プロジェクション行列
D3DXMATRIXA16 g_matProjT; //asmシェーダー用
DWORD g_dwBehaviorFlags; //ビヘイビアフラグ
bool g_bUseSoftwareVP;
//ソフトウェアVPフラグ、ハードウェアが無かった時のために必要
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR*
strFileName, ID3DXMesh** ppMesh );//メッシュロード
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase );//メッシュコンテナー描画
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame
);//フレーム描画
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainer
);//メッシュコンテナのボーンマトリクスポインター
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );//フレームのボーンマトリクスポインター
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
);//フレームマトリクスの更新
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice,LPD3DXFRAME
pFrameBase );//スキニングメソッドの更新
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer );//スキニングメッシュの生成
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase
);//アトリビュートテーブルの解放
void MtoW(WCHAR * lpuni, LPSTR lpsjis, int buffersize)
{
int len =
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpsjis,-1,NULL,0);
if (buffersize) {
//必要な文字数がバッファサイズより大きい場合はバッファイサイズ分を返還
if (len > buffersize-1) len = buffersize-1;
}
MultiByteToWideChar(
CP_ACP, // ANSI Code Page (MBCS/マルチバイト文字)
MB_PRECOMPOSED, // 既定変換方法
lpsjis, // 変換元文字列
-1, // 変換元文字列サイズ(-1指定で自動計算)(pInはゼロ終端であること)
lpuni, // 変換先バッファ
len); // 変換先バッファサイズ
}
//--------------------------------------------------------------------------------------
//割り当て名:フレームかメッシュ
//--------------------------------------------------------------------------------------
HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName )
{
UINT cbLength;
if( Name != NULL )//名前が存在するなら
{
cbLength = (UINT)strlen(Name) + 1;//名前の文字数+1
*pNewName = new CHAR[cbLength];//名前用メモリ確保
if (*pNewName == NULL)//確保できなかったら
return E_OUTOFMEMORY;//エラー
memcpy( *pNewName, Name, cbLength*sizeof(CHAR) );//Nameをコピー
}
else//名前が存在しなかったらNULL
{
*pNewName = NULL;
}
return S_OK;
}
//--------------------------------------------------------------------------------------
//階層割り当て:フレーム作成
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME *ppNewFrame
)
{
HRESULT hr = S_OK;
D3DXFRAME_DERIVED *pFrame;//フレーム
*ppNewFrame = NULL;
pFrame = new D3DXFRAME_DERIVED;
if (pFrame == NULL)//フレームが作成できなかったら
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
hr = AllocateName(Name,
&pFrame->Name);//割り当て名を設定
if (FAILED(hr))
goto e_Exit;
//フレームの部品を初期化
D3DXMatrixIdentity(&pFrame->TransformationMatrix);
D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);
pFrame->pMeshContainer = NULL;
pFrame->pFrameSibling = NULL;
pFrame->pFrameFirstChild = NULL;
*ppNewFrame = pFrame;
pFrame = NULL;
e_Exit:
delete pFrame;
return hr;
}
//--------------------------------------------------------------------------------------
//メッシュコンテナ作成
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateMeshContainer(
LPCSTR Name,//名前
CONST D3DXMESHDATA *pMeshData,//メッシュデータ
CONST D3DXMATERIAL *pMaterials,//マテリアル
CONST D3DXEFFECTINSTANCE *pEffectInstances,//エフェクトの実体
DWORD NumMaterials,//マテリアル数
CONST DWORD *pAdjacency,//隣接関係
LPD3DXSKININFO pSkinInfo,//スキン情報
LPD3DXMESHCONTAINER *ppNewMeshContainer)//メッシュコンテナのポインタ
{
HRESULT hr;
D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;
UINT NumFaces;//面の数
UINT iMaterial;//マテリアルの数
UINT iBone, cBones;//ボーンの数
LPDIRECT3DDEVICE9 pd3dDevice = NULL;
LPD3DXMESH pMesh = NULL;
*ppNewMeshContainer = NULL;
//パッチメッシュは扱えないので見つかったら終了
if (pMeshData->Type != D3DXMESHTYPE_MESH)
{
hr = E_FAIL;
goto e_Exit;
}
// メッシュポインタをメッシュデータ構造体から得る
pMesh = pMeshData->pMesh;
//FVFコンパチブルメッシュは扱えないので見つかったら終了
if (pMesh->GetFVF() == 0)
{
hr = E_FAIL;
goto e_Exit;
}
//D3DXMESHCONTAINERとしてリターンするためにオーバーロード状態の構造体を設定する
pMeshContainer = new D3DXMESHCONTAINER_DERIVED;
if (pMeshContainer == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));
//名前を設定する
hr = AllocateName(Name, &pMeshContainer->Name);
if (FAILED(hr))
goto e_Exit;
pMesh->GetDevice(&pd3dDevice);
NumFaces = pMesh->GetNumFaces();
//法線がメッシュにないなら、法線を設定する
if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
{
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
//メッシュのクローンを作って法線の場所を空ける
hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),
pMesh->GetFVF() | D3DFVF_NORMAL,
pd3dDevice,
&pMeshContainer->MeshData.pMesh );
if (FAILED(hr))
goto e_Exit;
//使用するメッシュコンテナからメッシュポインタを取り戻す
//注意:それの参照がまだないので解放はしない
pMesh = pMeshContainer->MeshData.pMesh;
//メッシュポインタに法線を作る
D3DXComputeNormals( pMesh, NULL );
}
else //法線が無ければ、ただメッシュにメッシュコンテナの参照をセットする
{
pMeshContainer->MeshData.pMesh = pMesh;
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
pMesh->AddRef();
}
//メモリを割り当てマテリアル情報を設定する
//シェーダーの代わりにD3D9のマテリアルとテクスチャ
pMeshContainer->NumMaterials = max(1, NumMaterials);
pMeshContainer->pMaterials = new
D3DXMATERIAL[pMeshContainer->NumMaterials];
pMeshContainer->ppTextures = new
LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];
pMeshContainer->pAdjacency = new DWORD[NumFaces*3];
if ((pMeshContainer->pAdjacency == NULL) ||
(pMeshContainer->pMaterials == NULL))
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
memcpy(pMeshContainer->pAdjacency, pAdjacency,
sizeof(DWORD) * NumFaces*3);
memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) *
pMeshContainer->NumMaterials);
//マテリアルが設定されたらそれをコピーする
if (NumMaterials > 0)
{
memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL)
* NumMaterials);
for (iMaterial = 0; iMaterial < NumMaterials;
iMaterial++)
{
if (pMeshContainer->pMaterials[iMaterial].pTextureFilename !=
NULL)
{
WCHAR str[MAX_PATH];
MtoW(
str,pMeshContainer->pMaterials[iMaterial].pTextureFilename, MAX_PATH );
if( FAILED( D3DXCreateTextureFromFileW( pd3dDevice, str,
&pMeshContainer->ppTextures[iMaterial] ) ) )
pMeshContainer->ppTextures[iMaterial] = NULL;
//ポインタをダイナミックメモリに確保しない事、テクスチャ名はNULLにする
pMeshContainer->pMaterials[iMaterial].pTextureFilename =
NULL;
}
}
}
else //もし、マテリアルが無かったらデフォルトの材質を
{
pMeshContainer->pMaterials[0].pTextureFilename = NULL;
memset(&pMeshContainer->pMaterials[0].MatD3D, 0,
sizeof(D3DMATERIAL9));
pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;
pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;
pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;
pMeshContainer->pMaterials[0].MatD3D.Specular =
pMeshContainer->pMaterials[0].MatD3D.Diffuse;
}
//スキン情報があれば、ハードウェアスキニングのためにそれを使う
if (pSkinInfo != NULL)
{
//まず最初にデータはスキン情報とメッシュに保存される
pMeshContainer->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();
pMeshContainer->pOrigMesh = pMesh;
pMesh->AddRef();
//フィギュアスペースからボーンスペースへの頂点を移すためにオフセットマトリクスの配列が必要
cBones = pSkinInfo->GetNumBones();
pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];
if (pMeshContainer->pBoneOffsetMatrices == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
//ここでボーンマトリクスを得て後で取得する必要を無くする
for (iBone = 0; iBone < cBones; iBone++)
{
pMeshContainer->pBoneOffsetMatrices[iBone] =
*(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));
}
//GenerateSkinnedMeshはハードウェアスキニングに最適なバージョンに変える
hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer );
if (FAILED(hr))
goto e_Exit;
}
*ppNewMeshContainer = pMeshContainer;
pMeshContainer = NULL;
e_Exit:
SAFE_RELEASE(pd3dDevice);
//適当に割り当てられたデータをきれいにする
if (pMeshContainer != NULL)
{
DestroyMeshContainer(pMeshContainer);
}
return hr;
}
//--------------------------------------------------------------------------------------
//フレーム削除
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
SAFE_DELETE_ARRAY( pFrameToFree->Name );
SAFE_DELETE( pFrameToFree );
return S_OK;
}
//--------------------------------------------------------------------------------------
//メッシュコンテナ削除
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER
pMeshContainerBase)
{
UINT iMaterial;
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
SAFE_DELETE_ARRAY( pMeshContainer->Name );
SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );
//割り当てられた全てのテクスチャを解放する
if (pMeshContainer->ppTextures != NULL)
{
for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials;
iMaterial++)
{
SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );
}
}
SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );
SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pSkinInfo );
SAFE_RELEASE( pMeshContainer->pOrigMesh );
SAFE_DELETE( pMeshContainer );
return S_OK;
}
//--------------------------------------------------------------------------------------
//スキンメッシュ生成
//--------------------------------------------------------------------------------------
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice,
D3DXMESHCONTAINER_DERIVED *pMeshContainer )
{
HRESULT hr = S_OK;
D3DCAPS9 d3dCaps;
pd3dDevice->GetDeviceCaps( &d3dCaps );
if( pMeshContainer->pSkinInfo == NULL )
return hr;
g_bUseSoftwareVP = false;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
//ノンインデックススキンモードが選択されて、ConvertToBlendedMeshを使用して、描画可能メッシュを発生させなさいという場合
if( g_SkinningMethod == D3DNONINDEXED )
{
hr =
pMeshContainer->pSkinInfo->ConvertToBlendedMesh
(
pMeshContainer->pOrigMesh,
D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh
);
if (FAILED(hr))
goto e_Exit;
//デバイスが2つのマトリクスブレンドしかできないなら、ConvertToBlendedMeshは近似できません。
//1番目は、装置のHW頂点処理を使用することで描かれます、そして、残りは、SW頂点処理を使用することで描かれます。
LPD3DXBONECOMBINATION rgBoneCombinations =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
//キャップスに合わないどんなセットのボーンの組み合わせも探してください。
for (pMeshContainer->iAttributeSW = 0;
pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups;
pMeshContainer->iAttributeSW++)
{
DWORD cInfl = 0;
for (DWORD iInfl = 0; iInfl <
pMeshContainer->NumInfl; iInfl++)
{
if
(rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] !=
UINT_MAX)
{
++cInfl;
}
}
if (cInfl >
d3dCaps.MaxVertexBlendMatrices)
{
break;
}
}
//HWとSWの両方があれば、Software Processingフラグを加えてください。
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)
{
LPD3DXMESH pMeshTmp;
hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),
pMeshContainer->MeshData.pMesh->GetFVF(),
pd3dDevice, &pMeshTmp);
if (FAILED(hr))
{
goto e_Exit;
}
pMeshContainer->MeshData.pMesh->Release();
pMeshContainer->MeshData.pMesh = pMeshTmp;
pMeshTmp = NULL;
}
}
//選択されたモードにスキンインデックスをつけられるなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。
else if( g_SkinningMethod == D3DINDEXED )
{
DWORD NumMaxFaceInfl;
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
LPDIRECT3DINDEXBUFFER9 pIB;
hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);
if (FAILED(hr))
goto e_Exit;
hr =
pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB,
pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl);
pIB->Release();
if (FAILED(hr))
goto e_Exit;
//12のエントリーパレット保証
どんな三角形(3つの頂点あたり4つの独立している影響)も扱うことができる
NumMaxFaceInfl = min(NumMaxFaceInfl, 12);
if( d3dCaps.MaxVertexBlendMatrixIndex + 1 <
NumMaxFaceInfl )
{
//HWはインデックスをつけられた頂点ブレンドを支持しません。 代わりにSWを使用してください。
pMeshContainer->NumPaletteEntries = min(256,
pMeshContainer->pSkinInfo->GetNumBones());
pMeshContainer->UseSoftwareVP = true;
g_bUseSoftwareVP = true;
Flags |= D3DXMESH_SYSTEMMEM;
}
else
{
//ハードウェアはボーンのキャップと数からパレットサイズを決定するのを使用する
//法線はライトのためにブレンドされる必要があり頂点データに存在しています
//マトリクスの数はMaxVertexBlendMatrixIndexによって指定された半数です。
pMeshContainer->NumPaletteEntries = min( (
d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,
pMeshContainer->pSkinInfo->GetNumBones() );
pMeshContainer->UseSoftwareVP = false;
Flags |= D3DXMESH_MANAGED;
}
hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh
(
pMeshContainer->pOrigMesh,
Flags,
pMeshContainer->NumPaletteEntries,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh);
if (FAILED(hr))
goto e_Exit;
}
//頂点シェーダがインデックススキンモードを選択したなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。
else if( ( g_SkinningMethod == D3DINDEXEDVS ) || ( g_SkinningMethod ==
D3DINDEXEDHLSLVS ) )
{
//パレットサイズを得る
//最初の9つの定数が他のデータに使用されます。 それぞれの4×3マトリクスは3つの定数を持っている。
//(96 - 9) /3 すなわち、Maximumの一定のカウント-- 中古の定数
UINT MaxMatrices = 26;
pMeshContainer->NumPaletteEntries = min(MaxMatrices,
pMeshContainer->pSkinInfo->GetNumBones());
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
{
pMeshContainer->UseSoftwareVP = false;
Flags |= D3DXMESH_MANAGED;
}
else
{
pMeshContainer->UseSoftwareVP = true;
g_bUseSoftwareVP = true;
Flags |= D3DXMESH_SYSTEMMEM;
}
SAFE_RELEASE(pMeshContainer->MeshData.pMesh);
hr =
pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh
(
pMeshContainer->pOrigMesh,
Flags,
pMeshContainer->NumPaletteEntries,
pMeshContainer->pAdjacency,
NULL, NULL,
NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh);
if (FAILED(hr))
goto e_Exit;
//FVFは当プログラムの宣言に合わなければなりません。
頂点シェーダはFFパイプラインほど寛大ではありません。
DWORD NewFVF = (pMeshContainer->MeshData.pMesh->GetFVF() &
D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 |
D3DFVF_LASTBETA_UBYTE4;
if (NewFVF != pMeshContainer->MeshData.pMesh->GetFVF())
{
LPD3DXMESH pMesh;
hr =
pMeshContainer->MeshData.pMesh->CloneMeshFVF(pMeshContainer->MeshData.pMesh->GetOptions(),
NewFVF, pd3dDevice, &pMesh);
if (!FAILED(hr))
{
pMeshContainer->MeshData.pMesh->Release();
pMeshContainer->MeshData.pMesh = pMesh;
pMesh = NULL;
}
}
D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
LPD3DVERTEXELEMENT9 pDeclCur;
hr = pMeshContainer->MeshData.pMesh->GetDeclaration(pDecl);
if (FAILED(hr))
goto e_Exit;
//頂点シェーダが、D3DCOLORとしてUBYTE4を解釈するので、タイプをアップデートしてください。
//メモ:CloneMeshと共にこれができません、そして、それは、floatにUBYTE4データを変換するでしょう。D3DCOLORにキャスト操作。
pDeclCur = pDecl;
while (pDeclCur->Stream != 0xff)
{
if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) &&
(pDeclCur->UsageIndex == 0))
pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
pDeclCur++;
}
hr =
pMeshContainer->MeshData.pMesh->UpdateSemantics(pDecl);
if (FAILED(hr))
goto e_Exit;
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。
if( g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones() )
{
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();
//ブレンドマトリクスのためのスペースを割り当て
delete[] g_pBoneMatrices;
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];
if( g_pBoneMatrices == NULL )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
}
}
//ソフトウェアスキンが選択されて、GenerateSkinnedMeshを使用して、UpdateSkinnedMeshと共に使用できるメッシュを作成する場合
else if( g_SkinningMethod == SOFTWARE )
{
hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED,
pMeshContainer->pOrigMesh->GetFVF(),
pd3dDevice,
&pMeshContainer->MeshData.pMesh);
if (FAILED(hr))
goto e_Exit;
hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL,
&pMeshContainer->NumAttributeGroups);
if (FAILED(hr))
goto e_Exit;
delete[] pMeshContainer->pAttributeTable;
pMeshContainer->pAttributeTable = new
D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];
if (pMeshContainer->pAttributeTable == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
hr =
pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable,
NULL);
if (FAILED(hr))
goto e_Exit;
//別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。
if (g_NumBoneMatricesMax <
pMeshContainer->pSkinInfo->GetNumBones())
{
g_NumBoneMatricesMax =
pMeshContainer->pSkinInfo->GetNumBones();
//ブレンドマトリクスのためのスペースを割り当て
delete[] g_pBoneMatrices;
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];
if( g_pBoneMatrices == NULL )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
}
}
else //無効のg_SkinningMethod値
{
//メソッド値のスキニングエラーによるリターン失敗
hr = E_INVALIDARG;
goto e_Exit;
}
e_Exit:
return hr;
}
//--------------------------------------------------------------------------------------
//メッシュコンテナ描画
//--------------------------------------------------------------------------------------
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER
pMeshContainerBase, LPD3DXFRAME pFrameBase )
{
HRESULT hr;
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
UINT iMaterial;
UINT NumBlend;
UINT iAttrib;
DWORD AttribIdPrev;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
UINT iPaletteEntry;
D3DXMATRIXA16 matTemp;
D3DCAPS9 d3dCaps;
pd3dDevice->GetDeviceCaps( &d3dCaps );
//最初にスキン情報が無いかチェックする
if (pMeshContainer->pSkinInfo != NULL)
{
if( g_SkinningMethod == D3DNONINDEXED )
{
AttribIdPrev = UNUSED32;
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
//デバイス(通常HW)のデフォルトvtx処理を使用して、描いてください。
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
NumBlend = 0;
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
{
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
{
NumBlend = i;
}
}
if( d3dCaps.MaxVertexBlendMatrices >=
NumBlend + 1 )
{
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
i ), &matTemp ) );
}
}
V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );
//マテリアルが面のサブセットに使用したルックアップ
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))
{
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );
}
}
//必要なら、SWを使用することでHWが扱うことができなかったサブセットを描いてください。
if (pMeshContainer->iAttributeSW <
pMeshContainer->NumAttributeGroups)
{
AttribIdPrev = UNUSED32;
V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
for (iAttrib = pMeshContainer->iAttributeSW; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
NumBlend = 0;
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)
{
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
{
NumBlend = i;
}
}
if (d3dCaps.MaxVertexBlendMatrices <
NumBlend + 1)
{
//まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。
for (DWORD i = 0; i < pMeshContainer->NumInfl;
++i)
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
V( pd3dDevice->SetTransform(
D3DTS_WORLDMATRIX( i ), &matTemp ) );
}
}
V(
pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );
//マテリアルが面のサブセットに使用したルックアップ
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) ||
(AttribIdPrev == UNUSED32))
{
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
//正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。
V(
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );
}
}
V( pd3dDevice->SetSoftwareVertexProcessing( FALSE ) );
}
V( pd3dDevice->SetRenderState(
D3DRS_VERTEXBLEND, 0) );
}
else if (g_SkinningMethod == D3DINDEXED)
{
//HWがインデックスをつけられた頂点処理をサポートしないなら、ソフトウェア頂点処理に切り替わってください。
if (pMeshContainer->UseSoftwareVP)
{
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)
return;
V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
}
//頂点ブレンドインデックスリストの数にブレンドされるように設定してください。
if (pMeshContainer->NumInfl == 1)
{
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
D3DVBF_0WEIGHTS) );
}
else
{
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND,
pMeshContainer->NumInfl - 1) );
}
if (pMeshContainer->NumInfl)
V(
pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE)
);
//メッシュの各属性グループは、パレットでマトリクスのセットについて計算してください、そして、次に、メッシュサブセットを描いてください。
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
//まず最初にワールドマトリクスを計算する
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
{
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX(
iPaletteEntry ), &matTemp ) );
}
}
//メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
//最終的に現在のワールドマトリクスパレットとマテリアルステートとサブセットを描いてください。
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);
}
//リセット ブレンディングステート
V( pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE,
FALSE) );
V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0)
);
//ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
if (pMeshContainer->UseSoftwareVP)
{
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
}
}
else if (g_SkinningMethod == D3DINDEXEDVS)
{
//UBYTE4の代わりにCOLORを使用してください。Geforce3がそれを支持しないので。
D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );
if (pMeshContainer->UseSoftwareVP)
{
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)
return;
V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
}
V( pd3dDevice->SetVertexShader(
g_pIndexedVertexShader[pMeshContainer->NumInfl - 1] ) );
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
//まず最初にワールドマトリクスを計算する
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
{
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);
D3DXMatrixMultiplyTranspose(&matTemp, &matTemp,
&g_matView);
V(
pd3dDevice->SetVertexShaderConstantF(iPaletteEntry*3 + 9,
(float*)&matTemp, 3) );
}
}
//全てのアンビエントとエミッシブの合計
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);
D3DXCOLOR color2(.25, .25, .25, 1.0);
D3DXCOLOR ambEmm;
D3DXColorModulate(&ambEmm, &color1, &color2);
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);
//マテリアルカラープロパティーセット
V( pd3dDevice->SetVertexShaderConstantF(8,
(float*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse),
1) );
V( pd3dDevice->SetVertexShaderConstantF(7,
(float*)&ambEmm, 1) );
vConst.y =
pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Power;
V( pd3dDevice->SetVertexShaderConstantF(0,
(float*)&vConst, 1) );
V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId]) );
//最終的に現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib )
);
}
//ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
if (pMeshContainer->UseSoftwareVP)
{
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
}
V( pd3dDevice->SetVertexShader( NULL ) );
}
else if (g_SkinningMethod == D3DINDEXEDHLSLVS)
{
if (pMeshContainer->UseSoftwareVP)
{
//HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
//アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING
)
return;
V(
pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
}
pBoneComb =
reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
//まず最初にワールドマトリクスを計算する
for (iPaletteEntry = 0; iPaletteEntry <
pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
{
iMatrixIndex =
pBoneComb[iAttrib].BoneId[iPaletteEntry];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply(&matTemp,
&pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);
D3DXMatrixMultiply(&g_pBoneMatrices[iPaletteEntry],
&matTemp, &g_matView);
}
}
V( g_pEffect->SetMatrixArray( "mWorldMatrixArray",
g_pBoneMatrices, pMeshContainer->NumPaletteEntries) );
//全てのアンビエントとエミッシブの合計
D3DXCOLOR
color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);
D3DXCOLOR color2(.25, .25, .25, 1.0);
D3DXCOLOR ambEmm;
D3DXColorModulate(&ambEmm, &color1, &color2);
ambEmm +=
D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);
//マテリアルカラープロパティーセット
V( g_pEffect->SetVector("MaterialDiffuse",
(D3DXVECTOR4*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse))
);
V( g_pEffect->SetVector("MaterialAmbient",
(D3DXVECTOR4*)&ambEmm) );
//メッシュサブセットのマテリアルをセットアップしてください--
オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
//CurNumBonesにボーンの数のための正しい頂点シェーダを選択するように設定してください。
V( g_pEffect->SetInt( "CurNumBones",
pMeshContainer->NumInfl -1) );
//現在のすべてのパラメータをアップデートしたシェーダーをスタートしてください。
UINT numPasses;
V( g_pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE )
);
for( UINT iPass = 0; iPass < numPasses; iPass++ )
{
V( g_pEffect->BeginPass( iPass ) );
//現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。
V( pMeshContainer->MeshData.pMesh->DrawSubset(
iAttrib ) );
V( g_pEffect->EndPass() );
}
V( g_pEffect->End() );
V( pd3dDevice->SetVertexShader(NULL)
);
}
//ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
if (pMeshContainer->UseSoftwareVP)
{
V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
}
}
else if (g_SkinningMethod == SOFTWARE)
{
D3DXMATRIX Identity;
DWORD cBones =
pMeshContainer->pSkinInfo->GetNumBones();
DWORD iBone;
PBYTE pbVerticesSrc;
PBYTE pbVerticesDest;
//ボーントランスフォームセットアップ
for (iBone = 0; iBone < cBones; ++iBone)
{
D3DXMatrixMultiply
(
&g_pBoneMatrices[iBone], // output
&pMeshContainer->pBoneOffsetMatrices[iBone],
pMeshContainer->ppBoneMatrixPtrs[iBone]
);
}
//ワールドトランスフォームセットアップ
D3DXMatrixIdentity(&Identity);
V( pd3dDevice->SetTransform(D3DTS_WORLD, &Identity)
);
V(
pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY,
(LPVOID*)&pbVerticesSrc) );
V( pMeshContainer->MeshData.pMesh->LockVertexBuffer(0,
(LPVOID*)&pbVerticesDest) );
//スキンメッシュ生成
pMeshContainer->pSkinInfo->UpdateSkinnedMesh(g_pBoneMatrices,
NULL, pbVerticesSrc, pbVerticesDest);
V(
pMeshContainer->pOrigMesh->UnlockVertexBuffer() );
V( pMeshContainer->MeshData.pMesh->UnlockVertexBuffer()
);
for (iAttrib = 0; iAttrib <
pMeshContainer->NumAttributeGroups; iAttrib++)
{
V(
pd3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D))
);
V( pd3dDevice->SetTexture(0,
pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId])
);
V(
pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId)
);
}
}
else //バグアウト サポート外のメッシュ
{
return;
}
}
else //スタンダードメッシュに、マテリアルプロパティーを設定した後に、ただそれを描いてください。
{
V( pd3dDevice->SetTransform(D3DTS_WORLD,
&pFrame->CombinedTransformationMatrix) );
for (iMaterial = 0; iMaterial <
pMeshContainer->NumMaterials; iMaterial++)
{
V( pd3dDevice->SetMaterial(
&pMeshContainer->pMaterials[iMaterial].MatD3D ) );
V( pd3dDevice->SetTexture( 0,
pMeshContainer->ppTextures[iMaterial] ) );
V( pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial)
);
}
}
}
//--------------------------------------------------------------------------------------
//フレーム描画
//--------------------------------------------------------------------------------------
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame )
{
LPD3DXMESHCONTAINER pMeshContainer;
pMeshContainer = pFrame->pMeshContainer;
while (pMeshContainer != NULL)
{
DrawMeshContainer( pd3dDevice, pMeshContainer, pFrame );
pMeshContainer =
pMeshContainer->pNextMeshContainer;
}
if (pFrame->pFrameSibling != NULL)
{
DrawFrame( pd3dDevice, pFrame->pFrameSibling);
}
if (pFrame->pFrameFirstChild != NULL)
{
DrawFrame( pd3dDevice, pFrame->pFrameFirstChild );
}
}
//--------------------------------------------------------------------------------------
//メッシュ上のボーンマトリクスポインターをセット
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase
)
{
UINT iBone, cBones;
D3DXFRAME_DERIVED *pFrame;
D3DXMESHCONTAINER_DERIVED *pMeshContainer =
(D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
//skinmeshがあれば、ボーンのマトリクスをセットアップしてください。
if (pMeshContainer->pSkinInfo != NULL)
{
cBones = pMeshContainer->pSkinInfo->GetNumBones();
pMeshContainer->ppBoneMatrixPtrs = new
D3DXMATRIX*[cBones];
if (pMeshContainer->ppBoneMatrixPtrs == NULL)
return E_OUTOFMEMORY;
for (iBone = 0; iBone < cBones; iBone++)
{
pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind( g_pFrameRoot,
pMeshContainer->pSkinInfo->GetBoneName(iBone) );
if (pFrame == NULL)
return E_FAIL;
pMeshContainer->ppBoneMatrixPtrs[iBone] =
&pFrame->CombinedTransformationMatrix;
}
}
return S_OK;
}
//--------------------------------------------------------------------------------------
//ボーンマトリクスポインターセット
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )
{
HRESULT hr;
if (pFrame->pMeshContainer != NULL)
{
hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);
if (FAILED(hr))
return hr;
}
if (pFrame->pFrameSibling != NULL)
{
hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);
if (FAILED(hr))
return hr;
}
if (pFrame->pFrameFirstChild != NULL)
{
hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);
if (FAILED(hr))
return hr;
}
return S_OK;
}
//--------------------------------------------------------------------------------------
//フレームマトリクス更新
//--------------------------------------------------------------------------------------
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix
)
{
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
if (pParentMatrix != NULL)
D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix,
&pFrame->TransformationMatrix, pParentMatrix);
else
pFrame->CombinedTransformationMatrix =
pFrame->TransformationMatrix;
if (pFrame->pFrameSibling != NULL)
{
UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);
}
if (pFrame->pFrameFirstChild != NULL)
{
UpdateFrameMatrices(pFrame->pFrameFirstChild,
&pFrame->CombinedTransformationMatrix);
}
}
//--------------------------------------------------------------------------------------
//スキニングメソッド更新
//--------------------------------------------------------------------------------------
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrameBase
)
{
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
D3DXMESHCONTAINER_DERIVED *pMeshContainer;
pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;
while( pMeshContainer != NULL )
{
GenerateSkinnedMesh( pd3dDevice, pMeshContainer );
pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;
}
if (pFrame->pFrameSibling != NULL)
{
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameSibling);
}
if (pFrame->pFrameFirstChild != NULL)
{
UpdateSkinningMethod(pd3dDevice,pFrame->pFrameFirstChild);
}
}
//--------------------------------------------------------------------------------------
//アトリビュートテーブルの解放
//--------------------------------------------------------------------------------------
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase )
{
D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
D3DXMESHCONTAINER_DERIVED *pMeshContainer;
pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pFrame->pMeshContainer;
while( pMeshContainer != NULL )
{
delete[] pMeshContainer->pAttributeTable;
pMeshContainer = (D3DXMESHCONTAINER_DERIVED
*)pMeshContainer->pNextMeshContainer;
}
if (pFrame->pFrameSibling != NULL)
{
ReleaseAttributeTable(pFrame->pFrameSibling);
}
if (pFrame->pFrameFirstChild != NULL)
{
ReleaseAttributeTable(pFrame->pFrameFirstChild);
}
}
|