Sign in to follow this  

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.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a model of a soldier in format .x

My game is in 3D platform like booster trooper:
http://www.youtube.com/watch?v=YiCufmL8IFM

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Can bones be moved in code...?

Yep. See my previous posts.

Are you animating your model?

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 this post


Link to post
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 this post


Link to post
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 possible
enum 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 object
protected:
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 this post


Link to post
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 this post


Link to post
Share on other sites
Thank you for your help

the output window in MS Studio show:

ValveBiped_Bip01_L_Clavicle
ValveBiped_Bip01_L_Finger21
ValveBiped_Bip01_L_Finger2
ValveBiped_Bip01_L_Finger22
ValveBiped_Bip01_L_Finger1
ValveBiped_Bip01_L_Hand
ValveBiped_Bip01_L_Finger11
ValveBiped_Bip01_R_Ulna
ValveBiped_Bip01_R_Forearm
ValveBiped_Bip01_R_Wrist
ValveBiped_Bip01_R_UpperArm
ValveBiped_Bip01_L_UpperArm
ValveBiped_Bip01_L_Foot
ValveBiped_Bip01_L_Toe0
ValveBiped_Bip01_L_Wrist
ValveBiped_Bip01_L_Ulna
ValveBiped_Bip01_L_Forearm
ValveBiped_Bip01_L_Finger0
ValveBiped_Bip01_L_Calf
ValveBiped_Bip01_L_Finger12
ValveBiped_Bip01_L_Finger01
ValveBiped_Bip01_L_Finger02
ValveBiped_Bip01_L_Thigh
ValveBiped_Bip01_R_Calf
ValveBiped_Bip01_R_Foot
ValveBiped_Bip01_R_Toe0
ValveBiped_Bip01_R_Finger1
ValveBiped_Bip01_R_Finger2
ValveBiped_Bip01_R_Finger11
ValveBiped_Bip01_R_Finger02
ValveBiped_Bip01_R_Finger01
ValveBiped_Bip01_R_Finger0
ValveBiped_Bip01_R_Hand
ValveBiped_Bip01_R_Finger21
ValveBiped_Bip01_R_Finger22
ValveBiped_Bip01_R_Thigh
ValveBiped_Bip01_Pelvis
ValveBiped_Bip01_Head1
ValveBiped_Bip01_Spine2
ValveBiped_Bip01_Spine1
ValveBiped_Bip01_Spine4
ValveBiped_Bip01_R_Clavicle
ValveBiped_Bip01_Spine
ValveBiped_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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by VitaliBR
if( strcmp(pFrame->Name,"<put the name of an arm here>")==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 this post


Link to post
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 this post


Link to post
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);
}
}





image


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 this post


Link to post
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 this post


Link to post
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:

// FROM
tempRot = pFrame->TransformationMatrix * tempRot;
// TO
tempRot *= 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this