您的位置:首页 > 其它

骨骼动画的实现

2013-08-20 23:03 435 查看
http://www.cppblog.com/lovedday/archive/2009/12/09/24729.html

http://www.cppblog.com/lovedday/archive/2008/06/11/52868.html

重点:
http://www.cppblog.com/lovedday/archive/2007/07/22/28595.html
http://www.cppblog.com/lovedday/archive/2008/04/22/47819.html 变换

具体是个什么样子原理尚不清楚,暂时放在这里,日后再详细写入

找了好久也没有找到合适的渲染代码,几处资料讲解的不够详细,以至于貌似冲突的样子。猜测下。

D3DMESHCONTAINER     A,B,C.....

D3DXFRAME    a1,a2,a3,a4,b1,b2.b3,........

虽然D3DXFRAME (框架骨骼)   中包含一个指向D3DMESHCONTAINER(容器)的指针,但貌似其并不是最顶层。A--->B---->C--->......, 也就是说容器作为一层,一个X文件可能形成几个容器结构,然后彼此通过指针串联起来。而每块骨骼都对应着某个容器,因此每个骨骼有一个指向容器的指针。而骨骼本身的层次则通过兄弟骨骼和子骨骼指针指向下去。当然里面也是一样子的。由此就可以解释了一个网格容器(MESH)当中,可能通过D3DXSKININFO 存储了多个骨骼的信息,一个X文件中可能有多个网格容器就是了。模型容器数据在某个数据对象当中,当然了数据对象有各种类型,通过类型可以判断是否为网格容器。

typedef struct _D3DXFRAME{                  //骨骼(框架)结构体

LPSTR Name;                         //骨骼名

D3DXMATRIX TransformationMatrix;    //相对于父骨骼坐标系的变换矩阵

LPD3DXMESHCONTAINER pMeshContainer; //网格容器

struct _D3DXFRAME* pFrameSibling;   //兄弟骨骼

struct _D3DXFRAME* pFrameFirstChild;//子骨骼

}D3DXFRAME,LPD3DXFRAME;

typedef struct _D3DMESHCONTAINER{           //网格容器结构体

LPSTR Name;                         //网格容器名

D3DXMESHDATA MeshData;              //网格数据

LPD3DMATERIAL pMaterials;          //网格材质

LPD3DXEFFECTINSTANCE pEffects;      //特效

DWORD NumMatrials;                  //材质数

DWORD* pAdjacency;                  //邻接三角形信息

LPD3DXSKININFO pSkininfo;           //蒙皮信息

struct _D3DMESHCONTAINER* pNextMeshContainer;      //下一个网格容器指针

}D3DMESHCONTAINER, *LPD3DMESHCONTAINER;

struct D3DXFRAME_DERIVED:public D3DXFRAME{ //骨骼(框架)扩展结构体

D3DXMATRIXA16 CombinedTransformationMatrix;        //动作变换矩阵

};

struct D3DMESHCONTAINER_DERIVED:public D3DMESHCONTAINER{   //网格容器扩展结构体

LPDIRECT3DTEXTURE9* ppTextures;     //纹理数组,如果没有纹理数组则为NULL

LPD3DXMESH pOrigMesh;               //原网格

LPD3DXATTRIBUTERANGE pAttributeTable;              //属性表

DWORD NumAttributeGroups;           //属性组个数

DWORD NumInfl;

LPD3DXBUFFER pBoneCombinationBuf;   //骨骼缓冲区

D3DXMATRIX** ppBoneMatrixPtrs;      //骨骼矩阵

D3DXMATRIX* pBoneOffsetMatrices;    //骨骼权重矩阵

DWORD NumPaletteEntries;

};

//在内存中创建一个Frame(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::CreateFrame(

LPCSTR Name,                        //框架名

LPD3DXFRAME* ppNewFrame             //返回创建的Frame对象

)

//创建一个网格容器(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::CreateMeshContainer(

LPCSTR Name,                        //网格容器名

const D3DXMESHDATA* pMeshData,      //网格数据

const D3DXMATERIAL* pMaterials,     //网格材质

const D3DXEFFECTINSTANCE* pEffectInstances,   //效果

DWORD NumMaterials,                 //材质数目

const DWORD* pAjacency,             //邻接三角形信息

LPD3DXSKININFO pSkinInfo,           //蒙皮信息

LPD3DXMESHCONTAINER* ppNewMeshContainer   //返回创建的网格对象

);

//释放一个帧(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::DestroyFrame(

LPD3DXFRAME pFrameToFree

);

//释放网格容器(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::DestroyMeshContainer(

LPD3DMESHCONTAINER pMeshContainerToFree

);

//ID3DXAllocateHierarchy接口的扩展类

class CAllocateHierarchy: public ID3DXAllocateHierarchy

{

public:

    STDMETHOD(CreateFrame)(THIS_ LPCTSTR 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);

public:

    CAllocateHierarchy(CSkinMesh *pSkinMesh) :m_pSkinMesh(pSkinMesh) {}

CSkinMesh* m_pSkinMesh;

};

/*----------------------该类的实现细节(内含4个纯虚函数的实现细节)-------------------------*/

//骨骼名称命名

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;

}

//创建并初始化一个帧并命名

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;

    //初始化帧的数据

    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;

}

//创建网格容器

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;

    if (pMeshData->Type != D3DXMESHTYPE_MESH) //如果不是网格数据类型

    {

        hr = E_FAIL;

        goto e_Exit;

    }

    pMesh = pMeshData->pMesh;

    if (pMesh->GetFVF() == 0) //取得定点的可变格式,返回0表示不能转换为可变格式

    {

        hr = E_FAIL;

        goto e_Exit;

    }

    pMeshContainer = new D3DXMESHCONTAINER_DERIVED; //申请内存

    if (pMeshContainer == NULL)

    {

        hr = E_OUTOFMEMORY;

        goto e_Exit;

    }

    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED)); //内存置0

    hr = AllocateName(Name, &pMeshContainer->Name); //网格容器命名

    if (FAILED(hr))

        goto e_Exit;        

    pMesh->GetDevice(&pd3dDevice);   //获得容器设备

    NumFaces = pMesh->GetNumFaces();   //获得网格的三角形面数

    //如果没有法向量,则添加它们

    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))

    {

        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

  

        //先复制

        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 

    pMesh->GetFVF() | D3DFVF_NORMAL, 

    pd3dDevice, &pMeshContainer->MeshData.pMesh );

        if (FAILED(hr))

           goto e_Exit;

        pMesh = pMeshContainer->MeshData.pMesh;

  

        //生成法向量

   D3DXComputeNormals( pMesh, NULL );

    }

    else 

    {

        pMeshContainer->MeshData.pMesh = pMesh;

        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

  

        pMesh->AddRef();

    }

    pMeshContainer->NumMaterials = max(1, NumMaterials);

    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];

    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];

    pMeshContainer->pAdjacency = new DWORD[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 (NumMaterials > 0)            

    {

        memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials);

  

        for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)

        {

           if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL)

           {

                TCHAR* strTexturePath=pMeshContainer->pMaterials[iMaterial].pTextureFilename;

                if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath, 

      &pMeshContainer->ppTextures[iMaterial] ) ) )

                    pMeshContainer->ppTextures[iMaterial] = NULL;

                pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;

           }

        }

    }

    else //没有材质,则添加一个默认值

    {

        pMeshContainer->pMaterials[0].pTextureFilename = NULL;

        memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9));

        pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;

        pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;

        pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;

        pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;

    }

    //存在蒙皮信息

    if (pSkinInfo != NULL)

    {

        pMeshContainer->pSkinInfo = pSkinInfo;

        pSkinInfo->AddRef();

  

        pMeshContainer->pOrigMesh = pMesh; //备份指针

        pMesh->AddRef();

        cBones = pSkinInfo->GetNumBones();

        pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];

        if (pMeshContainer->pBoneOffsetMatrices == NULL)

        {

           hr = E_OUTOFMEMORY;

           goto e_Exit;

        }

  

   //取得骨骼的权重矩阵

        for (iBone = 0; iBone < cBones; iBone++)

        {

           pMeshContainer->pBoneOffsetMatrices[iBone] = *

(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));

        }

  

        //生成蒙皮网格

        hr = m_pSkinMesh->GenerateSkinnedMesh(pMeshContainer);

        if (FAILED(hr))

           goto e_Exit;

    }

    *ppNewMeshContainer = pMeshContainer;

    pMeshContainer = NULL;

e_Exit:

    SafeRelease(pd3dDevice);

    //释放网格容器

    if (pMeshContainer != NULL)

    {

        DestroyMeshContainer(pMeshContainer);

    }

    return hr;

}

//释放帧

HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree) 

{

    SafeDeleteArray( pFrameToFree->Name );

    SafeDelete( pFrameToFree );

    return S_OK; 

}

//释放网格容器

HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)

{

    UINT iMaterial;

    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;

    SafeDeleteArray( pMeshContainer->Name );

    SafeDeleteArray( pMeshContainer->pAdjacency );

    SafeDeleteArray( pMeshContainer->pMaterials );

    SafeDeleteArray( pMeshContainer->pBoneOffsetMatrices );

    //释放所有纹理对象

    if (pMeshContainer->ppTextures != NULL)

    {

        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)

        {

           SafeRelease( pMeshContainer->ppTextures[iMaterial] );

        }

    }

    SafeDeleteArray( pMeshContainer->ppTextures );

    SafeDeleteArray( pMeshContainer->ppBoneMatrixPtrs );

    SafeRelease( pMeshContainer->pBoneCombinationBuf );

    SafeRelease( pMeshContainer->MeshData.pMesh );

    SafeRelease( pMeshContainer->pSkinInfo );

    SafeRelease( pMeshContainer->pOrigMesh );

    SafeDelete( pMeshContainer );

    return S_OK;

}

//装入骨骼动画

HRESULT WINAPI D3DXLoadMeshHierarchyFromX(

LPCTSTR Filename,                    //骨骼动画的.x文件名

DWORD MeshOptions,                   //D3DXMESH_MANAGED等选项

LPDIRECT3DDEVICE pDevice,            //关联的3D设备

LPD3DXALLOCATEHIERARCHY pAlloc,      //Frame层次对象生成接口

LPD3DXLOADUSERDATA pUserDataLoader, //一般为NULL

LPD3DXFRAME* ppFrameHierarchy,       //返回已具有层次结构的根Frame指针

LPD3DXANIMATIONCONTROLLER* ppAnimController //返回相应的动画控制器

);

//生成蒙皮网格

HRESULT ID3DXSkinInfo::ConvertToIndexedBlendedMesh(

LPD3DXMESH pMesh,                    //传入的原网格

DWORD Options,                       //当前并未使用 

DWORD paletteSize,                   //骨骼矩阵调用

const DWORD* pAdjacencyIn,           //传入的临界三角形信息

LPDWORD pAdjacencyOut,               //一般为NULL

DWORD* pFaceRemap,                   //一般为NULL

LPD3DXBUFFER* ppVertexRemap,         //一般为NULL

DWORD* pMaxVertexInfl,               //一个顶点可以受到骨骼影响的最大骨骼数

DWORD* pNumBoneCombinations,         //骨骼组合属性表中的骨骼数

LPD3DXBUFFER* ppBoneCombinationTable,   //骨骼组合属性表

LPD3DMESH* ppMesh

);

//ppBoneCombinationTable(骨骼组合属性表)的元素定义

typedef struct _D3DXBONECOMBINATION{

DWORD AttribId;                      //子集的属性id

DWORD FaceStart;                     //起始三角形面

DWORD FaceCount;                     //子集的三角形面个数

DWORD VertexStart;                   //起始顶点

DWORD VertexCount;                   //顶点计数

DWORD* BoneId;                       //该子集的各个骨骼

}D3DXBONECOMBINATION, *LPD3DXBONECOMBINATION;

//释放骨骼框架

HRESULT D3DXALLOCATEHIERARCHY::D3DXFrameDestroy(

LPD3DXFRAME pFrameRoot,              //根帧指针

LPD3DXALLOCATEHIERARCHY pAlloc       //创建帧层次结构的接口

);

//调整当前动画的时间点

HRESULT D3DXANIMATIONCONTROLLER::AdvanceTime(

DOUBLE TimeDelta,                    //动画进行的时间

LPD3DXANIMATIONCALLBACKHANDLER pCallbackHandler //回调处理,可设置为NULL

);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: