动画基础概念
3D模型动画的基本原理是让模型中各顶点的位置随时间变化。主要种类有Morph(变形)动画,关节动画和骨骼蒙皮动画(SkinnedMesh)。
(自己搭的blog被黑了,只有本地备份,太伤了,所以文章会有一些格式问题)
从动画数据的角度来说,三者一般都采用关键帧技术,即只给出关键帧的数据,其他帧的数据使用插值得到。但由于这三种技术的不同,关键帧的数据是不一样的。
- Morph(渐变,变形)动画是直接指定动画每一帧的顶点位置,其动画关键中存储的是Mesh所有顶点在关键帧对应时刻的位置。
- 关节动画的模型不是一个整体的Mesh,而是分成很多部分(Mesh),通过一个父子层次结构将这些分散的Mesh组织在一起,父Mesh带动其下子Mesh的运动,各Mesh中的顶点坐标定义在自己的坐标系中,这样各个Mesh是作为一个整体参与运动的。动画帧中设置各子Mesh相对于其父Mesh的变换(主要是旋转,当然也可包括移动和缩放),通过子到父,一级级的变换累加(当然从技术上,如果是矩阵操作是累乘)得到该Mesh在整个动画模型所在的坐标空间中的变换(从本文的视角来说就是世界坐标系了,下同),从而确定每个Mesh在世界坐标系中的位置和方向,然后以Mesh为单位渲染即可。关节动画的问题是,各部分Mesh中的顶点是固定在其Mesh坐标系中的,这样在两个Mesh结合处就可能产生裂缝。
- 第三类就是骨骼蒙皮动画即SkinnedMesh了,骨骼蒙皮动画的出现解决了关节动画的裂缝问题,而且效果非常酷,发明这个算法的人一定是个天才,因为SkinnedMesh的原理简单的难以置信,而效果却那么好。骨骼动画的基本原理可概括为:在骨骼控制下,通过顶点混合动态计算蒙皮网格的顶点,而骨骼的运动相对于其父骨骼,并由动画关键帧数据驱动。一个骨骼动画通常包括骨骼层次结构数据,网格(Mesh)数据,网格蒙皮数据(skin info)和骨骼的动画(关键帧)数据。下面将具体分析。
SkinnedMesh中文一般称作骨骼蒙皮动画,正如其名,这种动画中包含骨骼(Bone)和蒙皮(Skinned Mesh)两个部分,Bone的层次结构和关节动画类似,Mesh则和关节动画不同:关节动画中是使用多个分散的Mesh,而Skinned Mesh中Mesh是一个整体,也就是说只有一个Mesh,实际上如果没有骨骼让Mesh运动变形,Mesh就和静态模型一样了。
Skinned Mesh技术的精华在于蒙皮,所谓的皮并不是模型的贴图(也许会有人这么想过吧),而是Mesh本身,蒙皮是指将Mesh中的顶点附着(绑定)在骨骼之上,而且每个顶点可以被多个骨骼所控制,这样在关节处的顶点由于同时受到父子骨骼的拉扯而改变位置就消除了裂缝。
Skinned Mesh这个词从字面上理解似乎是有皮的模型,哦,如果贴图是皮,那么普通静态模型不也都有吗?所以我觉得应该理解为具有蒙皮信息的Mesh或可当做皮肤用的Mesh,这个皮肤就是Mesh。
而为了有皮肤功能,Mesh还需要蒙皮信息,即Skin数据,没有Skin数据就是一个普通的静态Mesh了。
Skin数据决定顶点如何绑定到骨骼上。顶点的Skin数据包括顶点受哪些骨骼影响以及这些骨骼影响该顶点时的权重(weight),另外对于每块骨骼还需要骨骼偏移矩阵(BoneOffsetMatrix)用来将顶点从Mesh空间变换到骨骼空间。在本文中,提到骨骼动画中的Mesh特指这个皮肤Mesh,提到模型是指骨骼动画模型整体。骨骼控制蒙皮运动,而骨骼本身的运动呢?当然是动画数据了。
每个关键帧中包含时间和骨骼运动信息,运动信息可以用一个矩阵直接表示骨骼新的变换,也可用四元数表示骨骼的旋转,也可以随便自己定义什么只要能让骨骼动就行。除了使用编辑设定好的动画帧数据,也可以使用物理计算对骨骼进行实时控制。
-
线性混合蒙皮算法
在骨骼动画的蒙皮算法中,出现最早、最经典,也是应用最为广泛的算法是线性混合蒙皮算法。
根据骨骼动画的基本原理,动画模型之所以能够运动,是由于其骨骼带动了蒙在骨骼之上的皮肤一同动作,实现了动画效果。因此,因首先设置好模型骨架以及各骨骼之间的关联性,当运动数据到来时,计算皮肤顶点的新位置,就可以完成模型的运动。

黑色与白色的皮肤顶点分别与其相同颜色的骨骼相绑定。

方框里的皮肤顶点离两个骨骼关节最近,它们同时受到两个骨骼关节的影响。当骨架运动的时候,对于这些受多个骨骼共同影响的皮肤顶点,我们要计算它们变换后的位置信息,即找到皮肤网格自动变形后的方法,传统一般采用线性混合蒙皮算法。线性混合蒙皮算法是由 Lander 最早提出并实现的一种柔性绑定算法。Lander 利用线性混合蒙皮算法实现了人体上臂的动画,解决了之前的刚性绑定算法在关节处的失真问题。该算法的基本原理可以用下列公式表示

V表示顶点变换前的世界坐标系中的位置,V'表示顶点变换后的位置,i 表示同时影响该顶点的骨骼数量,一般取 2-4 之间的值。W_i表示第 i 个骨骼对该顶点的施加的影响权重,取 0-1 之间的值,M_i表示在模型初始参考姿势下,与顶点相关的第 i 个骨骼由本地坐标转换为世界坐标的转换矩阵(即骨骼变换的绝对矩阵),通过矩阵M_i能将骨骼 i 从初始位置转换到动画数据来到时的新位置上.
综上所述,线性混合蒙皮算法即是求得一个顶点在每个骨骼影响下的一系列新的位置,然后对这些位置数据进行加权平均计算得到最后的结果。
在线性混合蒙皮算法中,顶点的新位置 V′是通过其初始位置V 乘以一个矩阵 C 得到,这个矩阵被称为变换矩阵。

我们可以使用 OFFSET(偏移)的 3 个量来表示子关节相对父关节的偏移量;用 CHANNELS 来表示关节旋转通道数量和旋转顺序,其中根关节有6个通道,其他关节有3个通道,与根关节相比少了XYZ的位置(position)信息,这是因为其他关节都可以根据相对其于父关节的偏移量计算坐标位置。
运动数据对应的是骨架信息中各关节点的层次数据,即CHANNELS 中 Zrotation Xrotation Yrotation 顺序的数据。对于子关节来说,平移信息存储在骨架信息的 OFFSET 中,旋转信息则来自于运动数据部分;对于根关节来说,平移量是 OFFSET 和运动数据部分中定义的平移量之和。要得到蒙皮所需的绝对变换矩阵,首先需要根据 BVH 文件中的旋转数据分别创建三个方向轴(Y 轴,X 轴,Z 轴)对应的旋转矩阵,然后将它们按顺序相乘得到矩阵R (也称相对矩阵):

绝对变换矩阵是由关节的相对矩阵乘上它的父关节的绝对矩阵得到的,其中,根关节的绝对变换矩阵就是它的相对矩阵。因此,根据骨架各关节之间的关系,可以计算出每一个关节的绝对变换矩阵,用来将关节的本地坐标变换为世界坐标。
在骨骼动画中,一般使用正向运动学和逆向运动学将运动数据作用到动画模型上。正向运动学是从模型的根节点开始(对人体模型来说,髋关节就是根节点),根据骨骼的拓展顺序,逐个计算各关节在动画数据下的偏移和旋转量,直至到达末端节点为止。
蒙皮算法中变换矩阵的计算实际上就是插值的计算。对于动画中发生动作的骨骼,应根据该骨骼的数据找出其前后两个关键帧,根据时间差进行插值计算。对于使用四元数表示旋转的情况,可以使用四元数线性插值或四元数球面插值。将插值得到的四元数转换成变换矩阵(旋转矩阵部分),最后更新骨骼之间的层次关系,计算出各个骨骼的绝对变换矩阵,完成顶点的新位置计算。
2.线性混合蒙皮算法的缺陷
线性混合蒙皮算法需要手工设置骨骼对皮肤顶点影响的权重值,这项工作繁琐耗时,并且要求设计者对模型的构成要比较熟悉。不过随着建模软件的日趋完善,现在已经有很多建模软件简化了权重设置这项工作,比如常用的 3DMax、Maya 等大型 3D 建模软件,为骨骼与皮肤的绑定提供了很多便捷的操作功能,能大大节省该工作的时间,提高工作效率。
另外,线性混合蒙皮算法因其原理为线性计算,有一个无法克服的缺陷:对于比较灵活的关节(如肩膀),当关节处旋转角度很大时,会产生皮肤失真的结果,比如皮肤的塌陷、扭曲打结(裹糖纸)等现象。

v1和v2是皮肤顶点v分别受两端骨骼单独作用时变换的位置,v点变换后的坐标是v1和v2的线性加权平均。因为v1和v2都是在世界坐标系下变换得到的顶点坐标,直接的线性加权平均导致混合后的新顶点损失了v在关节局部坐标系下的向量长度信息,所以导致了皮肤塌陷的现象。除了产生皮肤塌陷的失真问题,发生更大角度的旋转的关节区域的皮肤还会出现扭曲现象(即“裹糖纸”现象)。我们假设人体模型的肩部关节绕 x 轴旋转180 度,那么在上述公式中骨骼变换的绝对矩阵可以写为:


也就是说,我们可以将骨骼变换的绝对矩阵进行混合操作,再与顶点位置V相乘得到新顶点的位置。可以看到,即使所有的变换矩阵Mi是刚性的,括号内也是一个线性的变换过程,得到的结果不一定是刚性的转换矩阵(比如几个正交矩阵的线性组合不一定还是正交矩阵),这便可以解释线性混合蒙皮在关节旋转角度过大时出现皮肤塌陷或扭曲的现象了:在骨骼的旋转变换过程中出现了我们不需要的缩放和平移信息,而骨架只提供运动信息,没有对皮肤的体积进行很好的控制和支撑,因此皮肤可以任意内陷。在关节旋转超过 60 度时,这种内陷尤其明显,这就是线性混合蒙皮中皮肤失真的主要原因。
- World Space:世界坐标系
- local-space :局部空间假定 骨骼变换相对于其父骨骼
- Component Space:组件空间假定骨骼变换相对于 SkeletalMeshComponent
- Bone Space:以EffectorSpaceBoneName配置的骨骼为原点的坐标系。
Poses 的变换可以在localSpace和Component Space都可以,一般来讲,在动画蓝图中使用姿势时,它们都位于局部空间中。但是,特定混合 节点和所有SkeletalControl都在组件空间中运算。这意味着,在将输入姿势传入这些类型的节点前, 需要变换这些姿势。如果输入姿势来自输出局部空间姿势的某个节点, 必须先将该姿势转换到正确的空间,然后SkeletalControl才能对它执行运算。 在执行运算后,必须将转换后的姿势重新转换回 局部空间,以便为其他混合或“结果(Result)”引脚提供输入。
一.UE4动画基本数据结构解析

骨架网格体由两部分构成:构成骨架网格体表面的一组多边形,用于是使多边形顶点产生动画的一组层次化的关联骨骼。USkeletalMeshComponent继承自USkinnedMeshComponent,也支持骨骼蒙皮的基本组件。
1.1USkeleton
对骨骼的理解
我们想要理解骨骼,首先先看看静态模型吧,静态模型没有骨骼,我们在世界坐标系中放置静态模型时,只要指定模型自身坐标系在世界坐标系中的位置和朝向。
在骨骼动画中,不是把Mesh直接放到世界坐标系中,Mesh只是作为Skin使用的,是依附于骨骼的,真正决定模型在世界坐标系中的位置和朝向的是骨骼。
在渲染静态模型时,由于模型的顶点都是定义在模型坐标系中的,所以各顶点只要经过模型坐标系到世界坐标系的变换后就可进行渲染。
而对于骨骼动画,我们设置模型的位置和朝向,实际是在设置根骨骼的位置和朝向,然后根据骨骼层次结构中父子骨骼之间的变换关系计算出各个骨骼的位置和朝向,然后根据骨骼对Mesh中顶点的绑定计算出顶点在世界坐标系中的坐标,从而对顶点进行渲染。
要记住,在骨骼动画中,骨骼才是模型主体,Mesh不过是一层皮,一件衣服。
如何理解骨骼?请看第二个观念:骨骼可理解为一个坐标空间。
在一些文章中往往会提到关节和骨骼,那么关节是什么?骨骼又是什么?下

最低0.47元/天 解锁文章
2390

被折叠的 条评论
为什么被折叠?



