现在的位置: 首页 > 综合 > 正文

高效率3D图形程序中的骨骼

2013年09月12日 ⁄ 综合 ⁄ 共 2277字 ⁄ 字号 评论关闭
骨骼 皮肤动画技术是3D动画领域的一项比较高级的技术。由于其生动、逼真的效果,在影视制作、动态仿真等领域起着重要的作用。只有使用骨骼 皮肤技术,才能制作出广播级的动画作品。
  顾名思义,骨骼 皮肤动画的含义是使用一系列的骨骼去带动一张皮肤进行运动。其特点是:
  第一,作为皮肤的网格是一个整体,而不是分成区段的。
  在简单的区段动画中,一个复杂的物体是由许多“坚硬”的段组成的,最典型和常见的例子是人体,是由头、躯干、手臂、腿、脚等组成,而躯干又分上身、下身,手臂又分上臂、前臂和手,腿部又分为大腿和小腿。分别为这些段定义运动,就可以组成人体的较复杂的运动了。这种技术的优点是实现方便,而且运算速度快,适用于对视觉效果要求不高的场所。但是有一个致命的缺点是会在段与段之间相联接的地方出现明显的接缝,而在进行某些动作的时候会出现段与段分离的现象,这些在广播级的动画中是绝对不允许出现的。但是由于骨骼皮肤动画中的皮肤是一个整体,所以避免了这些情况的发生。
  第二,皮肤的形状是可以改变的,并且完全是由与其相关的骨骼决定的。
  皮肤不再是一个“硬梆梆的”网格,而是“有弹力的、能拉伸的”。相比区段动画中所有的由形状不变的生硬网格组成的区段,骨骼 皮肤动画中的皮肤能在任何时刻保持光滑、生动的外表,在制作一些像蛇、动物的尾巴等软的东西时尤其出色。
  既然骨骼 皮肤动画有这些好处,它又是怎么实现的呢?
  首先,需要有一个做皮肤用的网格和一系列骨骼。对于网格有一些要求,例如,在关节处的多边形数目应该多一些等等。而骨骼的大小和位置关系应该与皮肤相对应,因为要靠位置来判断骨骼影响了皮肤网格上的哪些点。
  然后,决定网格上的点是由哪快骨骼影响的。每一块骨骼都有一个作用范围,在这个范围中的点都要受该骨骼的影响。在关节处的点往往会受到多于一块的骨骼的影响,这些骨骼的影响通过不同的权值叠加在点上,使网格的关节部分尽量保持平滑。每一块骨骼都包括一组位置、朝向信息,借助这组信息,网格上的点确定自己的位置和朝向。这样就实现了骨骼对皮肤的影响。
  最后,设置骨骼的运动信息,带动受其影响的网格上的各点运动,就形成了动画。
  在一些3D动画软件中,第二步是即时算出来的,也就是说,一开始网格并不知道受哪些骨骼控制,只有建立了骨骼,并吧它付给网格后,软件才开始计算各点的位置是否在某一块骨骼的影响区域中,在所有的点都找到了自己的骨骼后,才可以进行动画。这种机制一般运用于各种3D动画设计软件中。
  在要求高效率的场合(如游戏中),这种方式是不可取的。为了实现高效率,预处理是一种普遍而有用的的方法。所谓预处理,就是在程序之外尽可能的把所有固定的数据处理好,并且为程序中优化的算法奠定基石。预处理的一个比较成功的例子是Id公司的Quake中对地图的处理。为了使Quake一帧场景中所需处理的多边形数目最少,需要对地图数据进行优化。采用BSP树和创立可能可见集可以达到优化的要求,但是为每一幅地图生成一棵BSP的过程是极其缓慢的。据ID公司的资料纪录,当时生成一棵BSP树用了十多分钟,而创立可能可见集的工作在一台有四个CPU的机器上用了约一个小时。然而每一地图的BSP树和可能可见集一旦生成,就可以在游戏中不再改变。这种情况下就可以采用预处理。借助于这种方法,Id公司的人员将Quake引擎的效率提高了一半以上。由这个例子我们可以看出预处理的道理就是“长痛不如短痛”。
  在高效率3D程序中要实现骨骼皮肤动画,也需要预先制作好皮肤和骨骼,并且在数据中记录皮肤网格上的各点分别受哪些骨骼控制。这就是一个预处理过程。另外,为了实现简化,在预处理时可以不靠骨骼的“影响区域”来确定骨骼影响的点。因为这样做需要确定网格的点与骨骼作用区域的相包含关系,这将是一个繁琐的过程。
  下面我们通过一个骨骼 皮肤动画的程序例子(下载)来分析一下其具体实现。
  我们选用的这个例子为一工作台模式的程序,采用VC++ 6.0编译,使用OpenGL加速,需要OpenGL实用工具库Glut的支持,并且使用了一个提供从3DS文件中读取数据的辅助库。此程序的功能包括两大部分:读入一个皮肤网格和一系列骨骼,确定网格和骨骼的关系;读入一系列动画信息,实现一个简单的动画。前者就是我们提到过的所谓预处理过程,是程序的重点。
  程序中首先定义了如下结构:

  typedef float MATRIX[4][3];   /*矩阵的定义*/
  struct Bone
  {
    struct  Bone *NextPtr;   /*使用链表存储骨骼*/
    char   Name[12];      /*这块骨骼的名字*/
    long   NrVerts;      /*这块骨骼影响的顶点的个数*/
    MATRIX  Matrix;      /*骨骼的初始化矩阵*/
    MATRIX* AnimPtr;       /*指向表示动画信息的矩阵数组的指针*/
  };

  struct Skin
  {
    long    NrFrames;     /*动画的帧数*/
    point3ds *PointPtr;     /*顶点缓存,用于暂时存储变换位置后的顶点*/
    Bone *  BonePtr;      /*骨骼链表的头节点*/
    mesh3ds * MeshPtr;      /*网格皮肤*/
  };

  struct BonePoint
  {
    point3ds  Point;      /*顶点的位置*/
    int    -->

作者:

抱歉!评论已关闭.