2012年

11月

20日

SharpDXでXファイル読み込み

昨日からの続き。一度やってみることにしました。

 

Dllimportで実装は出来たものの、やっぱりSlimDXの方が良いなぁ・・・

使ってみたところ、足りない関数が沢山あってとても面倒です。

SharpDXで用意されていなかった関数

・D3DXLoadMeshFromX

・D3DXLoadMeshFromXof

・D3DXLoadMeshFromXInMemory

・D3DXLoadMeshHierarchyFromX

・D3DXComputeNormals

・ID3DXMesh::GetNumVertices

・ID3DXMesh::GetNumFaces

 

うーん、やっぱり不便。他にも色んな関数が存在しません。

とりあえずはアニメーションデータが無いXファイルの読み込み方。

元となるD3DXLoadMeshFromXはこんな関数です。

RESULT D3DXLoadMeshFromX(
    LPCSTR pFilename,                   // ファイル名
    DWORD Options,                      // メッシュの作成フラグ
    LPDIRECT3DDEVICE9 pDevice,          // デバイス
    LPD3DXBUFFER* ppAdjacency,          // 隣接面バッファ
    LPD3DXBUFFER* ppMaterials,          // マテリアルバッファ
    LPD3DXBUFFER* ppEffectInstances,    // エフェクトバッファ
    DWORD* pNumMaterials,               // マテリアル数
    LPD3DXMESH* ppMesh                  // 作成されるメッシュを受け取るポインタ
);

で、Dllimport属性でC#用の関数を作ります。

私はこのようにしました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[DllImport("d3dx9_43.dll", EntryPoint = "D3DXLoadMeshFromXA")]
static extern int LoadMeshFromFile(
    string pFilename,
    uint Options,
    IntPtr pDevice,
    out IntPtr ppAdjacency,
    out IntPtr ppMaterials,
    out IntPtr ppEffectInstances,
    out uint pNumMaterials,
    out IntPtr ppMesh);

d3dx9_43.dllからD3DXLoadMeshFromXAを呼び出します。

関数名は変えたかったのでEntryPointを使いました。

 

次に、作成されたポインタからSharpDXクラスを作ります。今回は最小限必要なMeshクラスとMaterialクラスを作ります。

 

Sharp.Direct3D9.Mesh(ID3DXMESH)クラスはコンストラクタでIntPtr型を指定するようになっているので、上記の関数で作成されたppMeshポインタを渡せば済みます。

1
Mesh mesh = new Mesh(ppMesh);

次にマテリアルの作成方法。マテリアルバッファからSharpDX.Direct3D9.ExtendedMaterial(D3DXMaterial)構造体を取り出します。

 

こちらはMeshと違いコンストラクタで渡せないので、SharpDX.Direct3D.Blobクラスにポインタを渡してバッファ化します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
DataStream data = null;

try
{
    // バッファのストリームを開く
    data = new DataStream(new SharpDX.Direct3D.Blob(ppMaterials));

    for (int i = 0; i < pNumMaterials; i++)
    {
        // マテリアル読み込み
        ExtendedMaterial material = (ExtendedMaterial)Marshal.PtrToStructure(
                                        data.PositionPointer,
                                        typeof(ExtendedMaterial));

        // 次のマテリアルのポインタまでオフセット
        data.Seek(Marshal.SizeOf(material), SeekOrigin.Current);
    }
}
finally
{
    // ストリームを閉じる
    if (data != null)
    {
        data.Close();
        data.Dispose();
        data = null;
    }
}

System.Runtime.InteropServices.Marshal.PtrToStructureメソッドを使うとポインタを構造体へ綺麗に変換することが出来ます。あとはExtendedMaterial.TextureFileNameからテクスチャを読み込めばマテリアル読み込みは終了です。

実行結果

今回のサンプル↓

SharpDX版 実行ファイル(ソース付)
XFileView_SharpDX.rar
圧縮ファイル アーカイブ 6.6 MB

おまけ

SlimDXで同じ処理を書いてみました。やっぱりこっちの方が簡単で良いなぁ

SlimDX版 実行ファイル(ソース付)
XFileView_SlimDX.rar
圧縮ファイル アーカイブ 9.7 MB