骨骼动画的实现

来源:互联网 发布:茉莉机器人3.3源码 编辑:程序博客网 时间:2024/05/17 04:30

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
);

原创粉丝点击