UE3骨骼动画开发笔记

发表于2017-03-23
评论1 2.2k浏览

UE3骨骼动画开发笔记

为了让游戏角色变得更生动形象,这就会使用到UE3的动画系统对骨骼进行开发,考虑到有些人还不会,下面就给大家介绍下UE3骨骼动画开发教程,一起来看看吧。

1.              3D动画类型介绍

 

3D模型的动画实现比较典型的有:帧动画骨骼动画morph动画

 

帧动画:在早期的机器上,渲染本身已经占用了很多CPU资源,因此,对于渲染,往往采取的是一种空间换时间的策略,以避免在模型的渲染中继续加重CPU的负担。帧动画模型在这种条件下应运而生。比较著名的帧动画格式是Quake2所采用的MD2。到今天为止,帧动画依然存在,只不过帧动画更多地是来描述小且动作相对少些的物体。

 

帧动画将每帧所需要的所有顶点的:顶点位置,法线或顶点颜色,纹理坐标等信息全部存储下来,在渲染的时候逐帧播放或插值播放,这就是帧动画的原理。

 

 

骨骼动画:

好莱坞电影制作中的动作捕捉仪器捕捉真人的骨骼数据,图中演员身上的白点即为要捕捉的骨骼数据感应器

 

骨骼动画技术后于帧动画技术出现。最开始,骨骼动画仅用于非实时渲染的建模领域,如3DMax这类建模软件之中,以方便美工的建模。后来,CPU从渲染中解放后,骨骼动画才用于实时渲染的游戏中。骨骼动画相对于帧动画而言,更加灵活多变,但同时,骨骼动画需要更多的计算量,因此早期的时候,骨骼动画往往应用在需要着重体现动作细节的模型中。GPU出现后,CPU的问题早已不像以前那么突出,对于现在新的硬件技术,帧动画已经逐渐过时了,所以,现在Unreal 3也已经不再支持帧动画方式了

 

骨骼动画,顾名思义,最初的想法就来源于人体骨骼运动原理。例如说,人的上肢所有肌肉和皮肤都受上肢骨胳的影响,而人的踝关节则分别承受小腿骨胳和脚骨的影响。根据这个我们可以将骨骼动画理解为两个概念:

 

骨骼:用以控制蒙皮的一种抽象的概念,如人体骨骼控制皮肤。

蒙皮:被骨骼控制、并显示在外的因素,如人体的皮肤被骨骼所影响。

 

在游戏中,骨骼除非是为了调试用,否则一般是不会渲染的,它只是一个变换的概念,说白了,骨骼就是一个变换矩阵(或者后面讲到的四元素和位移值的组合)。最终被渲染出来的是蒙皮的内容,蒙皮并非指模型表面的材质,它指的是模型的顶点、法线和UV纹理坐标等即将被渲染的所有元素。其中顶点是最为重要的元素,骨骼动画就是通过控制附着在骨骼上的顶点的运动来实现动画的。

 

骨骼权重:骨头与蒙皮顶点的关联需要考虑到每块骨头对蒙皮顶点的影响。尽管大部分情况下,一个顶点将仅仅被一个骨头的影响,但是关节处的顶点往往被多根骨头影响,例如踝关节,可能会分别受小腿骨50%和脚骨50%的影响,这种影响叫作权重(Weight)。在这种情况下,我们称踝关节的这些顶点,受小腿骨影响的权重是50%,受脚骨影响的权重也是50%。

 

骨骼动画算法的简单描述:如图所示

假设图中骨头A对顶点1的影响是100%。这时候,如果骨头A平移(1010),那么1同样平移(1010)。如果A以自身坐标系旋转30度,1同样应该以此骨头的自身坐标系旋转30度。

 

那么实际上,每根骨头最终将被换算成一个矩阵,这个矩阵记录了旋转,平移信息,我们用这个矩阵来对蒙皮顶点进行影响。在骨头中,一般使用四元数来获得旋转时的精确性,这样,骨头一般记录表示旋转的四元数和表示位移的一个矢量,最后,将四元数和矢量换算成骨头的矩阵,并用顶点与这个矩阵乘法以进行影响。在UE3中,骨骼信息通过FBoneAtom类来表示,FBoneAtom3个变量:

FQuat Rotation; // 保存骨骼旋转数据的四元数

FVector Translation; // 保存骨骼位移数据的向量

Float Scale; // 保存骨骼缩放信息的浮点数,骨骼缩放只支持等比例缩放

 

Morph动画:即变形动画。和骨骼动画不同的是,Morph动画的原理是,在现有模型的基础上(称之为基础模型),通过修改其某些部位的顶点,从而得到另一个顶点数相同的模型版本,然后以修改后的模型为一个“Morph目标”,按照一定的权重将基础模型变化到该目标,Morph动画工作的前提是这两个模型的顶点数目必须一样且一一对应。UE3引擎中,Morph目标是以叠加的方式应用的,也就是说,假如你的基础模型是没有任何表情,然后加入了一个“微笑”的Morph目标,嘴部的顶点会受到影响,再加入一个“挤眼”的Morph目标,眼部眉毛的顶点会受到影响,这两个部位的影响是叠加的,即同时出现微笑和挤眼运动的效果。如图所示:

图一:左一模型为应用Morph前的基础模型

图一:左一模型为应用Morph后的基础模型

 

UE3引擎中,Morph动画可以同骨骼动画协同工作,Morph目标在骨骼变化前应用到模型上。为了节省Morph目标集的存储空间,UE3在导入Morph目标时,会把它同基础模型比较,只存储那些和基础模型不同的顶点。当使用Morph目标时,它仅修改基础模型顶点的一个子集,这样便降低了内存的消耗。

 

 

2.              Unreal动画系统介绍

UE3动画系统术语:

AnimSequence:动画序列。例如:一个攻击动画序列、跑步动画序列。它保存了该动画序列每帧的骨骼变换数据。

 

AnimSet:动画集。即AnimSequence的集合。

 

AnimTree:动画树。它把多个动画数据通过树节点的方式混合起来,可以通过AnimTree编辑器方便清晰地管理各种复杂动画的混合。

 

AnimNodeSequence 动画序列节点(AnimTree里的节点,该节点会输出动画序列中的动画数据)

 

AnimBlendNode 融合节点(按照一定条件融合各动画节点进行动画输出的节点)

 

SkelController 骨骼控制器(针对某个特定骨骼进行操作的节点)

IK 逆向运动学(InverseKinematic

 

UE3动画系统概述:

UE3中的Mesh分为SkeletalMeshes(骨架网格物体)StaticMeshes(静态网格物体)。顾名思义,一个是带骨骼的Mesh,一个是不带骨骼的静态Mesh。在虚幻引擎中,带动画的网格物体称为SkeletalMeshes(骨架网格物体),因为基于骨骼的骨架动画是用于驱动游戏中物体的动画的主要机制。引擎的动画系统处理动画的流程大致如下图:

 

 

 

首先,通过SkeletalMesh指定的AnimSet进行插值混合等处理一般的动画,得到一份骨骼数据。然后,应用SkelControllerIK处理等对该骨骼数据进行处理。接下来,为该骨架设置物理。然后,物理子系统通过设置的物理权重处理剩余的物理到骨骼数据上,然后将最终的骨骼数据应用于Mesh顶点上。假如Mesh还有指定的Morph目标集,则先应用Morph目标位置的修改。最后,得到最终的Mesh顶点数据,图形子系统再渲染该Mesh

 

 

3.              UE3动画树

 

动画和动画之间可能需要平滑过度或者同时混合播放,这时就需要根据一定的条件赋予每个动画序列一定的权重进行融合。虚幻引擎3使用'混合树'AnimTree来把多个动画序列数据混合到一起。AnimTree让我们通过编辑器界面比较直观地管理、分类并融合不同的动画序列。通过AnimTree能够按照一定逻辑来混合动画序列源,并且能比较便捷地测试各分支混合的结果,下面是一个简单的动画树的样子:

 

动画树是由根结点及树节点组成。节点主要有两类:

    AnimTreeRoot (根节点)((蓝色框内的节点)动画树的根节点,在这里汇总了动画序列最终混合结果、骨骼控制器数据、Morph顶点数据,相当于动画树最终的输出。

Blend Nodes(混合节点)(绿色框内的节点)这些节点有一组子节点,并以某种方式把它们混合到一起。

Data Nodes(数据节点)(红色框内的节点)是树的叶子节点,没有子节点但实际上可以生成骨架变换。

 

混合节点中的黑色滑块是用来控制该节点不同分支的条件值,通过它可以很方便地测试AnimTree各个分支的动画效果。

 

AnimTree Root (根节点)的编辑:

 

 

点击根节点,AnimTree编辑器下方的属性框如上图所示,主要要配置预浏览模型及预浏览AnimSet,这样才能在编辑器的左上角显示出要编辑动画树的模型及观察对应动画效果。

 

 

几个典型的AnimTree节点使用:

 

 

1AnimNodeBlendBySpeed(按速度混合动画节点)

这个混合节点允许Anim Tree在拥有它的actor内由Velocity(速度)或Acceleration(加速度)向量的大小决定的约束条件之间的输入之间自动混合。

 

如图所示,黑色滑块在0.0的位置,即速度为0的情况下播放的是player_stand(静止)动画。

 

当滑块划过一定位置后便播放player_run动画,在程序中可以通过配置AnimNodeBlendBySpeed的属性Constraints来决定child1child2的速度范围,通过配置属性Use Acceleration来决定是否使用加速度值。

 

 

2AnimNodeBlendDirectional(定向混合动画节点)

该混合节点允许Anim Tree在表现拥有它的actor向前移动、向后移动、向左和向右的四个输入之间自动进行混合。该混合节点会将速度或加速度的方向与拥有它的actor的方向做比较,得到角色将要前往的方向,然后在前后左右的正向所对应的动画序列之间作插值得到最终的混合动画,如图所示,正在播放一个往前的动画。

 

 

3AnimNodeAimOffset(瞄准偏移动画节点)

 

游戏中,我们经常有这样的需求,比如玩家持有一把弓箭时,我们希望他能够将武器指向玩家的瞄准方向,根据不同方向旋转上半身抬头或者低头。如果针对每个方向都制作一个动画,那么动画制作人员工作量非常大,而且程序要去计算角色的瞄准方向,然后根据每个方向去引用具体的动画,也非常的繁杂。UE3AnimTree就提供了这样一个混合节点AnimNodeAimOffset,它能够帮助我们解决这样的问题。AnimNodeAimOffset是根据玩家的基础旋转(ActorRotator)和瞄准方向(AimDir)做一个比较得到一个相对旋转,从而得出玩家的瞄准方向。下图是一个AnimNodeAimOffset节点所在的AnimTree

 

双击AimNodeAimOffset,如下图,会出现9个瞄准方向的编辑视图,New一个Profile,然后AddBone,这里添加了一个上半身脊椎的骨骼Bip01-Spine

 

 

 

点击LeftUp按钮,能够在AnimTree编辑器里看到角色身上有一个旋转编辑视图,这时可以编辑玩家瞄准左上时,上半身的转向情况,如图所示:

 

编辑好9个方向后,就可以通过拖动AnimNodeAimOffset的黑色滑块来控制射箭动画的瞄准方向了,如下图所示,滑块滑向了左上角,角色对应向自身的左上角射箭:

 

 

下图所示,滑块滑向了右上角,角色对应向自身的左上角射箭:

 

至此为止,动画制作人员只需要提供一个射箭动画,而程序一行代码都不需要添加。

 

 

 

 

4AnimNodeBlendPerBone(基于每个骨骼混合的动画节点)

 

举个例子说明该节点的应用,比如在跑的同时射箭,需要在上半身播放射箭动作,下半身播放跑步动作,这个时候,就要用到AnimNodeBlendPerBone

 

如图所示,通过AimNodeBlendPerBone,将player_run设为源动画序列,player_shoot设为目标动画序列:

 

 

然后点击AimNodeBlendPerBone节点,编辑其属性:

 

 

我们将player_shoot动画所影响的骨骼开始分支设为Bip01-Spine2,即第二节脊椎骨骼,这样上半身完全受射箭动作控制,下半身受跑步动作控制,就能实现跑步同时射箭的需求。同理,游戏中,其他有许多需要在角色不同部位播放不同动画序列的情况,都可以用这个节点方便地满足需求。

 

 

UE3引擎另外还提供了大量有用的节点类型以满足一般的游戏动画需求,这里只象征性地介绍几个,有兴趣可以去这里看更多的内容:

http://udn.epicgames.com/Three/AnimationNodes.html

 

如果开发人员拥有源码权限,还可以根据自己的特定需求来添加动画节点类型。

 

 

4.              UE3骨骼控制器

 

UE3中,除了通过动画控制模型的运动,还可以通过骨骼控制器即SkelController来针对某个骨骼进行特殊的控制,编辑SkelController也是在AnimTreeEditor里编辑的,但是动画系统和骨骼控制是相互独立的系统,把他们都放在AnimTreeEditor里编辑是为了方便起见。在上文的动画系统概述中提到,骨骼控制器是应用在动画系统处理之后,所以它会在动画混合后的骨骼基础上再进行骨骼控制。

 

如图所示,在AnimTree跟节点上右键即可指定添加一个骨骼进行骨骼控制器的应用:

 

我们可以用用骨骼控制器来实现一些IK(逆运动学)特效,例如脚步适应不平整地面、上肢自适应不同长度的武器装备等,以及针对特定部位对模型进行拉伸缩放等效果,后面会专门用一个专题来详细介绍如何在代码和编辑器中实现这些效果。

 

应用SkelController实现的脚步自适应地面效果:

 

 

 

另外同骨骼控制器一样,Morph动画也是在AnimTree中进行编辑,它同动画系统也是相互独立的,也是为了方便同样放在AnimTree中编辑,后面也会专门用一个专题来介绍使用Morph进行捏脸的实现。

 

 

 

 

5.              动画相关脚本

 

SkeletalMeshAnimSet(动画集)添加及AnimTree(动画树)添加:

defaultproperties

{

Begin Object Class=SkeletalMeshComponentName=SkeletalMeshComponent

   SkeletalMesh=SkeletalMesh'BigCritter.CritterMesh'

 AnimSets(0)=AnimSet'BigCritter.CritterAnims'

AnimTreeTemplate=AnimTree'BigCritter.CritterAnimTree'

End Object

}

 

如果是动态添加的SkeletalMesh,可以像下面这样添加:Mesh.SetAnimTreeTemplate(AnimTree'BigCritter.CritterAnimTree');

Mesh.AnimSets.AddItem(AnimSet'BigCritter.CritterAnims');

 

 

在脚本中寻找动画节点、骨骼控制器、Morph节点:

local AnimNode animNode;
local SkelControlBase seklControlBase;
local MorphNodeBase morphNodeBase;


animNode = Mesh.FindAnimNode('AnimNodeName');
SkelControlBase = Mesh.FindSkelControl;
MorphNodeBase = Mesh.FindMorphNode;

 

// todo,再根据需求对节点进行具体设置

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论