骨骼动画(Character Animation with Direct3D )3_1学习心得

         第一次想自己写一个系列的文章,写的不好,大家别骂啊 ,也欢迎交流;

 

        从第三章开始才是真正的接触骨骼动画的内容,第一个例子讲解如何绘制一个简单的节点示意图(具体到人就是关节)

1.基本流程

     1)  D3DXLoadMeshHierarchyFromX(fileName, D3DXMESH_MANAGED, g_pDevice, &boneHierarchy, NULL, &m_pRootBone, NULL);

 解释一下各个参数的意思:

fileName:骨骼文件名

  boneHierarchy:应该是你自己实现的继承于ID3DXAllocateHierarchy并且已经实现了四个接口函数

  m_pRootBone:返回的根节点

   2)更新Bone中的CombinedTransformationMatrix,这里利用一个递归 子节点 = 子节点(D3DXFRAME中的TransformationMatrix) 父节点  ;

 其实Bone中的这个CombinedTransformationMatrix理论上可以不存在,加了这个数据会让绘制更方便操作也更易理解

D3DXFRAME中的TransformationMatrix 有人可能不太明白这个成员的意思:这个矩阵描述的是相对父节点的局部坐标矩阵

假设一个点现在处在父节点,那么这个节点 *  TransformationMatrix就到达了当前节点(在局部坐标系下的表示)

而CombinedTransformationMatrix可以理解为相对世界的坐标系(言外之意 一个点通过这个矩阵变换 , 一步就可以变换到当前节点)

假设我们现在有一个如下图的骨骼结构,当你绘制节点4的时候,如果你没有CombinedTransformationMatrix这个成员 你不得不计算 1 * 2 然后才能得到节点4,

但是这也会有问题1节点有两个子节点2和3 ,你怎么知道应该走2呢,所以CombinedTransformationMatrix更适合在初始化的时候就被递归更新,这样以后每次用直接拿来用就可以了

 

   3)Render(绘制)

这个没什么好说的 其实就是给一个实例图,每个小球都代表了一个节点, 子节点和父节点进行连线

2.注意事项:

         我买的是英文原版的,但是为了加深学习的印象,我在DXUT框架下自己实现了一下,但运行之后发现有的引用计数不为0,我通过D3D文档中的骨骼例子发现

BoneHierarchyLoader boneHierarchy;
 boneHierarchy.DestroyFrame(m_pRootBone);

这样调用只会释放掉一个,并不能将整棵树都释放掉

//应该调用下面的这个

BoneHierarchyLoader boneHierarchy;
    D3DXFrameDestroy(m_pRootBone, &boneHierarchy);

所以每个例子我建议大家都应该自己再写一遍,特别是D3D这个本来就很有难度的东西,如果只是看看书,是不行的

下面我们看下代码部分:(不可能全部讲解,只跳重点的 大家可以去下载这本书的源代码 再结合本文分析 )

下面的内容 最好是你已经自己实现了一遍(哪怕是照着抄了一遍都可以)

//调用

        D3DXMATRIX i;
        D3DXMatrixIdentity(&i);
        UpdateMatrices((Bone*)m_pRootBone, &i);

//实现

void SkinnedMesh::UpdateMatrices(Bone* bone, D3DXMATRIX *parentMatrix)
{
        if(bone == NULL)return;(所有节点都已循环绘制完毕)

       //计算当前的结合矩阵 = TransformationMatrix * 父矩阵 
        D3DXMatrixMultiply(&bone->CombinedTransformationMatrix,
            &bone->TransformationMatrix,
            parentMatrix);

        //计算兄弟节点

        if(bone->pFrameSibling)
        {
                UpdateMatrices((Bone*)bone->pFrameSibling,
                 parentMatrix);
        }

       //计算子节点

       if(bone->pFrameFirstChild)
       {
             UpdateMatrices((Bone*)bone->pFrameFirstChild,
             &bone->CombinedTransformationMatrix);
        }
}

//调用

m_drone.RenderSkeleton(NULL, NULL, world);

//实现

通过一个球体 代表关节 然后在子节点和父节点之间用直线连接

void SkinnedMesh::RenderSkeleton(Bone* bone, Bone *parent, D3DXMATRIX world)
{
 //Temporary function to render the bony hierarchy
 if(bone == NULL)bone = (Bone*)m_pRootBone;

 D3DXMATRIX r, s;
 D3DXMatrixRotationYawPitchRoll(&r, -D3DX_PI * 0.5f, 0.0f, 0.0f);

 //Draw line between bones
 if(parent != NULL && bone->Name != NULL && parent->Name != NULL)
 {
  //绘制球体
  g_pDevice->SetRenderState(D3DRS_LIGHTING, true);

//这个我有点疑问 一个球绕y轴旋转 会有什么用呢   不明白  欢迎大家给出解释
  g_pDevice->SetTransform(D3DTS_WORLD, &( r* bone->CombinedTransformationMatrix * world ));
  m_pSphereMesh->DrawSubset(0);

  D3DXMATRIX w1 = bone->CombinedTransformationMatrix;
  D3DXMATRIX w2 = parent->CombinedTransformationMatrix;

  //绘制线

  D3DXVECTOR3 thisBone = D3DXVECTOR3(w1(3, 0), w1(3, 1), w1(3, 2));
  D3DXVECTOR3 ParentBone = D3DXVECTOR3(w2(3, 0), w2(3, 1), w2(3, 2));

  if(D3DXVec3Length(&(thisBone - ParentBone)) < 2.0f)
  {
   g_pDevice->SetTransform(D3DTS_WORLD, &world);
   VERTEX vert[] = {VERTEX(ParentBone, 0xffff0000), VERTEX(thisBone, 0xff00ff00)};
   g_pDevice->SetRenderState(D3DRS_LIGHTING, false);
   g_pDevice->SetFVF(VERTEX::FVF);
   g_pDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, 1, &vert[0], sizeof(VERTEX));
  }
 }

 if(bone->pFrameSibling)RenderSkeleton((Bone*)bone->pFrameSibling, parent, world);
 if(bone->pFrameFirstChild)RenderSkeleton((Bone*)bone->pFrameFirstChild, bone, world);
}

//总结

理解基本流程,理解CombinedTransformationMatrix的含义 D3DXFRAME中的TransformationMatrix的含义

 

 

写的很菜,不过花了我很长时间,自己学到了很多东西,希望大家指正,我建议大家至少读过那本龙书再来看骨骼动画,当然你也可以直接看,不过理解起来吃力。

其实有很多东西我没有讲,比如你load之后,是d3d内部帮你构建了所有的对象,并且将他们自动连接到一起(兄弟节点和子节点的赋值),不过这些我认为我不可能将的特别清楚,这些理论上可以自己实现,你可以自己串一个链,然后调用render,只要你构造正确,也完全没问题。大家有什么不明白的,可以qq交流,我也是小菜鸟,骨骼动画更是初涉

 

 

qq:379187940  欢迎交流指正

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值