# Motion of model by code

This topic is 2659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have a model of a soldier in format .x

My game is in 3D platform like booster trooper:

If you look at the video, the character's arms move up and down according to the crosshair (mouse)
I am wanting to do something, but I have no idea how to move the arms of my character by code

I'm using DirectX and C++

##### Share on other sites
Heya,

There are several techniques to doing this but I'll tell you how I like to do it (:

But first, do you know how to do skeletal animation? Also, do you know how to blend between multiple animations?

If not that is a pre-requisite and something you want to learn.

Anyways... What I would do in this situation is split the body into upper body and lower body bone groups.

This makes it so you can play a different animation on the lower body than the upper body - ie the lower body can crouch, run and jump while the upper body can aim, shoot and reload.

Next up, for the upper body aiming, let's assume the player is just idling ie their upper body is just aiming, not shooting or reloading or anything.

I'd make 3 upper body animations for the "aiming" state. One pointed straight up, one pointed straight ahead, and one pointed straight down.

Calculate the angle that the player is aiming and convert it into a percent - IE if they were pointing 45 degrees upwards, they would be pointing 50% upwards.

What you would do then is play the straight forward animation on the upper body, along with the straight up animation which you would blend in 50% of the way.

As the player points their gun higher, the % they are pointing vertical becomes higher and so the amount you blend in the pointing up animation becomes higher too.

When you are pointed up 100% of the way up, all you see is the pointing up animation. When you are pointed up 0% of the way, all you see is the pointing forward animation. When you are between 0% and 100% you see a blend of the 2 which makes it look like the player is able to smoothly point up or down.

BTW you just do the mirror of this for pointing downwards and blend in the pointing down animation instead of the pointing up animation.

Essentially you are ALWAYS playing the pointing forward animation, and from there you figure out which animation to blend into it (the up or down pointing one) and how much to blend them (based on how high or low the player is aiming).

Also, if you have other animations such as firing and reloading, you would make the 3 animations for each of those as well (forward, up and down).

Hope this helps, let me know if you are confused about any of this and I can try and elaborate.

##### Share on other sites
Well, until the party to split the model into the top and bottom, I understand.
after that I got confused

##### Share on other sites
No need to "split" anything. However, you need to be familiar with how your code updates the bone matrices, usually done once per frame by multiplying it by its parent's matrix.

In your model, determine which "bone" moves the arm (a bone is just a matrix). As the user moves the mouse, determine the angle to rotate the arm. That will probably be based on the bone's world position in relation to the target (apparently moved by the mouse). Multiply the bone matrix by a rotation matrix based on the determined angle before you multiply it by it's parent's matrix.

You may have to take into consideration the parent's rotation.

##### Share on other sites
How can I control the bones in format .x?

##### Share on other sites
Is your "soldier" x-file an animated model?

If not, you'll have to create one.

If you're working in 2D, a much easier alternative is just to use sprites rather than a 3D model - a sprite for the body and a sprite for the arm (or quads with transparent textures).

##### Share on other sites
"No need to "split" anything."

Good luck when you want to play a lower body animation separately from the upper body animation! :P

##### Share on other sites
Yes, my soldier is a animated model

is model 3d, my game is 3D

Astrix256 try to explain again? I got confused

I look my model (with wordpad)
 Frame Bip01_Head {         FrameTransformMatrix {          0.979719, 0.200374, -0.000001, 0.000000,          -0.200374, 0.979719, 0.000000, 0.000000,          0.000001, 0.000000, 1.000000, 0.000000,          4.443601, 0.000000, 0.000000, 1.000000;;         }        }        Frame Bip01_L_Arm {         FrameTransformMatrix {          -0.069033, -0.001290, -0.997614, 0.000000,          0.018641, -0.999826, 0.000003, 0.000000,          -0.997440, -0.018596, 0.069045, 0.000000,          0.000004, 0.003534, -1.732721, 1.000000;;         }         Frame Bip01_L_Arm1 {          FrameTransformMatrix {           0.998888, 0.004094, -0.046963, 0.000000,           -0.005302, 0.999658, -0.025617, 0.000000,           0.046842, 0.025837, 0.998568, 0.000000,           6.384776, 0.000000, -0.000001, 1.000000;;          }

They are the bones of the model, right?
There is no way to control the bones of the arm by code? would be much easier

thanks

##### Share on other sites
Quote:
 Atrix256 said: Good luck when you want to play a lower body animation separately from the upper body animation! :P

You don't need separate animations for upper and lower body. The arm is animated as desired when the final bone matrices for the animation is being calculated each frame during whatever animation is being played - jumping, running, standing still, etc.

@VitaliBR:

Yep, that looks like an animated model.

At some point in your code for animating the model, you should be calculating final bone matrices each frame, before you render the animation (however you do that). In that calculation loop, you would modify the rotation of the arm as desired.

EDIT: The result will be similar to what Atrix256 is describing, only you'll only need one rather than 3 animations for each movement type (running, jumping,...).

##### Share on other sites
Can bones be moved in code (i.e how do games like half life have
animations but can move the head from side to side seemingly seperate
to the main animation)?

##### Share on other sites
Quote:
 Can bones be moved in code...?

Yep. See my previous posts.

A common method for animating x-file models is (in DX9) to use ID3DXAnimationController. Are you using DX9? If so, are you using the D3DX animation controller?

##### Share on other sites
Yes, i'm using Dx

but no ID3DXAnimationController :/

##### Share on other sites
Quote:
 Are you animating your model? ... Are you using DX9?

Still not enough information to help you. See the above questions. There are several versions of DirectX - which version are you using?

Have you implemented code to animate your model? Does it load and play the animation correctly?

##### Share on other sites
I'm using DirectX 9

my code to animation of model:

SkinMesh.h
//////////////////////////////////////////////////////////////////////// SkinMesh.h: interface for the CSkinMesh class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_SKINMESH_H)#define AFX_SKINMESH_H#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <tchar.h>#include <d3dx9.h>#include <d3dx9mesh.h>#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }//-----------------------------------------------------------------------------// Name: struct D3DXFRAME_DERIVED// Desc: Structure derived from D3DXFRAME so we can add some app-specific//       info that will be stored with each frame//-----------------------------------------------------------------------------struct D3DXFRAME_DERIVED: public D3DXFRAME{    D3DXMATRIXA16        CombinedTransformationMatrix;};//-----------------------------------------------------------------------------// Name: struct D3DXMESHCONTAINER_DERIVED// Desc: Structure derived from D3DXMESHCONTAINER so we can add some app-specific//       info that will be stored with each mesh//-----------------------------------------------------------------------------struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER{    LPDIRECT3DTEXTURE9*  ppTextures;       // array of textures, entries are NULL if no texture specified                                        // SkinMesh info                 LPD3DXMESH           pOrigMesh;    LPD3DXATTRIBUTERANGE pAttributeTable;    DWORD                NumAttributeGroups;     DWORD                NumInfl;    LPD3DXBUFFER         pBoneCombinationBuf;    D3DXMATRIX**         ppBoneMatrixPtrs;    D3DXMATRIX*          pBoneOffsetMatrices;    DWORD                NumPaletteEntries;    bool                 UseSoftwareVP;    DWORD                iAttributeSW;     // used to denote the split between SW and HW if necessary for non-indexed skinning};// enum for various skinning modes possibleenum METHOD {    D3DNONINDEXED,    D3DINDEXED,    SOFTWARE,    NONE};class CSkinMesh;//-----------------------------------------------------------------------------// Name: class CAllocateHierarchy// Desc: Custom version of ID3DXAllocateHierarchy with custom methods to create//       frames and meshcontainers.//-----------------------------------------------------------------------------class CAllocateHierarchy: public ID3DXAllocateHierarchy{public:    STDMETHOD(CreateFrame)(THIS_ LPCTSTR Name, LPD3DXFRAME *ppNewFrame);#if ((D3D_SDK_VERSION & 0xFF)==31)	//ÕâÀïÊÇDirectx9.0bµÄ    STDMETHOD(CreateMeshContainer)(THIS_ LPCTSTR Name, 							LPD3DXMESHDATA pMeshData,                            LPD3DXMATERIAL pMaterials, 							LPD3DXEFFECTINSTANCE pEffectInstances, 							DWORD NumMaterials,                             DWORD *pAdjacency, 							LPD3DXSKININFO pSkinInfo,                             LPD3DXMESHCONTAINER *ppNewMeshContainer);#else	//ÕâÀïÊÇDirectx9.0cµÄ    STDMETHOD(CreateMeshContainer)(		THIS_ LPCSTR Name,         CONST D3DXMESHDATA *pMeshData,        CONST D3DXMATERIAL *pMaterials,         CONST D3DXEFFECTINSTANCE *pEffectInstances,         DWORD NumMaterials,         CONST DWORD *pAdjacency,         LPD3DXSKININFO pSkinInfo,         LPD3DXMESHCONTAINER *ppNewMeshContainer);#endif    STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);    STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);    CAllocateHierarchy(CSkinMesh *pSkinMesh) :m_pSkinMesh(pSkinMesh) {}public:	CSkinMesh*		m_pSkinMesh;};//ÃÉÆ¤¶¯»­class CSkinMesh  {public:	VOID SetAnim(BOOL bAnim);	BOOL CSkinMesh::InterSect( D3DVECTOR *pRayOrig, D3DVECTOR *pRayDir,D3DVECTOR* pVRet);	VOID UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );	LPD3DXANIMATIONCONTROLLER GetAnimController() {return m_pAnimController;};	BOOL SetAnimationName(char *strAnimName);//	void SetPosition(D3DXVECTOR3 &vPos)			{m_vPos=vPos; };//	void SetPosition(float x,float y,float z)	{m_vPos.x=x;m_vPos.y=y;m_vPos.z=z;};	VOID Render(float fTimeFromLastFrame,D3DXVECTOR3 vPos,D3DXVECTOR3 rotation,float scale=1.0f);	HRESULT LoadFromXFile(char* strFileName);	HRESULT GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED *pMeshContainer);	LPD3DXMESH  getMesh(); //Retuns of Mesh	CSkinMesh(LPDIRECT3DDEVICE9 pD3DDevice);//	CSkinMesh(LPDIRECT3DDEVICE9 pD3DDevice,char* strFileName);	HRESULT CalculateBondingBox(LPD3DXFRAME pFrameParent, D3DXVECTOR3 *pVmin,D3DXVECTOR3 *pVmax)	{		static LPVOID pV; 		static LPD3DXMESH pMesh;		static LPD3DXMATRIX pMat;		static D3DXVECTOR3 vMin,vMax; 		static D3DXVECTOR3 vTransFormed;		if(pFrameParent->pMeshContainer)		{			pMesh=pFrameParent->pMeshContainer->MeshData.pMesh;    			pMat=&(((D3DXFRAME_DERIVED*)pFrameParent)->CombinedTransformationMatrix);			pMesh->LockVertexBuffer(0,&pV); 			D3DXComputeBoundingBox((LPD3DXVECTOR3)pV,pMesh->GetNumVertices(),				pMesh->GetNumBytesPerVertex(),&vMin,&vMax); 						vTransFormed.x=pMat->_11*vMin.x+pMat->_21*vMin.y+pMat->_31*vMin.z+pMat->_41;			vTransFormed.y=pMat->_12*vMin.x+pMat->_22*vMin.y+pMat->_32*vMin.z+pMat->_42;			vTransFormed.z=pMat->_13*vMin.x+pMat->_23*vMin.y+pMat->_33*vMin.z+pMat->_43;			if(vTransFormed.x<pVmin->x) pVmin->x=vTransFormed.x;			if(vTransFormed.y<pVmin->y) pVmin->y=vTransFormed.y;			if(vTransFormed.z<pVmin->z) pVmin->z=vTransFormed.z;			vTransFormed.x=pMat->_11*vMax.x+pMat->_21*vMax.y+pMat->_31*vMax.z+pMat->_41;			vTransFormed.y=pMat->_12*vMax.x+pMat->_22*vMax.y+pMat->_32*vMax.z+pMat->_42;			vTransFormed.z=pMat->_13*vMax.x+pMat->_23*vMax.y+pMat->_33*vMax.z+pMat->_43;			if(vTransFormed.x>pVmax->x) pVmax->x=vTransFormed.x;			if(vTransFormed.y>pVmax->y) pVmax->y=vTransFormed.y;			if(vTransFormed.z>pVmax->z) pVmax->z=vTransFormed.z;			pMesh->UnlockVertexBuffer(); 		}		//else return S_OK;				if(pFrameParent->pFrameSibling)			CalculateBondingBox(pFrameParent->pFrameSibling,pVmin,pVmax);				if(pFrameParent->pFrameFirstChild)			CalculateBondingBox(pFrameParent->pFrameFirstChild,pVmin,pVmax);		return S_OK;		}	virtual ~CSkinMesh();	LPDIRECT3DVERTEXSHADER9 m_pIndexedVertexShader[4];	D3DXMATRIXA16*			m_pBoneMatrices;	UINT					m_NumBoneMatricesMax;	METHOD					m_SkinningMethod;	D3DCAPS9				m_d3dCaps;	D3DXVECTOR3				m_vObjectCenter;	// Center of bounding sphere of object	FLOAT					m_fObjectRadius;	// Radius of bounding sphere of object	D3DXVECTOR3				m_vMin;				// Center of bounding sphere of object	D3DXVECTOR3				m_vMax;				// Center of bounding sphere of objectprotected:	VOID DrawMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase);	VOID DrawFrame(LPD3DXFRAME pFrame);	HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase );	HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );	//	FLOAT						m_fRotateAngle;	BOOL						m_bMoving;	LPDIRECT3DDEVICE9			m_pd3dDevice;	LPD3DXFRAME					m_pFrameRoot;	LPD3DXANIMATIONCONTROLLER	m_pAnimController;	FLOAT						m_fElapsedTime;      // Time elapsed since last frame    LPD3DXMESH m_SkinMesh;};#endif // !defined(AFX_SKINMESH_H__AE3ADAAF_4BE2_4B23_9A1D_9379FA1BAFD9__INCLUDED_)

SkinMesh.cpp
// SkinMesh.cpp: implementation of the CSkinMesh class.////////////////////////////////////////////////////////////////////////#include "SkinMesh.h"//-----------------------------------------------------------------------------// Name: AllocateName()// Desc: Allocates memory for a string to hold the name of a frame or mesh//-----------------------------------------------------------------------------HRESULT AllocateName( LPCTSTR Name, LPTSTR *pNewName ){    UINT cbLength;	    if (Name != NULL)    {        cbLength = lstrlen(Name) + 1;        *pNewName = new TCHAR[cbLength];        if (*pNewName == NULL)            return E_OUTOFMEMORY;        memcpy(*pNewName, Name, cbLength*sizeof(TCHAR));    }    else    {        *pNewName = NULL;    }	    return S_OK;}//-----------------------------------------------------------------------------// Name: CAllocateHierarchy::CreateFrame()// Desc: //-----------------------------------------------------------------------------HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR Name, LPD3DXFRAME *ppNewFrame){    HRESULT hr = S_OK;    D3DXFRAME_DERIVED *pFrame;	    *ppNewFrame = NULL;	    pFrame = new D3DXFRAME_DERIVED;    if (pFrame == NULL)    {        hr = E_OUTOFMEMORY;        goto e_Exit;    }	    hr = AllocateName(Name, &pFrame->Name);    if (FAILED(hr))        goto e_Exit;	    // initialize other data members of the frame    D3DXMatrixIdentity(&pFrame->TransformationMatrix);    D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);	    pFrame->pMeshContainer = NULL;    pFrame->pFrameSibling = NULL;    pFrame->pFrameFirstChild = NULL;	    *ppNewFrame = pFrame;    pFrame = NULL;	e_Exit:    delete pFrame;    return hr;}//-----------------------------------------------------------------------------// Name: CAllocateHierarchy::CreateMeshContainer()// Desc: //-----------------------------------------------------------------------------#if ((D3D_SDK_VERSION&0xFF) ==31)	//ÕâÀïÊÇDirectx9.0bµÄHRESULT CAllocateHierarchy::CreateMeshContainer(	LPCTSTR Name, 	LPD3DXMESHDATA pMeshData,	LPD3DXMATERIAL pMaterials, 	LPD3DXEFFECTINSTANCE pEffectInstances, 	DWORD NumMaterials, 	DWORD *pAdjacency, 	LPD3DXSKININFO pSkinInfo, 	LPD3DXMESHCONTAINER *ppNewMeshContainer) #else						//Direct9.0c	LRESULT CAllocateHierarchy::CreateMeshContainer(		LPCTSTR Name, 		CONST D3DXMESHDATA *pMeshData,		CONST D3DXMATERIAL *pMaterials, 		CONST D3DXEFFECTINSTANCE *pEffectInstances, 		DWORD NumMaterials, 		CONST DWORD *pAdjacency, 		LPD3DXSKININFO pSkinInfo, 		LPD3DXMESHCONTAINER *ppNewMeshContainer) #endif{    HRESULT hr;    D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;    UINT NumFaces;    UINT iMaterial;    UINT iBone, cBones;    LPDIRECT3DDEVICE9 pd3dDevice = NULL;	    LPD3DXMESH pMesh = NULL;	    *ppNewMeshContainer = NULL;	    // this sample does not handle patch meshes, so fail when one is found    if (pMeshData->Type != D3DXMESHTYPE_MESH)    {        hr = E_FAIL;        goto e_Exit;    }	    // get the pMesh interface pointer out of the mesh data structure    pMesh = pMeshData->pMesh;	    // this sample does not FVF compatible meshes, so fail when one is found    if (pMesh->GetFVF() == 0)    {        hr = E_FAIL;        goto e_Exit;    }	    // allocate the overloaded structure to return as a D3DXMESHCONTAINER    pMeshContainer = new D3DXMESHCONTAINER_DERIVED;    if (pMeshContainer == NULL)    {        hr = E_OUTOFMEMORY;        goto e_Exit;    }    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));	    // make sure and copy the name.  All memory as input belongs to caller, interfaces can be addref'd though    hr = AllocateName(Name, &pMeshContainer->Name);    if (FAILED(hr))        goto e_Exit;        	    pMesh->GetDevice(&pd3dDevice);    NumFaces = pMesh->GetNumFaces();	    // if no normals are in the mesh, add them    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))    {        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;		        // clone the mesh to make room for the normals        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 			pMesh->GetFVF() | D3DFVF_NORMAL, 			pd3dDevice, &pMeshContainer->MeshData.pMesh );        if (FAILED(hr))            goto e_Exit;		        // get the new pMesh pointer back out of the mesh container to use        // NOTE: we do not release pMesh because we do not have a reference to it yet        pMesh = pMeshContainer->MeshData.pMesh;		        // now generate the normals for the pmesh        D3DXComputeNormals( pMesh, NULL );    }    else  // if no normals, just add a reference to the mesh for the mesh container    {        pMeshContainer->MeshData.pMesh = pMesh;        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;		        pMesh->AddRef();    }	    // allocate memory to contain the material information.  This sample uses    //   the D3D9 materials and texture names instead of the EffectInstance style materials    pMeshContainer->NumMaterials = max(1, NumMaterials);    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];    pMeshContainer->pAdjacency = new DWORD[NumFaces*3];    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL))    {        hr = E_OUTOFMEMORY;        goto e_Exit;    }	    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);    memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials);	    // if materials provided, copy them    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] = _T("");//                DXUtil_FindMediaFileCb( strTexturePath, sizeof(strTexturePath), pMeshContainer->pMaterials[iMaterial].pTextureFilename );                				if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, pMeshContainer->pMaterials[iMaterial].pTextureFilename, 					&pMeshContainer->ppTextures[iMaterial] ) ) )                    pMeshContainer->ppTextures[iMaterial] = NULL;								                // don't remember a pointer into the dynamic memory, just forget the name after loading                pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;            }        }    }    else // if no materials provided, use a default one    {        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 there is skinning information, save off the required data and then setup for HW skinning    if (pSkinInfo != NULL)    {        // first save off the SkinInfo and original mesh data        pMeshContainer->pSkinInfo = pSkinInfo;        pSkinInfo->AddRef();		        pMeshContainer->pOrigMesh = pMesh;        pMesh->AddRef();		        // Will need an array of offset matrices to move the vertices from the figure space to the bone's space        cBones = pSkinInfo->GetNumBones();        pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];        if (pMeshContainer->pBoneOffsetMatrices == NULL)        {            hr = E_OUTOFMEMORY;            goto e_Exit;        }		        // get each of the bone offset matrices so that we don't need to get them later        for (iBone = 0; iBone < cBones; iBone++)        {            pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));        }		        // GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version        hr = m_pSkinMesh->GenerateSkinnedMesh(pMeshContainer);        if (FAILED(hr))            goto e_Exit;    }	    *ppNewMeshContainer = pMeshContainer;    pMeshContainer = NULL;e_Exit:    SAFE_RELEASE(pd3dDevice);	    // call Destroy function to properly clean up the memory allocated     if (pMeshContainer != NULL)    {        DestroyMeshContainer(pMeshContainer);    }	    return hr;}//-----------------------------------------------------------------------------// Name: CAllocateHierarchy::DestroyFrame()// Desc: //-----------------------------------------------------------------------------HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree) {    SAFE_DELETE_ARRAY( pFrameToFree->Name );    SAFE_DELETE( pFrameToFree );    return S_OK; }//-----------------------------------------------------------------------------// Name: CAllocateHierarchy::DestroyMeshContainer()// Desc: //-----------------------------------------------------------------------------HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase){    UINT iMaterial;    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;	    SAFE_DELETE_ARRAY( pMeshContainer->Name );    SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );    SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );    SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );	    // release all the allocated textures    if (pMeshContainer->ppTextures != NULL)    {        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)        {            SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );        }    }	    SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );    SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );    SAFE_RELEASE( pMeshContainer->pSkinInfo );    SAFE_RELEASE( pMeshContainer->pOrigMesh );    SAFE_DELETE( pMeshContainer );    return S_OK;}//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CSkinMesh::CSkinMesh(LPDIRECT3DDEVICE9 pD3DDevice):m_vMax(0,0,0),m_vMin(0,0,0)  {	m_pd3dDevice=pD3DDevice;	m_fElapsedTime=0.0f;	m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );	m_bMoving=TRUE;    m_pAnimController = NULL;    m_pFrameRoot = NULL;    m_SkinningMethod = D3DINDEXED;    m_pBoneMatrices = NULL;    m_NumBoneMatricesMax = 0;}CSkinMesh::~CSkinMesh(){	CAllocateHierarchy Alloc(this);	D3DXFrameDestroy(m_pFrameRoot, &Alloc);	SAFE_RELEASE(m_pAnimController);	}HRESULT CSkinMesh::LoadFromXFile(char *strFileName){    HRESULT    hr;	CAllocateHierarchy Alloc(this);		//¼ÓÔØÖ¡µÄÊ÷ÐÍ½á¹¹    hr = D3DXLoadMeshHierarchyFromX(strFileName, D3DXMESH_MANAGED, m_pd3dDevice, &Alloc, NULL, &m_pFrameRoot, &m_pAnimController);    if (FAILED(hr))        return hr;		//ÉèÖÃ¾ØÕóÖ¸Õë    hr = SetupBoneMatrixPointers(m_pFrameRoot);    if (FAILED(hr))        return hr;	    hr = D3DXFrameCalculateBoundingSphere(m_pFrameRoot, &m_vObjectCenter, &m_fObjectRadius);    if (FAILED(hr))        return hr;	if(m_pFrameRoot)	CalculateBondingBox(m_pFrameRoot,&m_vMin,&m_vMax);  	LPD3DXANIMATIONSET pAnim;	m_pAnimController->GetAnimationSet(0,&pAnim);	 	return S_OK;}//-----------------------------------------------------------------------------// Name: GenerateSkinnedMesh()// Desc: Called either by CreateMeshContainer when loading a skin mesh, or when //       changing methods.  This function uses the pSkinInfo of the mesh //       container to generate the desired drawable mesh and bone combination //       table.//-----------------------------------------------------------------------------HRESULT CSkinMesh::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED *pMeshContainer){	//m_SkinMesh = pMeshContainer->pOrigMesh;    m_SkinMesh = pMeshContainer->MeshData.pMesh;	HRESULT hr = S_OK;    if (pMeshContainer->pSkinInfo == NULL)        return hr;    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );    // if non-indexed skinning mode selected, use ConvertToBlendedMesh to generate drawable mesh    if (m_SkinningMethod == D3DNONINDEXED)    {        hr = pMeshContainer->pSkinInfo->ConvertToBlendedMesh                                   (                                       pMeshContainer->pOrigMesh,                                       D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,                                        pMeshContainer->pAdjacency,                                        NULL, NULL, NULL,                                        &pMeshContainer->NumInfl,                                       &pMeshContainer->NumAttributeGroups,                                        &pMeshContainer->pBoneCombinationBuf,                                        &pMeshContainer->MeshData.pMesh                                   );        if (FAILED(hr))            goto e_Exit;        /* If the device can only do 2 matrix blends, ConvertToBlendedMesh cannot approximate all meshes to it           Thus we split the mesh in two parts: The part that uses at most 2 matrices and the rest. The first is           drawn using the device's HW vertex processing and the rest is drawn using SW vertex processing. */        LPD3DXBONECOMBINATION rgBoneCombinations  = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());        // look for any set of bone combinations that do not fit the caps        for (pMeshContainer->iAttributeSW = 0; pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups; pMeshContainer->iAttributeSW++)        {            DWORD cInfl   = 0;            for (DWORD iInfl = 0; iInfl < pMeshContainer->NumInfl; iInfl++)            {                if (rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] != UINT_MAX)                {                    ++cInfl;                }            }            if (cInfl > m_d3dCaps.MaxVertexBlendMatrices)            {                break;            }        }        // if there is both HW and SW, add the Software Processing flag        if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)        {            LPD3DXMESH pMeshTmp;            hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),                                                 pMeshContainer->MeshData.pMesh->GetFVF(),                                                m_pd3dDevice, &pMeshTmp);            if (FAILED(hr))            {                goto e_Exit;            }            pMeshContainer->MeshData.pMesh->Release();            pMeshContainer->MeshData.pMesh = pMeshTmp;            pMeshTmp = NULL;        }    }    // if indexed skinning mode selected, use ConvertToIndexedsBlendedMesh to generate drawable mesh    else if (m_SkinningMethod == D3DINDEXED)    {        DWORD NumMaxFaceInfl;        DWORD Flags = D3DXMESHOPT_VERTEXCACHE;        LPDIRECT3DINDEXBUFFER9 pIB;        hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);        if (FAILED(hr))            goto e_Exit;        hr = pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB, pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl);        pIB->Release();        if (FAILED(hr))            goto e_Exit;        // 12 entry palette guarantees that any triangle (4 independent influences per vertex of a tri)        // can be handled        NumMaxFaceInfl = min(NumMaxFaceInfl, 12);        if (m_d3dCaps.MaxVertexBlendMatrixIndex + 1 < NumMaxFaceInfl)        {            // HW does not support indexed vertex blending. Use SW instead            pMeshContainer->NumPaletteEntries = min(256, pMeshContainer->pSkinInfo->GetNumBones());            pMeshContainer->UseSoftwareVP = true;            Flags |= D3DXMESH_SYSTEMMEM;        }        else        {            // using hardware - determine palette size from caps and number of bones            // If normals are present in the vertex data that needs to be blended for lighting, then             // the number of matrices is half the number specified by MaxVertexBlendMatrixIndex.            pMeshContainer->NumPaletteEntries = min( ( m_d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,                                                      pMeshContainer->pSkinInfo->GetNumBones() );            pMeshContainer->UseSoftwareVP = false;            Flags |= D3DXMESH_MANAGED;        }        hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh                                                (                                                pMeshContainer->pOrigMesh,                                                Flags,                                                 pMeshContainer->NumPaletteEntries,                                                 pMeshContainer->pAdjacency,                                                 NULL, NULL, NULL,                                                 &pMeshContainer->NumInfl,                                                &pMeshContainer->NumAttributeGroups,                                                 &pMeshContainer->pBoneCombinationBuf,                                                 &pMeshContainer->MeshData.pMesh);        if (FAILED(hr))            goto e_Exit;    }     // if software skinning selected, use GenerateSkinnedMesh to create a mesh that can be used with UpdateSkinnedMesh    else if (m_SkinningMethod == SOFTWARE)    {        hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(),                                              m_pd3dDevice, &pMeshContainer->MeshData.pMesh);        if (FAILED(hr))            goto e_Exit;        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &pMeshContainer->NumAttributeGroups);        if (FAILED(hr))            goto e_Exit;        delete[] pMeshContainer->pAttributeTable;        pMeshContainer->pAttributeTable  = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];        if (pMeshContainer->pAttributeTable == NULL)        {            hr = E_OUTOFMEMORY;            goto e_Exit;        }        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, NULL);        if (FAILED(hr))            goto e_Exit;        // allocate a buffer for bone matrices, but only if another mesh has not allocated one of the same size or larger        if (m_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones())        {            m_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();            // Allocate space for blend matrices            delete []m_pBoneMatrices;             m_pBoneMatrices  = new D3DXMATRIXA16[m_NumBoneMatricesMax];            if (m_pBoneMatrices == NULL)            {                hr = E_OUTOFMEMORY;                goto e_Exit;            }        }    }    else  // invalid m_SkinningMethod value    {                // return failure due to invalid skinning method value        hr = E_INVALIDARG;        goto e_Exit;    }e_Exit:    return hr;}HRESULT CSkinMesh::SetupBoneMatrixPointers(LPD3DXFRAME pFrame){    HRESULT hr;    if (pFrame->pMeshContainer != NULL)    {	//×óÐò±éÀú        hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);        if (FAILED(hr))            return hr;    }    if (pFrame->pFrameSibling != NULL)    {        hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);        if (FAILED(hr))            return hr;    }    if (pFrame->pFrameFirstChild != NULL)    {        hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);        if (FAILED(hr))            return hr;    }    return S_OK;}HRESULT CSkinMesh::SetupBoneMatrixPointersOnMesh(LPD3DXMESHCONTAINER pMeshContainerBase){    UINT iBone, cBones;    D3DXFRAME_DERIVED *pFrame;    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;	//ÃÉÆ¤¶¯»­£¬ÔòÉèÖÃ¹Ç÷ÀµÄ±ä»»¾ØÕó    if (pMeshContainer->pSkinInfo != NULL)    {        cBones = pMeshContainer->pSkinInfo->GetNumBones();        pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];	//´´½¨¹Ç÷À        if (pMeshContainer->ppBoneMatrixPtrs == NULL)            return E_OUTOFMEMORY;        for (iBone = 0; iBone < cBones; iBone++)        {            pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(m_pFrameRoot, 				pMeshContainer->pSkinInfo->GetBoneName(iBone));            if (pFrame == NULL)                return E_FAIL;			//³õÊ¼»¯¾ØÕó            pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;        }    }    return S_OK;}VOID CSkinMesh::Render(float fElapsedAppTime,D3DXVECTOR3 vPos,D3DXVECTOR3 rotation,float scale){		// Get the app's time, in seconds. Skip rendering if no time elapsed//    FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );	    if( 0.00f == fElapsedAppTime )    return;	m_fElapsedTime = fElapsedAppTime;		// Setup world matrix    D3DXMATRIXA16 matWorld,matWorld2;	// set the rotation matrix	D3DXMatrixRotationYawPitchRoll(&matWorld2,rotation.x,rotation.y,rotation.z);	D3DXMatrixScaling(&matWorld,scale,scale,scale);	D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2);    D3DXMatrixTranslation( &matWorld2, vPos.x, vPos.y,vPos.z );	D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2);//    m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );	if(m_pAnimController)	{		if (m_bMoving)#if ((D3D_SDK_VERSION & 0xFF)==31)			m_pAnimController->SetTime(m_pAnimController->GetTime()+m_fElapsedTime );		else			m_pAnimController->SetTime(0);			#else 			m_pAnimController->AdvanceTime(m_fElapsedTime,NULL); 		else			m_pAnimController->ResetTime();#endif	}		UpdateFrameMatrices(m_pFrameRoot, &matWorld);		DrawFrame(m_pFrameRoot);}VOID CSkinMesh::DrawFrame(LPD3DXFRAME pFrame){    LPD3DXMESHCONTAINER pMeshContainer;	    pMeshContainer = pFrame->pMeshContainer;    while (pMeshContainer != NULL)    {        DrawMeshContainer(pMeshContainer, pFrame);        pMeshContainer = pMeshContainer->pNextMeshContainer;    }	    if (pFrame->pFrameSibling != NULL)    {        DrawFrame(pFrame->pFrameSibling);    }	    if (pFrame->pFrameFirstChild != NULL)    {        DrawFrame(pFrame->pFrameFirstChild);    }}//-----------------------------------------------------------------------------// Name: DrawMeshContainer()// Desc: Called to render a mesh in the hierarchy//-----------------------------------------------------------------------------VOID CSkinMesh::DrawMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase){    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;    UINT iMaterial;    UINT NumBlend;    UINT iAttrib;    DWORD AttribIdPrev;    LPD3DXBONECOMBINATION pBoneComb;    UINT iMatrixIndex;    UINT iPaletteEntry;    D3DXMATRIXA16 matTemp;    // first check for skinning    if (pMeshContainer->pSkinInfo != NULL)    {        if (m_SkinningMethod == D3DNONINDEXED)        {            AttribIdPrev = UNUSED32;             pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());            // Draw using default vtx processing of the device (typically HW)            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)            {                NumBlend = 0;                for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)                {                    if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)                    {                        NumBlend = i;                    }                }                if (m_d3dCaps.MaxVertexBlendMatrices >= NumBlend + 1)                {                    // first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends                    for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)                    {                        iMatrixIndex = pBoneComb[iAttrib].BoneId[i];                        if (iMatrixIndex != UINT_MAX)                        {                            D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );                            m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );                        }                    }                    m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend);                    // lookup the material used for this subset of faces                    if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))                    {                        m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );                        m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );                        AttribIdPrev = pBoneComb[iAttrib].AttribId;                    }                    // draw the subset now that the correct material and matrices are loaded                    pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib);                }            }            // If necessary, draw parts that HW could not handle using SW            if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)            {                AttribIdPrev = UNUSED32;                 m_pd3dDevice->SetSoftwareVertexProcessing(TRUE);                for (iAttrib = pMeshContainer->iAttributeSW; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)                {                    NumBlend = 0;                    for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)                    {                        if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)                        {                            NumBlend = i;                        }                    }                    if (m_d3dCaps.MaxVertexBlendMatrices < NumBlend + 1)                    {                        // first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends                        for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)                        {                            iMatrixIndex = pBoneComb[iAttrib].BoneId[i];                            if (iMatrixIndex != UINT_MAX)                            {                                D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );                                m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );                            }                        }                        m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend);                        // lookup the material used for this subset of faces                        if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))                        {                            m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );                            m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );                            AttribIdPrev = pBoneComb[iAttrib].AttribId;                        }                        // draw the subset now that the correct material and matrices are loaded                        pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib);                    }                }                m_pd3dDevice->SetSoftwareVertexProcessing(FALSE);            }            m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);        }        else if (m_SkinningMethod == D3DINDEXED)        {            // if hw doesn't support indexed vertex processing, switch to software vertex processing            if (pMeshContainer->UseSoftwareVP)            {                m_pd3dDevice->SetSoftwareVertexProcessing(TRUE);            }            // set the number of vertex blend indices to be blended            if (pMeshContainer->NumInfl == 1)                m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);            else                m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, pMeshContainer->NumInfl - 1);            if (pMeshContainer->NumInfl)                m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);            // for each attribute group in the mesh, calculate the set of matrices in the palette and then draw the mesh subset            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)            {                 // first calculate all the world matrices                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries;						++iPaletteEntry)                {                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];                    if (iMatrixIndex != UINT_MAX)                    {                        D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );                        m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp );                    }                }                               // setup the material of the mesh subset - REMEMBER to use the original pre-skinning attribute id to get the correct material id                m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );                m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );                // finally draw the subset with the current world matrix palette and material state                pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib );            }            // reset blending state            m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);            m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);            // remember to reset back to hw vertex processing if software was required            if (pMeshContainer->UseSoftwareVP)            {                m_pd3dDevice->SetSoftwareVertexProcessing(FALSE);            }        }        else if (m_SkinningMethod == SOFTWARE)        {            D3DXMATRIX  Identity;            DWORD       cBones  = pMeshContainer->pSkinInfo->GetNumBones();            DWORD       iBone;            PBYTE       pbVerticesSrc;            PBYTE       pbVerticesDest;            // set up bone transforms            for (iBone = 0; iBone < cBones; ++iBone)            {                D3DXMatrixMultiply                (                    &m_pBoneMatrices[iBone],                 // output                    &pMeshContainer->pBoneOffsetMatrices[iBone],                     pMeshContainer->ppBoneMatrixPtrs[iBone]                );            }            // set world transform            D3DXMatrixIdentity(&Identity);            m_pd3dDevice->SetTransform(D3DTS_WORLD, &Identity);            pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc);            pMeshContainer->MeshData.pMesh->LockVertexBuffer(0, (LPVOID*)&pbVerticesDest);            // generate skinned mesh            pMeshContainer->pSkinInfo->UpdateSkinnedMesh(m_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest);            pMeshContainer->pOrigMesh->UnlockVertexBuffer();            pMeshContainer->MeshData.pMesh->UnlockVertexBuffer();            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)            {                m_pd3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D));                m_pd3dDevice->SetTexture(0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]);                pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId);            }        }        else // bug out as unsupported mode        {            return;        }    }    else  // standard mesh, just draw it after setting material properties    {        m_pd3dDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix);        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)        {            m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );            m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );            pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial);        }    }}VOID CSkinMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix){    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;    if (pParentMatrix != NULL)        D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, 			&pFrame->TransformationMatrix, pParentMatrix);    else        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;    if (pFrame->pFrameSibling != NULL)    {        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);    }    if (pFrame->pFrameFirstChild != NULL)    {        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);    }}	VOID CSkinMesh::SetAnim(BOOL bAnim)	{		m_bMoving=bAnim;		if(!m_bMoving && m_pAnimController)		{	#if ((D3D_SDK_VERSION&0xFF)== 31)				m_pAnimController->SetTime(0);	#else			m_pAnimController->ResetTime();#endif		}	}	BOOL CSkinMesh::SetAnimationName(char *strAnimName)	{		if(!m_bMoving || !m_pAnimController  ) return FALSE;		DWORD nAnimSet;		char strTempName[256];		nAnimSet=m_pAnimController->GetNumAnimationSets();		LPD3DXANIMATIONSET pAnimSet;				for(DWORD i=0;i<nAnimSet;i++)		{				m_pAnimController->GetAnimationSet(i,&pAnimSet);			strcpy(strTempName,	pAnimSet->GetName());			if(strcmp(strAnimName,strTempName)==0) 			{				m_pAnimController->SetTrackAnimationSet(0,pAnimSet);			 				return TRUE;						}		}		return FALSE;		};//-----------------------------------------//Name:Intersect//Desc:Ê¹ÓÃË÷ÒýºÍ¶¥µã»º³åÇø£¬ÇóMeshºÍÉäÏß½»µã//2006/6/27 JohnsonFeng//Use: IntersectIndexBuffer//-----------------------------------------BOOL CSkinMesh::InterSect( D3DVECTOR *pRayOrig,		 D3DVECTOR *pRayDir,D3DVECTOR* pVRet){	return S_OK;}////   Note: this returns the current Mesh.//LPD3DXMESH CSkinMesh::getMesh(){ 	return m_SkinMesh; }

thanks for help guys :)

##### Share on other sites
First:
LPD3DXANIMATIONCONTROLLER GetAnimController() {return m_pAnimController;};

By the way, you are using ID3DXAnimationController. LPD3DXANIMATIONCONTROLLER is just a pointer to that interface.

Again:
Quote:
 Does it load and play the animation correctly?

I ask that because there's no sense trying to modify code that doesn't work!

If it does play correctly, then your routine UpdateFrameMatrices(...) will be where you'll do some calcuations for the bone (matrix) that you want to change.

Because you aren't at all familiar with animation, this is going to take some effort on your part.

The first thing you need to do is to identity which bone you want to make changes to. For instance, do you want to change the head rotation? Or an arm?

While I look over your code, you can ensure you know the correct name for the frame by adding some information code.

Make a temporary change as follows:
HRESULT CSkinMesh::SetupBoneMatrixPointersOnMesh(LPD3DXMESHCONTAINER pMeshContainerBase){    UINT iBone, cBones;    D3DXFRAME_DERIVED *pFrame;    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;	//ÃÉÆ¤¶¯»­£¬ÔòÉèÖÃ¹Ç÷ÀµÄ±ä»»¾ØÕó    if (pMeshContainer->pSkinInfo != NULL)    {        cBones = pMeshContainer->pSkinInfo->GetNumBones();        pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];	//´´½¨¹Ç÷À        if (pMeshContainer->ppBoneMatrixPtrs == NULL)            return E_OUTOFMEMORY;        for (iBone = 0; iBone < cBones; iBone++)        {            pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(m_pFrameRoot, 				pMeshContainer->pSkinInfo->GetBoneName(iBone));            if (pFrame == NULL)                return E_FAIL;			//³õÊ¼»¯¾ØÕó            //===================== TEMPORARY =============            if( pFrame->Name != NULL )            {                OutputDebugString(pFrame->Name);                OutputDebugString("\n");            }            //==============================================            pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;        }    }    return S_OK;}

Run your program. The output window in MS Studio should list the names of all the bones. Make sure you take note of the name of the frame you want to change.

##### Share on other sites

the output window in MS Studio show:

ValveBiped_Bip01_L_ClavicleValveBiped_Bip01_L_Finger21ValveBiped_Bip01_L_Finger2ValveBiped_Bip01_L_Finger22ValveBiped_Bip01_L_Finger1ValveBiped_Bip01_L_HandValveBiped_Bip01_L_Finger11ValveBiped_Bip01_R_UlnaValveBiped_Bip01_R_ForearmValveBiped_Bip01_R_WristValveBiped_Bip01_R_UpperArmValveBiped_Bip01_L_UpperArmValveBiped_Bip01_L_FootValveBiped_Bip01_L_Toe0ValveBiped_Bip01_L_WristValveBiped_Bip01_L_UlnaValveBiped_Bip01_L_ForearmValveBiped_Bip01_L_Finger0ValveBiped_Bip01_L_CalfValveBiped_Bip01_L_Finger12ValveBiped_Bip01_L_Finger01ValveBiped_Bip01_L_Finger02ValveBiped_Bip01_L_ThighValveBiped_Bip01_R_CalfValveBiped_Bip01_R_FootValveBiped_Bip01_R_Toe0ValveBiped_Bip01_R_Finger1ValveBiped_Bip01_R_Finger2ValveBiped_Bip01_R_Finger11ValveBiped_Bip01_R_Finger02ValveBiped_Bip01_R_Finger01ValveBiped_Bip01_R_Finger0ValveBiped_Bip01_R_HandValveBiped_Bip01_R_Finger21ValveBiped_Bip01_R_Finger22ValveBiped_Bip01_R_ThighValveBiped_Bip01_PelvisValveBiped_Bip01_Head1ValveBiped_Bip01_Spine2ValveBiped_Bip01_Spine1ValveBiped_Bip01_Spine4ValveBiped_Bip01_R_ClavicleValveBiped_Bip01_SpineValveBiped_Bip01_R_Finger12

Quote:
 Does it load and play the animation correctly?

Yes

Quote:
 do you want to change the head rotation? Or an arm?

The two arms

##### Share on other sites
Good for you. Glad that part of it worked.

Now you'll have to experiment a bit. See what happens when you try this:
VOID CSkinMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix){    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;    if (pParentMatrix != NULL)    {        if( strcmp(pFrame->Name,"<put the name of an arm here>")==0 )        {            D3DXMATRIX tempRot;            D3DXMatrixRotationY(&tempRot, D3DX_PI/4.0f); // also try D3DXMatrixRotationX and D3DXMatrixRotationZ            tempRot = pFrame->TransformationMatrix * tempRot;            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &tempRot, pParentMatrix);        }        else        {            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, 			&pFrame->TransformationMatrix, pParentMatrix);        }    }    else        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;    if (pFrame->pFrameSibling != NULL)    {        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);    }    if (pFrame->pFrameFirstChild != NULL)    {        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);    }}

The result won't be what you're looking for, but you should see the arm rotated out it's normal position.

Does that work?

EDIT: If you get some sort of reasonable change in the arm angle, you can start playing around with rotations to get what you want.

##### Share on other sites
Error:

Unhandled exception at 0x51f0d440 (msvcr100d.dll) in Resistance.exe: 0xC0000005: Access violation reading location 0x00000000.

in line:
if( strcmp(pFrame->Name,"<put the name of an arm here>")==0 )

with the strcmp

##### Share on other sites
Quote:
 Original post by VitaliBRif( strcmp(pFrame->Name,"")==0 )

Think very, very carefully about what is written inbetween those quotes.

edit: forgot to mention this probably won't help with your immediate problem. Your immediate problem is you have a null pointer and you're dereferencing it. could be either pFrame or pFrame->Name. I couldn't tell you why either of those would be null.

##### Share on other sites
Change that line to:
if( pFrame->Name != NULL && strcmp(pFrame->Name,"<put the name of an arm here>")==0 )

Also, as nobodynews mentioned, look at that line. Did you put the name of an arm inside the quotation marks?

##### Share on other sites
VOID CSkinMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix){    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;    if (pParentMatrix != NULL)    {		if( pFrame->Name != NULL && strcmp(pFrame->Name,"ValveBiped_Bip01_Head1")==0 )        {            D3DXMATRIX tempRot;            D3DXMatrixRotationY(&tempRot, D3DX_PI/4.0f); // also try D3DXMatrixRotationX and D3DXMatrixRotationZ            tempRot = pFrame->TransformationMatrix * tempRot;            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &tempRot, pParentMatrix);        }        else        {            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, 			&pFrame->TransformationMatrix, pParentMatrix);        }    }    else        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;    if (pFrame->pFrameSibling != NULL)    {        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);    }    if (pFrame->pFrameFirstChild != NULL)    {        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);    }}

was ugly, but it worked :D

I now access the bone in this way and rotates the arm, according to the mouse position, right?

##### Share on other sites
speaking of bipped, how did you export it and manage to render it , i always have problems with it not showing up in the render device..

[Edited by - Anddos on August 29, 2010 5:09:03 AM]

##### Share on other sites
Quote:
 I now access the bone in this way and rotates the arm, according to the mouse position, right?

[smile] That is pretty ugly, but you can see the principle involved.

Also, I made an error that's obvious because you posted an image. Good for you. I use a different matrix structure and didn't think about the differences with your code.

So, change:
// FROMtempRot = pFrame->TransformationMatrix * tempRot; // TOtempRot *= pFrame->TransformationMatrix;

There's a translation in the transformation matrix to move the head (or arm) to the correct position. The rotation of the head (or arm) needs to take place before the translation. Make that change and see if the head stays on the neck!

There's still a little work to do to determine the angle you'll need. AND you'll have to experiment with the rotation axis of tmpRot.

VOID CSkinMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix){    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;    if (pParentMatrix != NULL)    {		if( pFrame->Name != NULL && strcmp(pFrame->Name,"ValveBiped_Bip01_Head1")==0 )        {            D3DXMATRIX tempMat = pFrame->TransformationMatrix * pParentMatrix; // this matrix is the WORLD orientation of the bone            D3DXVECTOR3 boneLocation( tempMat._41, tempMat._42, tempMat._43 ); // this is the bone's location in the world            // NOTE - You must have the mouse position in the WORLD at this point - mouseLocation            // You'll need a global vector for that mouse position            D3DXVECTOR3 dirToMouse = mouseLocation - boneLocation; // points from the arm to the mouse location            float angle = atan2( dirToMouse.y, dirToMouse.x ); // assumes your "up" direction is the Y axis.            D3DXMATRIX tmpRot;            D3DXMatrixRotationY(&tmpRot,angle);            tmpRot *= pFrame->TransformationMatrix;            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &tempRot, pParentMatrix);        }        else        {            D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, 			&pFrame->TransformationMatrix, pParentMatrix);        }    }    else        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;    if (pFrame->pFrameSibling != NULL)    {        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);    }    if (pFrame->pFrameFirstChild != NULL)    {        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);    }}

Play around with that and see what you can do. Again, YOU have to come up with a D3DXVECTOR3 mouseLocation based on the mouse position on the screen.

##### Share on other sites
Error in line:
D3DXMATRIX tempMat = pFrame->TransformationMatrix * pParentMatrix; // this matrix is the WORLD orientation of the bone

1>\skinmesh.cpp(918): error C2678: binary '*' : no operator found which takes a left-hand operand of type 'D3DXMATRIX' (or there is no acceptable conversion)1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(116): could be 'D3DXVECTOR2 operator *(FLOAT,const D3DXVECTOR2 &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(191): or       'D3DXVECTOR3 operator *(FLOAT,const D3DXVECTOR3 &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(266): or       'D3DXVECTOR4 operator *(FLOAT,const D3DXVECTOR4 &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(351): or       'D3DXMATRIX operator *(FLOAT,const D3DXMATRIX &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(456): or       'D3DXQUATERNION operator *(FLOAT,const D3DXQUATERNION &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(496): or       'D3DXPLANE operator *(FLOAT,const D3DXPLANE &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(551): or       'D3DXCOLOR operator *(FLOAT,const D3DXCOLOR &)'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(345): or       'D3DXMATRIX D3DXMATRIX::operator *(const D3DXMATRIX &) const'1>          c:\program files\microsoft directx sdk (june 2010)\include\d3dx9math.h(348): or       'D3DXMATRIX D3DXMATRIX::operator *(FLOAT) const'

Where i find some models. x with basic animations (running and jumping)?
I'm a bad modeler and animator

##### Share on other sites
Quote:
 D3DXMATRIX tempMat = pFrame->TransformationMatrix * pParentMatrix;

Sorry about that. pParentMatrix is a pointer to a matrix, not a matrix.

Try:
D3DXMATRIX tempMat;
D3DXMatrixMultiply(&tempMat, &pframe->TransformationMatrix, pParentMatrx);

##### Share on other sites

This topic is 2659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628682
• Total Posts
2984206

• 13
• 13
• 9
• 10
• 10