Xファイルを読み込んで表示するプログラムです。
Xファイルの読み込みにはD3DXLoadMeshFromXを使います。
メッシュと、属性グループのテーブルを取得できます。
属性グループというのは、メッシュの中で同じマテリアルやテクスチャを持つ頂点のグループのことです。
頂点のマテリアルやテクスチャが違うと、その分属性グループがたくさん作られます。
//Xファイル読み込み
bool XFileObject::LoadXFile( LPCWSTR file )
{
//Xファイルのディレクトリを取得(テクスチャのロードに使う)
wchar_t dir[_MAX_DIR];
_wsplitpath_s(file, NULL,0,dir,_MAX_DIR,NULL,0,NULL,0);
//Xファイルロード
LPD3DXBUFFER pD3DBufMtr;
if ( D3D_OK != D3DXLoadMeshFromX(file, D3DXMESH_SYSTEMMEM, GetDevice(), NULL, &pD3DBufMtr, NULL, &m_dwNumMaterials, &m_pMesh ) ) {
return false;
}
//Xファイルに法線がない場合は、法線を書き込む
if ( !(m_pMesh->GetFVF() & D3DFVF_NORMAL) ) {
ID3DXMesh* pTempMesh = NULL;
m_pMesh->CloneMeshFVF(m_pMesh->GetOptions(),
m_pMesh->GetFVF()|D3DFVF_NORMAL, GetDevice(), &pTempMesh );
D3DXComputeNormals(pTempMesh, NULL);
m_pMesh->Release();
m_pMesh = pTempMesh;
}
//マテリアル、テクスチャの準備
m_pMatrs = (D3DMATERIAL9*)malloc(sizeof(D3DMATERIAL9) * m_dwNumMaterials);
m_ppTextures = (LPDIRECT3DTEXTURE9*)malloc(sizeof(LPDIRECT3DTEXTURE9) * m_dwNumMaterials);
D3DXMATERIAL* d3dxmatrs = (D3DXMATERIAL*)pD3DBufMtr->GetBufferPointer();
for (int i = 0; i < (int)m_dwNumMaterials; i++) {
//マテリアル複写
m_pMatrs[i] = d3dxmatrs[i].MatD3D;
m_pMatrs[i].Ambient = m_pMatrs[i].Diffuse;
//テクスチャをロード
m_ppTextures[i] = NULL;
if ( d3dxmatrs[i].pTextureFilename != NULL ) {
//テクスチャ名をwcharに変換
wchar_t filename[1024];
size_t num;
ZeroMemory( filename, sizeof(filename) );
mbstowcs_s( &num, filename, 1024, d3dxmatrs[i].pTextureFilename, _TRUNCATE );
//テクスチャファイルパスを作成する
wchar_t texturefile[1024];
ZeroMemory( texturefile, sizeof(texturefile) );
swprintf( texturefile, 1024, TEXT("%s%s"), dir, filename );
if ( S_OK != D3DXCreateTextureFromFile( GetDevice(), texturefile, &m_ppTextures[i] ) ) {
m_ppTextures[i] = NULL;
}
}
}
pD3DBufMtr->Release();
return true;
}
読み込んだメッシュはDrawSubsetで描画します。
DrawSubsetは属性グループごとに描画します。
なので属性グループの数だけDrawSubsetを呼びます。
//画面クリア
GetDevice()->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, g_backColor, 1.0f, 0 );
//デバイスに描画開始を知らせる
HRESULT hr;
hr = g_pD3DDevice->BeginScene();
//頂点シェーダをセット(使わない場合はNULL)
GetDevice()->SetVertexShader( NULL );
//頂点フォーマットをセット
GetDevice()->SetFVF( m_pMesh->GetFVF() );
//属性グループの数だけDrawSubsetを呼ぶ
for ( unsigned int u = 0; u < m_dwNumMaterials; u++ ) {
GetDevice()->SetMaterial( &m_pMatrs[u] );
GetDevice()->SetTexture( 0, m_ppTextures[u] );
m_pMesh->DrawSubset( u );
}
//デバイスに描画終了を知らせる
g_pD3DDevice->EndScene();
//画面をバックバッファと入れ替える。
g_pD3DDevice->Present( NULL, NULL, NULL, NULL );
属性グループをうまく使うと
部分的に非表示にしたり
テクスチャでキャラを描き分けることもできます。