階層有りXFile描画
-読み込み、更新、描画-
■バージョン
DirectX
DirectX9
VisualStudio
VisualStudio 2015
■サンプル
以下のリンクでサンプルをダウンロードできます。
※サンプルはアニメーション処理も入っています。
サンプル
■概要
このページでは階層有りXFileの読み込み、更新、描画を行います。
準備のページを見ていない人はそちらのページの知識、準備が
整っていることを前提として書いていますので、
以下のリンクから確認をお願いします。
階層有りXFile描画 -準備-
■読み込み
階層有りのXFileの読み込みには
「D3DXLoadMeshHierarchyFromX」を使用します。
この関数の第四引数に「ID3DXAllocateHierarchy」を
継承したクラス、または構造体を指定します。
この時に「CreateFrame」「CreateMeshContainer」が
自動で呼び出されます。
※サンプルのHierarchyXFileクラスのLoad関数が読み込み処理の部分です。
●D3DXLoadMeshHierarchyFromX
戻り値:
引数:
LPCTSTR Filename:
読み込むファイルの名前
DWORD MeshOptions:
メッシュの作成オプション
LPDIRECT3DDEVICE9 pDevice:
IDirect3DDevice9インターフェイスのポインタ
LPD3DXALLOCATEHIERARCHY pAlloc:
LPD3DXALLOCATEHIERARCHYインターフェイスのポインタ
※「CreateFrame」などの継承を行った
データ構造をを用意する必要あり
LPD3DXLOADUSERDATA pUserDataLoader:
ID3DXLoadUserDataインターフェース
※XFileにユーザーの作成した定義があるときに使用
LPD3DXFRAME* ppFrameHeirarchy:
ルートフレームを格納するためのLPD3DXFRAMEのポインタ
このデータからフレーム階層を全て把握できる
LPD3DXANIMATIONCONTROLLER* ppAnimControlle:
ID3DXAnimationControllerインターフェイスのポインタ
アニメーションとフレームは別々に扱われるので、
アニメーションに関するデータは
このID3DXAnimationControllerで使用、確認する
内容:
階層有りのXFileを読み込んで分解してくれます。
分解されたフレーム、メッシュコンテナは
第三引数の変数の「CreateFrame」「CreateMeshContainer」を
呼び出して、そこで詳細なデータの初期化を行います。
●注意点
「CreateFrame」「CreateHierarchy」内で不正アクセスなどのエラーが
行った場合、各関数ではなく、別の箇所で停止しているように見えることがあります。
D3DXLoadMeshHierarchyFromXで失敗、エラーになった場合は
「CreateFrame」「CreateMeshContainer」も合わせて疑ってください。
■更新
各階層のフレームはルートの行列に変化が起こるたびに更新を行う必要があります。
この更新はDirectXが用意した関数を使用して行うのではなく、
開発側で実装をしなくてはいけません。
※サンプルのHierarchyXFileクラスのUpdateFrame関数が更新処理の部分です。
●フレームの遷移方法
フレームを更新するには全てのフレームに対してアクセスする必要があり、
そのための方法として使用されているのが、
ルートフレームの情報を使用した再帰呼び出しです。
ルートフレームの中には兄弟フレーム、子フレームの情報が格納されている
「pFrameSibling」「pFrameFirstChild」があります。
これらの変数に値が格納されていれば、その値を使用して更新関数を呼び出します。
こうすることで、ルートから始まり、再帰を繰り返すことで
フレームの末端まで更新処理が行き届くことになります。
・兄弟再帰
// 兄弟があれば再帰で呼び出す
if (frame->pFrameSibling != NULL)
{
// 兄弟には親の行列を渡す
UpdateFrame(frame->pFrameSibling, parent_matrix);
}
・子再帰
if (frame->pFrameFirstChild != NULL)
{
// 子供には自分の行列を渡す
UpdateFrame(frame->pFrameFirstChild,
&frame->CombinedTransformationMatrix);
}
■描画
●再帰
階層有りのXFileの描画は各フレームごとのメッシュコンテナ毎に
描画をする必要があります。
そのため、更新の時と同じようにルートから各フレームを遷移する
再帰関数を作成し、その中でそのフレームが持っている
メッシュコンテナを描画させます。
例:
FrameData *frame_data = (FrameData*)frame;
LPD3DXMESHCONTAINER container_data = frame_data->pMeshContainer;
// コンテナの数だけ描画する
while (container_data != NULL)
{
DrawMeshContainer(frame, container_data);
container_data = container_data->pNextMeshContainer;
}
●メッシュコンテナの描画
メッシュコンテナの描画は通常のXFileの描画同じで、
マテリアルの数だけDrawSubsetを呼び出します。
注意点があるとしたら更新で作成した各フレーム毎の行列を
きちんと設定する必要があります。
例:
FrameData *frame_data = (FrameData*)frame;
MeshContainer *mesh_container = (MeshContainer*)container;
// 描画位置行列の設定
g_pD3DDevice->SetTransform(
D3DTS_WORLD,
&frame_data->CombinedTransformationMatrix);
// メッシュの描画
for (int i = 0; i < mesh_container->NumMaterials; i++)
{
g_pD3DDevice->SetMaterial(&mesh_container->pMaterials[i].MatD3D);
g_pD3DDevice->SetTexture(0, mesh_container->m_TextureList[i]);
mesh_container->MeshData.pMesh->DrawSubset(i);
}