游戏人生

不积跬步,无以至千里;不积小流,无以成江海。

导航

引擎设计跟踪(九.5) 骨骼蒙皮动画预研

最近看了骨骼蒙皮的细节,之前只了解大致原理:

  • 用场景图类似的级联层次结构,组织骨骼的框架
  • 运行时根据骨骼的空间参数(旋转,位移,缩放)计算蒙皮顶点.

基本原理

  1. 使用级联(父子)层次关系的好处就是能够方便反应真实的情况: 手臂运动时,手掌和手指会跟着运动(这个需要没帧在CPU端计算骨骼树上的所有最终变换).
  2. 骨骼蒙皮动画也是关键帧动画,但跟早期的关键帧"顶点动画"(比如md2模型)不同的是,关键帧只保存骨骼的空间信息,而不是顶点位置信息.
  3. 一组顶点可能收到多个骨骼影响,所以会在运行时混合(加权平均) 出所有骨骼的最终影响.
  4. 每一帧骨骼的动作变换,是相对于骨骼自己所在的空间,所以做蒙皮的时候,要先将顶点从模型空间变换到骨骼空间,在骨骼空间做完当前帧运动计算后再最终转到世界空间.

Pw = Vl * Mb-1 * Mbkf * Mb * Mw;
Vl为原始顶点坐标,局部空间坐标.
Mb-1 为骨骼空间矩阵的逆, 这一步将局部空间坐标转到骨骼空间
Mbkf为当前帧动画的动作变换,完成顶点运动,(这个参数是位于骨骼空间的变换参数,把顶点变换到骨骼空间就是为了他)
Mb则将运动后的顶点再转到局部空间
最后Mw跟平常的局部空间->世界空间变换一样

Mbkf是cpu实时计算(关键帧插值)出来的,当然根据结合律,某些矩阵相乘可以预计算


贴一张GPU Gems上的公式 (source: http://gamedev.stackexchange.com/questions/28012/bones-animation-matrices-and-calculations):

 

 

一些技术细节

  1. 空间变换通常会用4x3矩阵(去掉w分量),作为骨骼变换矩阵的存储,
    但如果忽略缩放的话,也可以用一个四元数(旋转)+一个向量(位移) 来存储,以节省数据传输带宽.

    还可以用双四元数(Dual Quaternion)来计算骨骼动画,这里有参考
    http://isg.cs.tcd.ie/projects/DualQuaternions/


  2. 如果要兼容SM2.0的话,VS的cosntant buffer限制为256个
    (参考 http://en.wikipedia.org/wiki/High_Level_Shader_Language )

    如果用4x3矩阵的话, 最多骨骼矩阵数量大概为 256/3 = 80多个 (shader里其他基本的参数(比如senmatics)会占用一些)
    如果用双四元数(DQ),或者Q(R)+V(T)的话,为 256/2 大概一百多个的样子, 这个会节省相当可观的带宽 (要考虑多遍绘制时的多次传输)
    详细论述见Crytek的ppt (http://www.crytek.com/download/izfrey_siggraph2011.pdf )

  3. (per-vertex)blendweight也会传进shader用于加权混合

  4. 需要blend indices用来索引骨骼矩阵的数组

 

关于IK

这个是计划支持的特性(支持程度未定),目前正在找相关资料和看Doom3的与IK相关的源代码.

 


更新:

每个顶点受影响的骨骼数量, 即每个顶点的blend indices的个数, 一般来说是2-4, 这样方便用一个register保存. blend indices通常用uint8x4保存, blend weight 通常是uint8nx4.

由于每个mesh(一个draw call单位)对应的骨骼数量, 受constant register数量的影响, 会有限制. 如果骨骼太多, 则要把mesh拆分成多个mesh, 即用多个draw call分开bone matrices的绑定.

 

posted on 2013-05-09 12:33  crazii  阅读(866)  评论(3编辑  收藏  举报