複数のメッシュの読み込みについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
haruwo

複数のメッシュの読み込みについて

#1

投稿記事 by haruwo » 13年前

[1] 質問文

 [1.1] 自分が今行いたい事は何か
 DirectX9 に おいて、複数の異なるメッシュを読み込む方法がわからないので質問させて頂きます。複数のメッシュを読み込みたいのです。具体的には、自キャラと地形のふたつを描画させたいのです。DirectXは初めてなので、手探りの状態で作っています。

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
検索をかけてみたところ、どうもLoadModel()関数というものが存在(自作?)するらしいのですが、どうもよくわからないというのが実情です。それと、D3DXLoadMeshFromX関数、D3DXCreateTextureFromFile関数を二つ書いたりもしたのですが、実行画面に何も映りません。ファイル名はきちんと書いているつもりです。

 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
バージョンの違いでしょうか。pMesh が g_pMesh になっていたり、そういったサンプルソース(ネット上)のを読み込んでもエラーが出ます。

 [1.4] 今何がわからないのか、知りたいのか
DirectX9 に おいて、複数の異なるメッシュを読み込む方法がわからないので質問させて頂きます。
InitGeometry()関数の後半の記述がなんなのかも、理解できません。

殆ど手探りで作っています。このソースも、チュートリアルのサンプルに少し手を加えたものです。

[2] 環境  
 [2.1] OS : Windows Vista,
 [2.2] コンパイラ名 : VC++ 2008EE,

haruwo

Re: 複数のメッシュの読み込みについて

#2

投稿記事 by haruwo » 13年前

コード:

//-----------------------------------------------------------------------------
// Name: InitGeometry()
// Desc: Load the mesh and build the material and texture arrays
//-----------------------------------------------------------------------------
// 3Dモデル作成 xファイルの読み込み等
// マテリアルは、D3DXLoadMeshFromX関数で取得したマテリアルバッファから格納
// テクスチャは、D3DXCreateTextureFromFileで取得する。
HRESULT InitGeometry()
{
    LPD3DXBUFFER pD3DXMtrlBuffer;

    // D3DXLoadMeshFromX()によってxファイルを読み込む
    if( FAILED( D3DXLoadMeshFromX( "meka.x", D3DXMESH_SYSTEMMEM, 
                                   g_pd3dDevice, NULL,
                                   &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, 
                                   &g_pMesh ) ) )
    {
        // If model is not in current folder, try parent folder
		// 同一フォルダにxファイルが無い場合に探す
        if( FAILED( D3DXLoadMeshFromX( "..\\Tiger.x", D3DXMESH_SYSTEMMEM, 
                                    g_pd3dDevice, NULL, 
                                    &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, 
                                    &g_pMesh ) ) )
        {
            MessageBox(NULL, "Could not find tiger.x", "Meshes.exe", MB_OK);
            return E_FAIL;
        }
    }

    // We need to extract the material properties and texture names from the 
    // pD3DXMtrlBuffer
    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];
    if( g_pMeshMaterials == NULL )
        return E_OUTOFMEMORY;
    g_pMeshTextures  = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
    if( g_pMeshTextures == NULL )
        return E_OUTOFMEMORY;

    for( DWORD i=0; i<g_dwNumMaterials; i++ )
    {
        // Copy the material
        g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

        // Set the ambient color for the material (D3DX does not do this)
        g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse;

        g_pMeshTextures[i] = NULL;
        if( d3dxMaterials[i].pTextureFilename != NULL && 
            lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
        {
            // Create the texture
            if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                d3dxMaterials[i].pTextureFilename, 
                                                &g_pMeshTextures[i] ) ) )
            {
                // If texture is not in current folder, try parent folder
                const TCHAR* strPrefix = TEXT("..\\");
                TCHAR strTexture[MAX_PATH];
                StringCchCopy( strTexture, MAX_PATH, strPrefix );
                StringCchCat( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename );
                // If texture is not in current folder, try parent folder
                if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                    strTexture, 
                                                    &g_pMeshTextures[i] ) ) )
                {
                    MessageBox(NULL, "Could not find texture map", "Meshes.exe", MB_OK);
                }
            }
        }
    }
    // Done with the material buffer
    pD3DXMtrlBuffer->Release();

    return S_OK;
}


//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if( g_pMeshMaterials != NULL ) 
        delete[] g_pMeshMaterials;

    if( g_pMeshTextures )
    {
        for( DWORD i = 0; i < g_dwNumMaterials; i++ )
        {
            if( g_pMeshTextures[i] )
                g_pMeshTextures[i]->Release();
        }
        delete[] g_pMeshTextures;
    }
    if( g_pMesh != NULL )
        g_pMesh->Release();
    
    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();

    if( g_pD3D != NULL )
        g_pD3D->Release();
}

//-----------------------------------------------------------------------------
// Name: SetupMatrices()
// Desc: Sets up the world, view, and projection transform matrices.
//-----------------------------------------------------------------------------
// ここではワールド変換、カメラと注視点(ビュー変換)、射影変換を行うための行列を作成し、
// Direct3Dデバイスに渡す。
VOID SetupMatrices() 
{
    // Set up world matrix
    D3DXMATRIXA16 matWorld1, matWorld2;
	// 平行移動行列を作り位置を変える. mx,my,mz は、位置(座標)を格納する変数 移動処理に用いる
	D3DXMatrixTranslation( &matWorld1, mx, my, mz );
	// 回転行列 引数にangle を渡し、回転処理に用いる
    D3DXMatrixRotationY( &matWorld2, angle );//timeGetTime()/1000.0f );
	matWorld2 *= matWorld1;
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld2 );

    // Set up our view matrix. A view matrix can be defined given an eye point,
    // a point to lookat, and a direction for which way is up. Here, we set the
    // eye five units back along the z-axis and up three units, look at the 
    // origin, and define "up" to be in the y-direction.

    D3DXVECTOR3 vEyePt( 0.0f, 15.0f,-15.0f ); 
    D3DXVECTOR3 vLookatPt( 0.0f, 3.0f, 0.0f ); 
    D3DXVECTOR3 vUpVec( 0.0f, 5.0f, 0.0f );
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    // For the projection matrix, we set up a perspective transform (which
    // transforms geometry from 3D view space to 2D viewport space, with
    // a perspective divide making objects smaller in the distance). To build
    // a perpsective transform, we need the field of view (1/4 pi is common),
    // the aspect ratio, and the near and far clipping planes (which define at
    // what distances geometry should be no longer be rendered).
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
    // Clear the backbuffer and the zbuffer
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
                         D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
    
    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Setup the world, view, and projection matrices
        SetupMatrices();

        // Meshes are divided into subsets, one for each material. Render them in
        // a loop
        for( DWORD i=0; i<g_dwNumMaterials; i++ )
        {
            // Set the material and texture for this subset
            g_pd3dDevice->SetMaterial( &g_pMeshMaterials[i] );
            g_pd3dDevice->SetTexture( 0, g_pMeshTextures[i] );
        
            // Draw the mesh subset
            g_pMesh->DrawSubset( i );
        }

        // End the scene
        g_pd3dDevice->EndScene();
    }

    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
禁止単語が含まれていると表示されてしまい、全部掲載できないみたいですので、
問題の部分のみ載せて頂きたいです。
申し訳ありません。

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#3

投稿記事 by ぬっち » 13年前

Xファイルからメッシュを読み込むということでよいのですね?
それでしたら、少なくとも2つの方法があります。
1. 自分でXファイルを解析して読み込ませる。
2. DirectXのヘルパー関数を使う。
多分今回は、2のほうがよいと思いますので、こちらを使います。

DirectXにはXファイルからメッシュを作成してくれる、D3DXLoadMeshFromXという関数があります。
これを呼び出した後、マテリアルの設定、テクスチャの設定を行う形になります。
テクスチャの設定では、D3DXLoadMeshFromXを呼び出します。

基本的にこのような流れで自作関数を作って複数回呼び出せば、複数のメッシュを作成することが出来ます。
簡単なソースコードを載せておきますので参考にしてください。

コード:

LPDIRECT3DDEVICE9		g_pD3DDev;
LPD3DXMESH			g_pMesh;
D3DMATERIAL9*			g_pMtrl;
LPDIRECT3DTEXTURE*		g_pTex;
DWORD				g_NumMtrl;

bool CreateMesh( const char* pFileName )
{
	// Xファイルの読み込み
	LPD3DXBUFFER pD3DXMtrlBuf;
	D3DXLoadMeshFromX( pFileName, D3DXMESH_SYSTEMEM, g_pD3DDev, NULL, &g_pMtrl, NULL, &g_NumMtrl, &g_pMesh );

	// マテリアル情報の読み込み
	g_pMtrl = new D3DMATERIAL9[ g_NumMtrl ];
	g_pTex = new LPDIRECT3DTEXTURE9[ g_NumMtrl ];
	D3DXMATERIAL* pD3DXMtrl = static_cast < D3DXMATERIAL* > ( pD3DXMtrlBuf->GetBufferPointer() );
	for( DWORD i = 0; i < g_NumMtrl; i++ ){
		// Xファイルには環境光成分がないため、Diffuse色で置き換える。
		g_pMtrl[ i ].Ambient = g_pMtrl[ i ].Diffuse;
		// テクスチャの読み込み
		if( !g_pMtrl[ i ].pTextureFileName ){
			g_pTex[ i ] = NULL;
		}
		else{
			if( FAILED( D3DXCreateTextureFromFile( g_pD3DDev, g_pMtrl[ i ].pTextureFileName, &g_pTex[ i ] ) ) ){
				g_pTex[ i ] = NULL;
		}

		pD3DMtrlBuf->Release();
}

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR pStr, int cmd )
{
	// 初期化などのいろいろな処理
	CreateMesh( "mesh1.x" );		// 1つ目のメッシュ作成
	CreateMesh( "mesh2.x" );		// 2つ目のメッシュ作成
	// 終了処理など。
	return 0;
}
エラーチェックなどを除いているため、そのあたりは自分で処理することになりますが、流れとしてはこんな感じです。

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#4

投稿記事 by ぬっち » 13年前

って、丁度書き込みしている時に投稿されたので気がつきませんでした^^;
長くなってしまったので別のレスで書きます。

>pMesh が g_pMesh になっていたり
これは、ただ単に変数の命名の仕方を変えているだけです。
この場合ですと、例えばg_pMeshならこのg_はグローバル変数であることを示します。
まあつまり、グローバル変数だよっていうことがすぐにわかるようにするためにしているわけです。

>nitGeometry()関数の後半の記述がなんなのかも、理解できません
これは、マテリアル情報の処理を行っています。
簡略化したものを私のほうで用意しているので、それを見てください。流れをつかみやすいように、エラーチェックなど省略しまくっていますが。。。
(ただ、これですときちんと処理を行っていない部分もあるかもしれませんが^^;)

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#5

投稿記事 by ぬっち » 13年前

何度もすいません;;

掲載したソースコードが間違っていました。
LPDIRECT3DDEVICE9 g_pD3DDev;
LPD3DXMESH g_pMesh;
D3DMATERIAL9* g_pMtrl;
LPDIRECT3DTEXTURE* g_pTex;
DWORD g_NumMtrl;
ですが、このままではまずいですね。。。
C++のクラスをご存知なのなら、これをメンバ変数にしてしまうという方法がありますが、今回の場合はCで考えてみることにします。
本当は、可変長配列を使うとよいのですが、ここではただ単に配列としてみました。
当然このままではメッシュが作れる限界数が存在することになるので、最終的には可変長配列やクラス化を検討することとなります。
修正したコードを乗せておきますね。

コード:

// 今回は2つのメッシュを読み込むとする。同時に読み込めるメッシュはこの場合2つ。
LPDIRECT3DDEVICE9       g_pD3DDev;
LPD3DXMESH          g_pMesh[ 2 ];
D3DMATERIAL9*           g_pMtrl[ 2 ];
LPDIRECT3DTEXTURE*      g_pTex[ 2 ];
DWORD               g_NumMtrl[ 2 ];
 
bool CreateMesh( const char* pFileName, int index )
{
    // Xファイルの読み込み
    LPD3DXBUFFER pD3DXMtrlBuf;
    D3DXLoadMeshFromX( pFileName, D3DXMESH_SYSTEMEM, g_pD3DDev, NULL, &g_pMtrl[ index ], NULL, &g_NumMtrl[ index ], &g_pMesh[ index ] );
 
    // マテリアル情報の読み込み
    g_pMtrl[ index ] = new D3DMATERIAL9[ g_NumMtrl ];
    g_pTex[ index ] = new LPDIRECT3DTEXTURE9[ g_NumMtrl ];
    D3DXMATERIAL* pD3DXMtrl = static_cast < D3DXMATERIAL* > ( pD3DXMtrlBuf->GetBufferPointer() );
    for( DWORD i = 0; i < g_NumMtrl[ index ]; i++ ){
        // Xファイルには環境光成分がないため、Diffuse色で置き換える。
        g_pMtrl[ index ][ i ].Ambient = g_pMtrl[ index ][ i ].Diffuse;
        // テクスチャの読み込み
        if( !g_pMtrl[ index ][ i ].pTextureFileName ){
            g_pTex[ index ][ i ] = NULL;
        }
        else{
            if( FAILED( D3DXCreateTextureFromFile( g_pD3DDev, g_pMtrl[ index ][ i ].pTextureFileName, &g_pTex[ index ][ i ] ) ) ){
                g_pTex[ index ][ i ] = NULL;
        }
 
        pD3DMtrlBuf->Release();
}
 
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR pStr, int cmd )
{
    // 初期化などのいろいろな処理
    CreateMesh( "mesh1.x", 0 );        // 1つ目のメッシュ作成
    CreateMesh( "mesh2.x", 1 );        // 2つ目のメッシュ作成
    // 終了処理など。
    return 0;
}
あと、ソースコード見ましたが、2つあるD3DXLoadMeshFromXに異なるメッシュを指定しているのはなぜです?
これは、コメントから察するに多分パスに関する対策を行っていると思うので、別のメッシュを指定してはまずいのではないですか?

haruwo

Re: 複数のメッシュの読み込みについて

#6

投稿記事 by haruwo » 13年前

ぬっち さんが書きました:何度もすいません;;

掲載したソースコードが間違っていました。
LPDIRECT3DDEVICE9 g_pD3DDev;
LPD3DXMESH g_pMesh;
D3DMATERIAL9* g_pMtrl;
LPDIRECT3DTEXTURE* g_pTex;
DWORD g_NumMtrl;
ですが、このままではまずいですね。。。
C++のクラスをご存知なのなら、これをメンバ変数にしてしまうという方法がありますが、今回の場合はCで考えてみることにします。
本当は、可変長配列を使うとよいのですが、ここではただ単に配列としてみました。
当然このままではメッシュが作れる限界数が存在することになるので、最終的には可変長配列やクラス化を検討することとなります。
修正したコードを乗せておきますね。
あと、ソースコード見ましたが、2つあるD3DXLoadMeshFromXに異なるメッシュを指定しているのはなぜです?
これは、コメントから察するに多分パスに関する対策を行っていると思うので、別のメッシュを指定してはまずいのではないですか?
あ、いえ、大丈夫です。
今、ソースを修正していました。

すみません。C++は詳しくないのです。

異なるメッシュを指定している筈は・・・・って本当ですね。
早速、修正しました。申し訳ありません・・・。

今、ぬっちさんのソースを参考に、自分なりに書き直しています。
ありがとうございます。本当、すみません・・・。

haruwo

Re: 複数のメッシュの読み込みについて

#7

投稿記事 by haruwo » 13年前

すみません。
手直ししたのですが、下記のようなエラーが生じてしまいます。

コード:

1>------ ビルド開始: プロジェクト: game_DirectX, 構成: Debug Win32 ------
1>コンパイルしています...
1>Meshes.cpp
1>c:\program files\microsoft directx sdk (february 2007)\include\d3d9types.h(1385) : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(45) : error C2664: 'D3DXLoadMeshFromXA' : 5 番目の引数を 'D3DMATERIAL9 **' から 'LPD3DXBUFFER *' に変換できません。(新しい機能 ; ヘルプを参照)
1>        指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(48) : error C2440: '初期化中' : 'DWORD [2]' から 'unsigned int' に変換できません。
1>        この変換が可能なコンテキストはありません。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(49) : error C2440: '初期化中' : 'DWORD [2]' から 'unsigned int' に変換できません。
1>        この変換が可能なコンテキストはありません。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(51) : error C2446: '<' : 'DWORD *' 型から 'DWORD' 型への変換ができません。
1>        この変換が可能なコンテキストはありません。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(51) : error C2040: '<' : 'DWORD' は 'DWORD [2]' と間接操作のレベルが異なります。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(55) : error C2039: 'pTextureFileName' : '_D3DMATERIAL9' のメンバではありません。
1>        c:\program files\microsoft directx sdk (february 2007)\include\d3d9types.h(155) : '_D3DMATERIAL9' の宣言を確認してください。
1>c:\users\yoshikazu\documents\visual studio 2008\projects\game_directx\game_directx\meshes.cpp(59) : error C2039: 'pTextureFileName' : '_D3DMATERIAL9' のメンバではありません。
1>        c:\program files\microsoft directx sdk (february 2007)\include\d3d9types.h(155) : '_D3DMATERIAL9' の宣言を確認してください。
1>game_DirectX - エラー 7、警告 1
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#8

投稿記事 by ぬっち » 13年前

うーん、いくつか間違ってる部分がありました;;
申し訳ない。。。

面倒ですので、前にあげてもらったソースコードをこちらで編集します。
しばらくお待ちください。

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#9

投稿記事 by ぬっち » 13年前

とりあえず、DirectX SDKのtutorialの6番目のMesh読み込みのプログラムで、複数のメッシュが読み込めるように変更しました。
ソース内でサンプルを改良したのは//****で挟むようになっています。
ここで表示したのは同じモデルですが、別のファイルからも取得しているので、複数のメッシュからの読み込みに成功していると考えられます。("tiger.x"と"tiger2.x")
もちろん、CreateMeshの片方を削除すると、1つのモデルしか表示されません。
確認してみてください。
添付ファイル
main.cpp
(13.72 KiB) ダウンロード数: 229 回

ぬっち
記事: 105
登録日時: 13年前
連絡を取る:

Re: 複数のメッシュの読み込みについて

#10

投稿記事 by ぬっち » 13年前

複数のファイルを添付できなかったので、実行結果を掲載します。
sample.jpg
sample.jpg (30.2 KiB) 閲覧数: 5704 回

haruwo

Re: 複数のメッシュの読み込みについて

#11

投稿記事 by haruwo » 13年前

ありがとうございます。
確認致しました。

DirectXはまだ始めたばかりだったので、
手探りだったのです・・・。

本当にご迷惑をおかけしたと思います。

申し訳ありませんでした。

ソースを見て、勉強させて頂きます。
ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る