Direct-X学习笔记--骨骼动画
学了几个月DX了,终于到了骨骼动画这一步了,好激动!之前导入过一些静态的模型,还是挺帅的。不过不能动,实在是太遗憾了。今天学习了骨骼动画,终于让偶的模型动起来啦!!!
一.简介
二.X文件
Animation 描述一个动画,包含一个或几个AnimationKey
AnimationKey 动画关键帧,定义具体的动作数据,包括一些列旋转、移动、放缩、矩阵变换。
ColorRGB 定义RGB对象,包括三个Float的值,分别是R、G、B。
ColorRGBA 定义RGBA对象。包括四个Float的值,分别是R、G、B、alpha。
Coords2d 定义纹理坐标向量,包括两个Float值,分别是u、v。
FloatKeys 定义浮点数组,用来定义动画键数值,包括两个部分:浮点值个数,浮点值列表。
Material 定义材质信息,可以被应用到一个完整的Mesh对象,也可以应用到其中的一个面。包含:
1.FaceColor环境光
2.Power镜面反射的强度
3.specularcolor镜面反射等等。
Matrix4X4 定义4X4矩阵,16个浮点数值。
Mesh 定义个Mesh对象,共有9个部分组成:
1、包含的顶点数
2、顶点列表,一个顶点包含三个浮点值
3、面数
4、面的顶点索引列表,每个面包含三个顶点
5、MeshFaceWraps 结构,暂时无用
6、MeshTextureCoords纹理坐标,可选
7、MeshNormals 法向,可选
8、MeshVertexColors 顶点颜色,默认为白色
9、MeshMaterialList 材质,不提供的话默认为白色。
MeshFace 面索引,包含两部分:面数,定点索引构成的面数组。
MeshTextureCoords 定义纹理坐标,包括:纹理坐标的个数,纹理坐标(每个纹理坐标有两个浮点值)。
MeshMaterialList 定义材质的应用,包括:多少个材质被使用,材质影响面的个数,面索引。
MeshNormals 定义Mesh的法向量,包括4部分:
1.nNormals法向量的个数=顶点数
2.Normals顶点法向量列表
3.nFaceNormals面的个数
4.FaceNormals面对应的法向量。
MeshVertexColors 指定顶点的颜色代替原来的材质,包含:顶点数目,颜色索引
TextureFilename 纹理的名称,字符串类型。
VertexDuplicationIndices 保留副本,用于精简Mesh的操作,包含:顶点数,原始顶点数,实际顶点数。
XSkinMeshHeader 描述被导出的SkinMesh相关信息,影响一个顶点的最多变换数目,影响每个面三个顶点的最大变换数目,影响一个顶点的骨骼数。
TimedFloatKeys 时间值,用于Animaterkey中定义时间间隔。
Vector 三维向量,三个浮点值。
SkinWeights 定义骨骼影响权重。包括以下几个部分:骨骼的名字,有多少个权重值,顶点的索引列表等等
三.封装一个容易使用的骨骼动画类
/*!* \file AllocateHierarchy.h** \author puppet_master* \date 九月 2015** \微软SDK自带的关于骨骼动画的类,用于骨骼动画的创建以及绘制更新* \注:程序不直接使用该类,而是将此类二次封装后再使用。*/#ifndef __ALLOCATEHIERARCHY_H_
#define __ALLOCATEHIERARCHY_H_//--------------------------------------------------------------------------------------
// Name: struct D3DXFRAME_DERIVED
// Desc:
//--------------------------------------------------------------------------------------
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; //纹理数组 //网格信息 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
};//--------------------------------------------------------------------------------------
// Name: class CAllocateHierarchy
// Desc: Custom version of ID3DXAllocateHierarchy with custom methods to create
// frames and meshcontainers.
//用来从.X文件中加载网格以及动画数据
//--------------------------------------------------------------------------------------
class CAllocateHierarchy : public ID3DXAllocateHierarchy
{
private:HRESULT AllocateName( LPCSTR Name, LPSTR* pNewName );HRESULT GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer );
public:STDMETHOD( CreateFrame )( THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame );STDMETHOD( CreateMeshContainer )( THIS_LPCSTR Name,CONST D3DXMESHDATA *pMeshData,CONST D3DXMATERIAL *pMaterials,CONST D3DXEFFECTINSTANCE *pEffectInstances,DWORD NumMaterials,CONST DWORD *pAdjacency,LPD3DXSKININFO pSkinInfo,LPD3DXMESHCONTAINER *ppNewMeshContainer );STDMETHOD( DestroyFrame )( THIS_ LPD3DXFRAME pFrameToFree );STDMETHOD( DestroyMeshContainer )( THIS_ LPD3DXMESHCONTAINER pMeshContainerBase );CAllocateHierarchy(){}
};#endif
#include "stdafx.h"
#include "AllocateHierarchy.h"HRESULT CAllocateHierarchy::AllocateName( LPCSTR Name, LPSTR* pNewName )
{UINT cbLength;if( Name != NULL ){cbLength = ( UINT )strlen( Name ) + 1;*pNewName = new CHAR[cbLength];if( *pNewName == NULL )return E_OUTOFMEMORY;memcpy( *pNewName, Name, cbLength * sizeof( CHAR ) );}else{*pNewName = NULL;}return S_OK;
}//--------------------------------------------------------------------------------------
// 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 CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer )
{D3DCAPS9 d3dCaps;pd3dDevice->GetDeviceCaps( &d3dCaps );if( pMeshContainer->pSkinInfo == NULL )return S_OK;SAFE_RELEASE( pMeshContainer->MeshData.pMesh );SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );if (FAILED(pMeshContainer->pSkinInfo->ConvertToBlendedMesh(pMeshContainer->pOrigMesh, D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE,pMeshContainer->pAdjacency,NULL, NULL, NULL,&pMeshContainer->NumInfl,&pMeshContainer->NumAttributeGroups,&pMeshContainer->pBoneCombinationBuf,&pMeshContainer->MeshData.pMesh)))return E_FAIL;return S_OK;
}//--------------------------------------------------------------------------------------
// Name: CAllocateHierarchy::CreateFrame()
// Desc: 创建框架,分配内存&初始化
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR 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 frameD3DXMatrixIdentity( &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: 创建网格容器对象,保存网格模型数据
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateMeshContainer(LPCSTR Name,CONST D3DXMESHDATA *pMeshData,CONST D3DXMATERIAL *pMaterials,CONST D3DXEFFECTINSTANCE *pEffectInstances,DWORD NumMaterials,CONST DWORD *pAdjacency,LPD3DXSKININFO pSkinInfo,LPD3DXMESHCONTAINER *ppNewMeshContainer )
{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 foundif( pMeshData->Type != D3DXMESHTYPE_MESH ){hr = E_FAIL;goto e_Exit;}// get the pMesh interface pointer out of the mesh data structurepMesh = pMeshData->pMesh;// this sample does not FVF compatible meshes, so fail when one is foundif( pMesh->GetFVF() == 0 ){hr = E_FAIL;goto e_Exit;}// allocate the overloaded structure to return as a D3DXMESHCONTAINERpMeshContainer = 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 thoughhr = AllocateName( Name, &pMeshContainer->Name );if( FAILED( hr ) )goto e_Exit;pMesh->GetDevice( &pd3dDevice );NumFaces = pMesh->GetNumFaces();// if no normals are in the mesh, add themif( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ){pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;// clone the mesh to make room for the normalshr = 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 yetpMesh = pMeshContainer->MeshData.pMesh;// now generate the normals for the pmeshD3DXComputeNormals( 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 materialspMeshContainer->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 themif( NumMaterials > 0 ){memcpy( pMeshContainer->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials );for( iMaterial = 0; iMaterial < NumMaterials; iMaterial++ ){if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL ){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 loadingpMeshContainer->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 skinningif( pSkinInfo != NULL ){// first save off the SkinInfo and original mesh datapMeshContainer->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 spacecBones = 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 laterfor( 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 versionhr = GenerateSkinnedMesh( pd3dDevice, 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 texturesif( 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;
}
/*!* \file D3DXAnimation.h** \author puppet_master* \date 九月 2015** \封装了微软自带的骨骼动画相关功能,提供一个简单的接口供使用*/#ifndef __D3DXANIMATION_H_
#define __D3DXANIMATION_H_#include "AllocateHierarchy.h"class CD3DXAnimation
{
private:IDirect3DDevice9* m_pDevice; //D3D设备对象CAllocateHierarchy* m_pAllocateHier; //骨骼动画网格模型指针LPD3DXFRAME m_pFrameRoot; //帧LPD3DXANIMATIONCONTROLLER m_pAnimController; //动画控制器D3DXMATRIX* m_pBoneMatrix; //骨骼矩阵
private://一些微软自带函数,关于骨骼动画加载与绘制更新的函数,将其封装,不使用这些接口void DrawMeshContainer( IDirect3DDevice9* pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase );void DrawFrame( IDirect3DDevice9* pd3dDevice, LPD3DXFRAME pFrame );HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrameBase, LPD3DXFRAME pFrameRoot );void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );
public:CD3DXAnimation(IDirect3DDevice9* device);~CD3DXAnimation(void);//提供给外界的接口//创建骨骼动画bool Init(LPCTSTR filename);//通过名字设置要播放的骨骼动画void SetAnimationByName(LPCTSTR name);//更新位置void SetMatrix(LPD3DXMATRIX mtrix);//更新动画void UpdateAnimation(double timeDelay);//绘制骨骼动画void Render();
};#endif
#include "stdafx.h"
#include "D3DXAnimation.h"CD3DXAnimation::CD3DXAnimation(IDirect3DDevice9* device):m_pDevice(device),m_pAllocateHier(NULL),m_pAnimController(NULL),m_pFrameRoot(NULL),m_pBoneMatrix(NULL)
{
}CD3DXAnimation::~CD3DXAnimation(void)
{D3DXFrameDestroy(m_pFrameRoot, m_pAllocateHier);SAFE_RELEASE(m_pAnimController);SAFE_DELETE(m_pAllocateHier);
}//--------------------------------------------------------------------------------------
// Name: SetupBoneMatrixPointers()
// Desc: 设置好各级框架的组合变换矩阵。
//--------------------------------------------------------------------------------------
HRESULT CD3DXAnimation::SetupBoneMatrixPointers( LPD3DXFRAME pFrameBase, LPD3DXFRAME pFrameRoot )
{if( pFrameBase->pMeshContainer != NULL ){D3DXFRAME_DERIVED* pFrame = NULL;D3DXMESHCONTAINER_DERIVED* pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pFrameBase->pMeshContainer;// if there is a skinmesh, then setup the bone matricesif (pMeshContainer->pSkinInfo != NULL){UINT cBones = pMeshContainer->pSkinInfo->GetNumBones();pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];for (UINT iBone = 0; iBone < cBones; iBone++){pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName(iBone));if (pFrame == NULL) return E_FAIL;pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;}}}if (pFrameBase->pFrameSibling != NULL){if (FAILED(SetupBoneMatrixPointers(pFrameBase->pFrameSibling, pFrameRoot)))return E_FAIL;}if (pFrameBase->pFrameFirstChild != NULL){if (FAILED(SetupBoneMatrixPointers(pFrameBase->pFrameFirstChild, pFrameRoot)))return E_FAIL;}return S_OK;
}//--------------------------------------------------------------------------------------
// Name: DrawFrame()
// Desc: 绘制骨骼
//--------------------------------------------------------------------------------------
void CD3DXAnimation::DrawFrame( IDirect3DDevice9* pd3dDevice, LPD3DXFRAME pFrame )
{if (pFrame == NULL) return;LPD3DXMESHCONTAINER pMeshContainer;pMeshContainer = pFrame->pMeshContainer; // 取得网格容器while( pMeshContainer != NULL ) {DrawMeshContainer(pd3dDevice, pMeshContainer, pFrame); // 绘制非空蒙皮网格pMeshContainer = pMeshContainer->pNextMeshContainer; // 遍历所有网格容器}DrawFrame(pd3dDevice, pFrame->pFrameSibling); // 绘制兄弟框架DrawFrame(pd3dDevice, pFrame->pFrameFirstChild); // 绘制子框架
}//--------------------------------------------------------------------------------------
// Name: DrawMeshContainer()
// Desc: 绘制蒙皮容器中的蒙皮网格
//--------------------------------------------------------------------------------------
void CD3DXAnimation::DrawMeshContainer( IDirect3DDevice9* pd3dDevice, 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;D3DXMATRIXA16 matTemp;D3DCAPS9 d3dCaps;pd3dDevice->GetDeviceCaps( &d3dCaps );// first check for skinningif( pMeshContainer->pSkinInfo != NULL ){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( 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 blendsfor( DWORD i = 0; i < pMeshContainer->NumInfl; ++i ){iMatrixIndex = pBoneComb[iAttrib].BoneId[i];if( iMatrixIndex != UINT_MAX ){D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );}}pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, NumBlend );// lookup the material used for this subset of facesif( ( AttribIdPrev != pBoneComb[iAttrib].AttribId ) || ( AttribIdPrev == UNUSED32 ) ){pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );AttribIdPrev = pBoneComb[iAttrib].AttribId;}// draw the subset now that the correct material and matrices are loadedpMeshContainer->MeshData.pMesh->DrawSubset( iAttrib );}}pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, 0 );}else // standard mesh, just draw it after setting material properties{pd3dDevice->SetTransform( D3DTS_WORLD, &pFrame->CombinedTransformationMatrix );for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++ ){pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );pMeshContainer->MeshData.pMesh->DrawSubset( iMaterial );}}
}//--------------------------------------------------------------------------------------
// Name: UpdateFrameMatrics()
// Desc: 更新框架中的变换矩阵
//--------------------------------------------------------------------------------------
void CD3DXAnimation::UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix )
{if (pFrameBase == NULL || pParentMatrix == NULL) return;D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase;// 将当前骨骼的相对于父骨骼的偏移矩阵作累积运算D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix); // 更新兄弟骨骼UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix); // 更新子骨骼
}//---------------------------------------------------------
//Name:真正暴露给外部调用的函数
//Desc:关于动画的创建,更新,绘制
//---------------------------------------------------------bool CD3DXAnimation::Init(LPCTSTR filename)
{m_pAllocateHier = new CAllocateHierarchy();D3DXLoadMeshHierarchyFromX(filename, D3DXMESH_MANAGED, m_pDevice, m_pAllocateHier, NULL, &m_pFrameRoot, &m_pAnimController);SetupBoneMatrixPointers(m_pFrameRoot, m_pFrameRoot);return true;
}void CD3DXAnimation::SetAnimationByName(LPCTSTR name)
{LPD3DXANIMATIONSET pAnimationSet = NULL;m_pAnimController->GetAnimationSetByName(name, &pAnimationSet);m_pAnimController->SetTrackAnimationSet((UINT)1.0, pAnimationSet);
}void CD3DXAnimation::SetMatrix(LPD3DXMATRIX mtrix)
{UpdateFrameMatrices(m_pFrameRoot, mtrix);
}void CD3DXAnimation::UpdateAnimation(double timeDelay)
{m_pAnimController->AdvanceTime(timeDelay, NULL);
}void CD3DXAnimation::Render()
{DrawFrame(m_pDevice, m_pFrameRoot);
}
使用骨骼动画类:
<span style="white-space:pre"> </span>g_pAnimation1 = new CD3DXAnimation(g_pDevice);g_pAnimation1->Init("tiny.x");
2.逻辑更新&绘制(两步暂时放在了一起):
g_pAnimation->SetMatrix(&matWorld1);g_pAnimation->UpdateAnimation(fElasedTime * 1);g_pAnimation->Render();
好了,这样就大功告成了。封装好了的骨骼动画类使用起来灰常方便,只要导入一个骨骼动画.X文件,就可以创建模型并让它动起来啦。
这样,这个小人就走起来啦,终于看到模型动起来了,好激动。。。
Direct-X学习笔记--骨骼动画相关推荐
- Direct 3D学习笔记(三)——光照与材质
Direct 3D学习笔记(三)--光照与材质 现实世界中物体的颜色是一个复杂的系统,物体在不同的光照下,可能呈现在我们面前的就是不同的颜色.根据物理中的光学知识,物体在各种环境光照下,根据物体自身特 ...
- android学习笔记---55_frame动画的实现,Java技术qq交流群:JavaDream:251572072
android学习笔记---55_frame动画的实现,Java技术qq交流群:JavaDream:251572072 Java技术qq交流群:JavaDream:251572072 2013/5/1 ...
- unity2D学习笔记-角色动画
unity2D学习笔记-角色动画 角色移动 动画效果(重点!!!!!) 创建:Animator与Animation 状态转换 跳跃 从fall到idle Hierarchy中创建一个Sprite作为载 ...
- 学习笔记 JavaScript 动画
学习笔记 JavaScript 动画 结果 代码里用到的图片 <html><head><style>#imageDiv {height: 100px;width: ...
- 学习笔记 JavaScript 动画 加速
学习笔记 JavaScript 动画 加速 效果 代码中用到的图片 <html><head><style>#imageDiv {position: absolute ...
- Mr.J-- jQuery学习笔记(十七)--动画淡入淡出弹窗广告
之前写过动画的隐藏与显示:Mr.J-- jQuery学习笔记(十四)--动画显示隐藏 动画隐藏与显示的一个小demo--对联广告:Mr.J-- jQuery学习笔记(十五)--实现页面的对联广告 展开 ...
- 【Unity 学习笔记】动画组件和动画控制器
动画是一款游戏不可缺少的一部分.在Unity中,我们可以直接使用Unity自带的动画系统来制作我们想要的动画,其操作相当便捷. 帧动画是2D像素游戏的主流,我将以帧动画为例记录我最近学习动画系统的一些 ...
- react native学习笔记29——动画篇 Animated高级动画
1.前言 上一节我们学习了全局的布局动画api--LayoutAnimation,体验到其流畅柔和的动画效果,但有时我们需要实现一些更精细化的动画,或者完成一些组合动画,这时我们可以使用React N ...
- 单目深度估计 | Learning Depth from Monocular Videos using Direct Methods 学习笔记
文章目录 摘要 1. 论文主要贡献: 2. 从视频中学习预测深度 2.1 尺度模糊 2.2 建模姿态估计预测器 3. 可微分直接视觉测距法 3.1 直接视觉测距法(DVO) 3.2 可微分的实现 4 ...
最新文章
- Vue开发使用Axios遇到了大坑!
- 一位美国前辈工程师的十大职业发展忠告
- 宝贝,来,讲讲spring事务有哪些坑?
- 子图同构问题与Ullmann Algorithm 算法(一)
- System.PlatformNotSupportedException
- php 数组格式的字符串转为数组_php将字符串转换为数组实例讲解
- SAP Spartacus Unit List树形数据的加载
- Rust 让人奔溃的那些特性!
- python 异步api ThreadPoolExecutor 、ProcessPoolExecutor(多线程、多进程)
- 使用ASP.NET MVC构建HTML5离线web应用程序
- FAQ 工作薄及工作表
- 鸿蒙2.0手机交互体验,鸿蒙 2.0手机应用开发者Beta,来了!全新交互体验
- IDEA设置背景颜色
- React 可视化开发工具 shadow-widget 最佳实践(上)
- Vue开发环境搭建,Vue.js安装,浏览器辅助工具Vue-devtools
- 即将到来的Xcode8 都更新了什么?
- awb数据怎么计算_自动白平衡(AWB)算法
- 分享几个图床网址,便于大家分享图片
- 2021-11-03如何删除文件夹名中间有【空格】及后边带有“..”的文件夹
- Vue控制表格列的显示隐藏
热门文章
- java安装失败错误代码1603_Java安装未成功错误代码1603?
- python画大象_[python实现设计模式]-2.模板方法模式---把大象关进冰箱.
- 单量子比特的布洛赫球(Bloch Sphere)分析
- iphone手机里的计算机没有了怎么办,iPhone连到系统上的设备没有发挥作用怎么办...
- this和super关键字详解
- “星际穿越”观后感(宇宙只是界面,科技永远触摸不到世界的本原)
- 如何判断数组为null还是为空?
- java类加载器以及spi
- pg数据类型及数据类型转换
- Android studio相对布局