ページ 11

メッシュの面数の取得について

Posted: 2016年3月07日(月) 12:03
by cattail
こんにちは、cattailです。
いつも教えて下さいましてありがとうございます。
また少し教えて頂きたいことがあります。
鎌田茂雄氏著のGAMECODINGとか逆引き大全500とかをコピペしながら勉強しています。
メッシュを表示したり、移動させたりできて、自分では出来てる感があったのですが、
やっぱりコピペ主体なもので理解できない部分が多々あります。

移動させるメッシュに丸い影を付けていたのですが、シャドウボリュームでやってみようと思っています。
メッシュの面数を取得したいのですが止まってしまいます。
レンダリングの最後の方の、
DWORD mensu = Thing[0].pMesh->GetNumFaces();
で止まってしまうみたいです。

動かないメッシュだと大丈夫なのですが、アニメするメッシュだと止まってしまいます。
以下のコードは本に出ていた一部変更したものですが(ほとんどコピペですが)、
アニメファイル読み込みの、xfileの読み込み1だと止まり、静止ファイル読み込みの、xfileの読み込み2だと大丈夫なようです。
xfileの読み込み1では、pMeshに情報が入っていないと思うのですが、メッシュ情報がどこにあるのかもわかりません。
教えて頂ければと思います。

Windows7
DirectX9
Microsoft Visual Studio 2008
(CなのかC++なのかも実はあまり分かっていません)
です。

よろしくお願いします。

コード:

//構造体 ////////////////////////////////////////////////////////////////////////////////////////////////////
struct THING
{	
	LPD3DXMESH pMesh;
	LPD3DXFRAME pFrameRoot;
    	LPD3DXANIMATIONCONTROLLER pAnimController;
	D3DMATERIAL9* pMeshMaterials;
	LPDIRECT3DTEXTURE9* pMeshTextures; 
	DWORD dwNumMaterials;
	D3DXVECTOR3 vecPosition;
	D3DXMATRIX matRotation;
	D3DXMATRIX matWorld;

	THING()
	{
		ZeroMemory(this,sizeof(THING));
	}
};

//xfileの読み込み1 ////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT InitThing1(THING *pThing,LPSTR szXFileName,D3DXVECTOR3* pvecPosition)
{
	// メッシュの初期位置
	memcpy(&pThing->vecPosition,pvecPosition,sizeof(D3DXVECTOR3));

	// Xファイルからアニメーションメッシュを読み込み作成する
	if( FAILED( 
	D3DXLoadMeshHierarchyFromX(szXFileName, D3DXMESH_MANAGED, pDevice, &cHierarchy, 
		                                          NULL, &pThing->pFrameRoot, &pThing->pAnimController)))
	{
            MessageBox(NULL, "Xファイルの読み込みに失敗しました",szXFileName, MB_OK);
            return E_FAIL;   
    	}
	//
	AllocateAllBoneMatrices(pThing,pThing->pFrameRoot);

	return S_OK;
}


//xfileの読み込み2 ////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT InitThing2(THING *pThing,LPSTR szXFileName,D3DXVECTOR3* pvecPosition)
{
	// メッシュの初期位置
	memcpy(&pThing->vecPosition,pvecPosition,sizeof(D3DXVECTOR3));
	// Xファイルからメッシュをロードする	
	LPD3DXBUFFER pD3DXMtrlBuffer = NULL;

	if( FAILED( D3DXLoadMeshFromX( szXFileName, D3DXMESH_SYSTEMMEM, 
            pDevice, NULL, &pD3DXMtrlBuffer, NULL,
			&pThing->dwNumMaterials, &pThing->pMesh ) ) )
    	{
            MessageBox(NULL, "Xファイルの読み込みに失敗しました",szXFileName, MB_OK);
            return E_FAIL;   
    	}
	D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
	pThing->pMeshMaterials = new D3DMATERIAL9[pThing->dwNumMaterials];
    	pThing->pMeshTextures  = new LPDIRECT3DTEXTURE9[pThing->dwNumMaterials];

	for( DWORD i=0; i<pThing->dwNumMaterials; i++ )
	{ 
		pThing->pMeshMaterials[i] = d3dxMaterials[i].MatD3D;		
        	pThing->pMeshMaterials[i].Ambient = pThing->pMeshMaterials[i].Diffuse;
        	pThing->pMeshTextures[i] = NULL;
        	if( d3dxMaterials[i].pTextureFilename != NULL && 
        	    lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
        	{       
        	    if( FAILED( D3DXCreateTextureFromFile( pDevice, 
                                                d3dxMaterials[i].pTextureFilename, 
                                                &pThing->pMeshTextures[i] ) ) )
            		{      
                	MessageBox(NULL, "テクスチャの読み込みに失敗しました", NULL, MB_OK);
			}
        	}
    	}
	pD3DXMtrlBuffer->Release();
    
	return S_OK;
}

//レンダリング////////////////////////////////////////////////////////////////////////////////////////////////////
VOID RenderThing(THING* pThing)
{
	static FLOAT fAnimTimeHold=fAnimTime;
	//ワールドトランスフォーム(絶対座標変換)
	D3DXMATRIXA16 matWorld,matPosition;
	D3DXMatrixIdentity(&matWorld);
	D3DXMatrixTranslation(&matPosition,pThing->vecPosition.x,pThing->vecPosition.y,
		 pThing->vecPosition.z);
	D3DXMatrixMultiply(&matWorld,&matWorld,&matPosition);
     	pDevice->SetTransform( D3DTS_WORLD, &matWorld );

	 // ビュートランスフォーム(視点座標変換)
     	D3DXVECTOR3 vecEyePt( 4.0f, 4.0f,-5.5f );  //カメラ(視点)位置
     	D3DXVECTOR3 vecLookatPt( 0.0f, 0.0f, 0.0f );//注視位置
     	D3DXVECTOR3 vecUpVec( 0.0f, 1.0f, 0.0f );//上方位置
     	D3DXMATRIXA16 matView;
     	D3DXMatrixLookAtLH( &matView, &vecEyePt, &vecLookatPt, &vecUpVec );
     	pDevice->SetTransform( D3DTS_VIEW, &matView );
	 // プロジェクショントランスフォーム(射影変換)
     	D3DXMATRIXA16 matProj;
     	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, (FLOAT)WINDOW_WIDTH/(FLOAT)WINDOW_HEIGHT, 1.0f, 100.0f );
     	pDevice->SetTransform( D3DTS_PROJECTION, &matProj );     
	 // ライトをあてる 白色で鏡面反射ありに設定
	 D3DXVECTOR3 vecDirection(1,-0.5,1);
     	D3DLIGHT9 light;
     	ZeroMemory( &light, sizeof(D3DLIGHT9) );
     	light.Type       = D3DLIGHT_DIRECTIONAL;
     	light.Diffuse.r  = 1.0f;
     	light.Diffuse.g  = 1.0f;
     	light.Diffuse.b  = 1.0f;    
	light.Specular.r=1.0f;
	light.Specular.g=1.0f;
	light.Specular.b=1.0f;
     	D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDirection );
     	light.Range       = 200.0f;
     	pDevice->SetLight( 0, &light );
     	pDevice->LightEnable( 0, TRUE );
	
	 //レンダリング
	 UpdateFrameMatrices(pThing->pFrameRoot, &matWorld);
	 DrawFrame(pDevice,pThing->pFrameRoot);
	 pThing->pAnimController->AdvanceTime(fAnimTime-fAnimTimeHold,NULL);
	 fAnimTimeHold=fAnimTime;
	 if(boPlayAnim)
	 {
		 fAnimTime+=0.0001f;		 
	 }			

	//ここを加えて見ました//////////////////////////////////	
	DWORD mensu = Thing[0].pMesh->GetNumFaces();//←←←←←ここで止まってしまうみたいです。
	char co[30];
	sprintf_s(co,"面数:%2d",int(mensu));
	RenderString(co,10,64);
	////////////////////////////////////////////////////////

}

Re: メッシュの面数の取得について

Posted: 2016年3月08日(火) 05:25
by へにっくす
とまるというか、そもそもコンパイル通りました?
Thing[0]のThingってどこにあるんでしょうか。

試しに以下のように変えたらどうなりますか。

コード:

    //ここを加えて見ました//////////////////////////////////  
    DWORD mensu = 0;                       // 変更
    if (pThing->pMesh != NULL) {           // 変更
        pThing->pMesh->GetNumFaces();      // 変更
    }                                      // 変更
    char co[30];
    sprintf_s(co,"面数:%2d",int(mensu));
    RenderString(co,10,64);
    ////////////////////////////////////////////////////////

Re: メッシュの面数の取得について

Posted: 2016年3月08日(火) 08:20
by cattail
>へにっくすさん
ご返事ありがとうございます!
コンパイルは通っていたのですが。
さっそく直してみましたら止まらなくなりました。
初歩的なことみたいですみませんでした。恥ずかしい!
ただ、メッシュが表示されていて、面数が0と表示されましたので、
pThing->pMesh は NULL だと思われます。
D3DXLoadMeshHierarchyFromXを使用した場合は、
pMeshに情報を入れるというか、メッシュ情報を取得する方法はあるのでしょうか?
これから少し調べてみます。
ちょっと先が見えてきたような気もするのでがんばります。

Re: メッシュの面数の取得について

Posted: 2016年3月08日(火) 10:54
by cattail
ネットを調べてみると、
D3DXLoadMeshHierarchyFromXの4つ目の引数 pAlloc が何かあるのかなと思います。
pAlloc ID3DXAllocateHierarchy はユーザーが実装しないといけないということなので、
実装できたらメッシュ情報も取得できるようになるのでしょうか?
引き続き調べます。
ただ、僕にはやたら難しく分からないまま読んでいる感じです。

コード:

	//インスタンス
	MY_HIERARCHY cHierarchy;
	
	//xfile読み込み
	D3DXLoadMeshHierarchyFromX(szXFileName, D3DXMESH_MANAGED, pDevice, &cHierarchy, 
		                                          NULL, &pThing->pFrameRoot, &pThing->pAnimController)))
読み込み部分は上のようになっています。
ほとんど本(18章スキン・メッシュアニメーション)と同じコードです。
cHierarchyの中にメッシュ情報が入るのかな、とは思いますけど、取り出し方が分かりません。
自分ではちょっと無理なのでは思い始めています。

Re: メッシュの面数の取得について

Posted: 2016年3月08日(火) 17:20
by cattail
えーと、
自分でも何が知りたいのかが段々分かってきました。
わーお、今さらですか、みたいな感じです。

上で、
>pAlloc ID3DXAllocateHierarchy はユーザーが実装しないといけないということなので、
>実装できたらメッシュ情報も取得できるようになるのでしょうか?

と書きましたが、既にスキンメッシュは表示されていますので、実装はできていると思われます。
ほとんどコピペではありますが、各コンテナは実装されているようです。
そこで、自分の知りたいことは、そこからどうやってメッシュ情報を取り出すか、です。
本からコピペした以下のコードがあります。

コード:

//メッシュコンテナーを作成する
HRESULT MY_HIERARCHY::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA* pMeshData,
                            CONST D3DXMATERIAL* pMaterials, CONST D3DXEFFECTINSTANCE* pEffectInstances,
							DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, 
                            LPD3DXMESHCONTAINER *ppMeshContainer) 
{

    HRESULT hr;
    MYMESHCONTAINER *pMeshContainer = NULL;
    INT iFacesAmount;
    INT iMaterial;
    LPDIRECT3DDEVICE9 pDevice = NULL;
    LPD3DXMESH pMesh = NULL;
    *ppMeshContainer = NULL;
	DWORD dwBoneAmt=0;

    pMesh = pMeshData->pMesh;
    pMeshContainer = new MYMESHCONTAINER;
    if (pMeshContainer == NULL)
    {
        return E_OUTOFMEMORY;
    }
    ZeroMemory(pMeshContainer, sizeof(MYMESHCONTAINER));

	pMeshContainer->Name=new TCHAR[lstrlen(Name) + 1];	
    if (!pMeshContainer->Name)
	{
		return E_FAIL;
	}
	strcpy(pMeshContainer->Name,Name);
    pMesh->GetDevice(&pDevice);
    iFacesAmount = pMesh->GetNumFaces();
	
    // 当該メッシュが法線を持たない場合は法線を追加する
    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 
                                    pMesh->GetFVF() | D3DFVF_NORMAL, 
                                    pDevice, &pMeshContainer->MeshData.pMesh );
        if (FAILED(hr))
		{
			return E_FAIL;
		}

        pMesh = pMeshContainer->MeshData.pMesh;
        D3DXComputeNormals( pMesh, NULL );
    }
    else 
    {
        pMeshContainer->MeshData.pMesh = pMesh;
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
        pMesh->AddRef();
    }
	//メッシュのマテリアル設定
    pMeshContainer->NumMaterials = max(1, NumMaterials);
    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];
    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];
    pMeshContainer->pAdjacency = new DWORD[iFacesAmount*3];
    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL))
    {
        return E_FAIL;
    }
    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * iFacesAmount*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)
            {
                TCHAR strTexturePath[MAX_PATH];
                strcpy( strTexturePath,  pMeshContainer->pMaterials[iMaterial].pTextureFilename );
                if( FAILED( D3DXCreateTextureFromFile( pDevice, strTexturePath, 
                                                        &pMeshContainer->ppTextures[iMaterial] ) ) )
                    pMeshContainer->ppTextures[iMaterial] = 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();
		dwBoneAmt = pSkinInfo->GetNumBones();
		pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[dwBoneAmt];

		for (DWORD i= 0; i < dwBoneAmt; i++)
		{	
			memcpy(&pMeshContainer->pBoneOffsetMatrices[i],
				pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i),sizeof(D3DMATRIX));	
		}
		if(FAILED(pMeshContainer->pSkinInfo->ConvertToBlendedMesh(
			pMesh,                                       
			NULL,	pMeshContainer->pAdjacency,NULL, NULL, NULL,
			&pMeshContainer->dwWeight,
			&pMeshContainer->dwBoneAmt,
			&pMeshContainer->pBoneBuffer,
			&pMeshContainer->MeshData.pMesh)
			))
		{
			return E_FAIL;
		}
	}
	//ローカルに生成したメッシュコンテナーを呼び出し側にコピーする
	*ppMeshContainer = pMeshContainer;

    return S_OK;
}
このコードは、ほとんど理解できないのですが、たぶんメッシュ情報の格納に使われている部分だと思います。
D3DXMESHCONTAINER構造体に情報を入れている部分だと思います。
だとすると、ここからメッシュ情報を取り出せばいいのではないかと考えています。

今のところはここまでです。
僕にとっては非常にややこしくて難しすぎます。
ここからメッシュの面数を取り出すにはどうしたらいいのでしょうか?

Re: メッシュの面数の取得について

Posted: 2016年3月09日(水) 05:41
by へにっくす
No.1のソースの49行目で、
&pThing->pMesh
があるので、ここで読み込み関数D3DXLoadMeshFromXが成功すれば何等かの情報が入るはずです。
InitThing2関数は呼ばれていますか(掲示されたソースでは見当たりません)?
呼ばれていなければその中の処理も行われないので、何も入っていないのは当然ですが。

Re: メッシュの面数の取得について

Posted: 2016年3月09日(水) 08:50
by cattail
>へにっくす さん
ご返事ありがとうございます。
アニメーションメッシュ、スキンメッシュをロードするときはInitThing1関数を呼びだし、
それ以外をロードするときはInitThing2関数を呼び出しています。
今は、アニメーションメッシュなどの面数を取得したいのでInitThing1関数でロードしています。
また、アニメしないメッシュではInitThing2関数でロードし、こちらは面数は取れています。(ちょっと怪しいけど)
キャラが歩くアニメのメッシュにシャドウボリュームで影を付けたいというのが目的なので、
InitThing1関数でロードしています。
色々やりましたが、ちょっと今は出来そうにないです。

Re: メッシュの面数の取得について

Posted: 2016年3月10日(木) 05:13
by へにっくす
想定済みってことですね。

以下参考になるかもしれないページ
(その25にあなたの言われたAllocについて簡単な説明がありますが、その23から順に読んでいくことをお勧めします)
http://marupeke296.com/DirectXMain.html

もう知っているということならすみません

Re: メッシュの面数の取得について

Posted: 2016年3月10日(木) 08:00
by cattail
>へにっくす さん
何度もすみません、ありがとうございます。
リンクして頂いたページをじっくり読んでみたいと思います。
また夜中に目が覚めてピコーンと思い当たるフシがあったので、
上記ページと合わせながらこれから試してみます。

Re: メッシュの面数の取得について

Posted: 2016年3月10日(木) 11:23
by cattail
とりあえず、pAllocのことは置いておきまして、
D3DXLoadMeshHierarchyFromXで6番目の引数に&pThing->pFrameRootがあるので、
pFrameRootの奥の方に何かあるのかなと思って調べたら、構造体の奥にpMeshがありました。
それで以下のようにしてみましたが、同じく止まってしまいました。
いけるかなと思ったんですがダメでした。
もう少しやってみます。

コード:

	D3DXLoadMeshHierarchyFromX(szXFileName, D3DXMESH_MANAGED, pDevice, &cHierarchy, 
					NULL, &pThing->pFrameRoot, &pThing->pAnimController)))

コード:

	DWORD mensu = 0;

	if(pThing->pFrameRoot != NULL){

		mensu = pThing->pFrameRoot->pMeshContainer->MeshData.pMesh->GetNumFaces();//ここで止まります

	}

	char co[30];
	sprintf_s(co,"面数:%2d",int(mensu));
	RenderString(co,10,64);