Unity Manual阅读记录——Animation(version 2019.4)

Animation简介在这里插入图片描述

Unity提供的动画系统的主要功能:

  • retargetable animations:重定向动画
  • full control of animation weights at runtime: runtime控制动画的权重
  • event calling from within the animation playback :动画播放途中调用event
  • sophisticated state machine hierarchies and transitions:精妙的动画状态机,包括hierarchy和transition
  • blend shapes for facial animations:用于面部动画的blend shape
  • and much more

这一部分的Manual主要是介绍了以下内容:

  • how to import and work with imported animation:如何导入动画(应该是动画资源),从而能够使用该动画
  • how to animate objects, colours, and any other parameters within Unity itself:如何在Unity里,制作关于物体、颜色和其他参数的动画


Animation System Overview

Unity提供的强大的动画系统,也被称为mecanim

Mecanim名字的由来
Mec源自法语,意思是Guy,也就是说,Mecanim最开始就是Unity为了人形模型设计的动画系统,Mecanim可以处理动画重定向,控制muscle,这个时候就是用Animator组件来控制人形动画,用Animation组件控制其他非人形动画。

后来Mecanim就逐渐发展到现在的也包括非人形动画了,而原有的Animation组件被弃用了。

mecanim有以下特点:

  • 简单易用的工作流,可以轻松设置动画相关的属性
  • Support for imported animation clips and animation created within Unity(Animation Clip的本质是什么?后面会提到)
  • Humanoid animation retargeting:将人物A的动画转换到人物B上面,注意这里是人形动画
  • Simplified workflow for aligning animation clips(aligning animation clips什么意思?)
  • 动画状态机
  • 支持用不同的逻辑操纵不同身体的部位
  • Layering and masking features

总结一下,重点在于:

  • 动画资源导入
  • 动画状态机和工作流的支持
  • 动画相关特点,比如人物动画重定向、Avatar Mask等

Animation workflow

Unity’s animation system is based on the concept of Animation Clips, which contain information about how certain objects should change their position, rotation, or other properties over time.

Unity的动画资源
Unity的动画系统,是基于Animation Clip(这里是Unity定义的Animation Clip的概念,后面会继续补充)的。Animation Clip本质上,记录的是随着时间的变化,物体在这一段时间里的状态记录,这里的状态具体是指的颜色、位置、旋转等参数,一段时间内这些参数的变化,构成了一段动画。
AnimationClip 主要是由外部的3D软件创建而来,注意,除了3dMax和Maya创建的动画Clip,也可以由Motion Capture制作相关动画:

  • Autodesk® 3ds Max®
  • Autodesk® Maya®,
  • Motion capture studios or other sources.

Unity的动画状态机:前面提到Unity提供了类似动画状态机的东西,也就是Animator Controller,复杂的为角色设置的Animator Controller,可以包含非常多的角色自带的动画,还可以同时在多个clip里blend(这个blend between multiple clips at the same time具体是怎么个blend法?)。

A more advanced Animator Controller might contain dozens of humanoid animations for all the main character’s actions, and might blend between multiple clips at the same time to provide a fluid motion as the player moves around the scene.

Unity的动画重定向:Unity的人形动画重定向的功能是基于Unity的Avatar实现的,只要是人型角色,其动作都可以map到相同的avatar上,基于此,Unity可以把外部的动画数据,比如动捕数据、Asset Store或第三方动画库里面的动画重定向到Unity里面人形model上。

Animator组件 上面说的Avatar、AnimationClip和Animator Controller,都会全部放在一个叫做Animator的组件里,其中AnimationClip会放在Animator Controller里面,这里的存储关系应该都是存的reference,如下图所示,注意非humanoid的动画类型,其Animator组件不需要Avatar这个东西:
在这里插入图片描述

补充几点:
Unity里的AnimationClip怎么来的?
可以由Unity内部创建,也可以由外部资源导入,比如第三方插件或者动补做出来的Animation Clip

Avatar资源存储的是什么?
导入的模型,本身是有自己的Bone的数据的,然而他需要映射(map)成Unity统一的Avatar格式,然后Unity才可以统一对humanoid的模型做处理,而这个avatar,是在导入模型时Unity会自动赠送的东西,算是模型数据的一部分,如下图所示:
在这里插入图片描述
在这里插入图片描述



Legacy animation system

While Mecanim is recommended for use in most situations, Unity has retained its legacy animation system which existed before Unity 4. You may need to use when working with older content created before Unity 4. For information on the Legacy animation system, see this section

这是老版的Unity动画系统,已经基本弃用掉了,现在用的就是Mecanim.



Animation Clips

前面提到了,Animation Clip本质上就是物体在一段时间内的属性的变换,Animation Clip可以由Unity从外部导入,也可以自己在Unity里制作,制作的方法是在Unity的Animation窗口里进行,如下图所示:
在这里插入图片描述

一. Animation from External Sources
外部导入的Animation Clip可以有如下途径:

  • 动作捕捉创建的Humanoid animations
  • 3D美术软件创建的动画
  • 第三方的资源包,比如Unity Asset Store
  • 从导入的timeline里切分出来的动画(Multiple clips cut and sliced from a single imported timeline)

如下图所示,是一个Animation Clip的属性展示栏:
在这里插入图片描述

Animation Created and Edited Within Unity
选中某个Animation Clip,然后打开Animation页面,即可编辑对应的Animation Clip,单独打开Animation创建,也可以创建想要的Animation Clip,由于Animation Clip本质上记录的是随时间的变化,物体属性的变化,这里的属性具体有:

  • 物体的Transform:position、rotation和scale
  • Component的属性:比如material的颜色、光照强度、声音大小等
  • Properties within your own scripts:比如float、int等属性的变化
  • The timing of calling functions within your own scripts:脚本调用函数的时间(这里具体应该还是脚本改动了属性,从而实现什么效果)

如下图所示,展示了Animation的Windows下面的光照变换动画:
在这里插入图片描述

Animation from external sources
对于外部导入的Animation Clip,有两种类型的格式,一种是动画通用的.fbx格式,另一种就是美术软件自己的native格式了(比如Maya, Cinema4D, 3DMax, blender),这些格式的文件 can contain animation data in the form of a linear recording of the movements of objects within the file.

关于动画Data,有以下几点:

  • 有的动画资源里只有Animation Clip,没有模型资源,而有的资源,比如说.fbx资源,可以把Model和对应的动画都塞到一个.fbx文件里面
  • 有的动画资源不可复用,只针对于特定的model,尤其是那些非人型的动画(比如一个章鱼)
  • 对于一个动画的库文件,往往会提供一个简单的人物模型,然后提供一堆动画,这个模型可以用于帮助预览
  • 有时一个动画文件会对应一个timeline的多个动画,Unity提供了切分的方式,可把它分割为多个Animation Clip(For example, a long motion captured timeline might contain the animation for a few different jump motions, and you may want to cut out certain sections of this to use as individual clips and discard the rest. Unity provides animation cutting tools to achieve this when you import all animations in one timeline by allowing you to select the frame range for each clip.)

Importing animation files
Unity使用animation资源之前需要Import进来,前面提到的资源都可以正常import进来,不过.blender的文件的import好像需要本地安装blender软件(Importing from .blend files requires a local installation of Blender™).

Viewing and copying data from imported animation files
在Animation Window里用于编辑和创建Animation Clip,这里也就是我理解的k帧界面,在这里可以添加和调整关键帧,对于有骨骼的人物动画而言,其k帧界面可能会很复杂,如下图示是一个run动画的人物的AnimationClip的界面:
在这里插入图片描述
为了不让k帧界面特别复杂,只选中特定的部位,就可以只看这些部位的动画相关属性的信息,如下图所示:
在这里插入图片描述

注意,默认的Unity里导入的AnimationClip的在Animation窗口里的数据是read-only的,要想修改其数据,需要自己创建一个空的Animation Clip,再在Animation窗口里把original的Data复制粘贴过去(这样做估计是为了防止导入的数据被误修改,同时也方便继续使用原本的动画资源),如下图所示:
在这里插入图片描述

Humanoid Avatars
Unity的Avatar系统,相当于人物模型的动画模板,通过Unity的Avatar System可以将人形A的动画映射到人形B上,这里面可以使用retargeting和IK

二. Animation Window Guide

Unity的Animation创建是用来创建和编辑AnimationClip的,在这里面除了可以编辑动画,还可以添加Animation Event,在事件里面改变相应的参数。

The Animation Window in Unity allows you to create and modify Animation Clips directly inside Unity. It is designed to act as a powerful and straightforward alternative to external 3D animation programs. In addition to animating movement, the editor also allows you to animate variables of materials and components and augment your Animation Clips with Animation Events, functions that are called at specified points along the timeline.

2.1 Using the Animation view
The Animation window is linked with with the Hierarchy window, the Project window, the Scene view, and the Inspector window.当在Scene里选中特点的GameObject的时候,Animation Window会自动显示其timeline和关键帧数据,当在Project窗口下选择特定的AnimationClip.asset时,同样也会这样

2.1.1 Animation窗口布局介绍
如下图所示,Scene场景下点击了RobotArm物体,如果该物体的子物件也会被此动画控制,那么子物件也会以hierarchy的形式表示出来,
在这里插入图片描述

When animating a hierarchy of GameObjects within a single clip like this, make sure you create the Animation on the root GameObject in the hierarchy.

Each property can be folded and unfolded to reveal the exact values recorded at each keyframe. 在Animation窗口里面,不仅物体的子物体会展示在Hierarchy里面,一些属性也会以Hierarchy的形式存在,如下图所示,一个rotation分为了三个部分,rotation本身是一个property,property也是可以进行折叠和展开的,不过这里好像只有关键帧才能展开:
在这里插入图片描述

在timeline界面,可以点击上方蓝色的timeline指定白色竖线的位置,用于指定当前编辑的帧的数据,如下图所示,还可以选中一个关键帧之间的过渡帧,自行在左边修改数据,改完后,会出现白色的菱形图案,会自动添加新的关键帧数据(这里好像是只要改动任何数据,最上面就会多一个菱形用于标识,然后下面改动的相同的一行也会出现一个菱形):
在这里插入图片描述

2.1.2 The Animation Timeline
关于动画窗口的timeline,有两种模式,Dopesheet and Curves,如下图所示:
**加粗样式**
这两种模式,用了不同的方式来展示timeline和关键帧数据,Dopesheet就是之前看到的timeline的展示窗口,它从左到右代表着时间线,时间线的每一小格代表一帧,而竖直方向的每一项,都代表一个Property,然后横向会把其关键帧对应的数据展示出来,中间就自行插值处理。

而Curve模式下,水平仍然是时间线,不过竖直方向变成了每一个property对应的值随着时间的变化起伏图,如下图所示,所有选中的property都会在timeline中显示,这种方式能很好的浏览一个property随着时间走向的变化情况,同时看清楚在关键帧中的property插值情况:
在这里插入图片描述

注意,由于不同的property的单位和数值范围也不一样,而在Curve模式下,不同property的y轴值是统一的,举个例子,有一个旋转向上跳跃的cube的AnimationClip,其高度可能从0到2,代表position.y从0m到了2m,但是其rotation的x可能从0旋转到了360,那么也就是说一个property的变化范围是0-2,而另一个是0-360,所以在y轴跨度为0-360时,这个位移的0-2的变化,看上去像一条没有变化的直线,如下图所
示:
在这里插入图片描述
当混合时,难以辨别出特定的曲线的时候,可以放置好白色竖线在想看的帧的位置,再按F,此时曲线的刻度会自动标记到适合选中的property的程度(这里的Curve图本身也支持拖拽和缩放),如下图所示:
在这里插入图片描述

Press A on the keyboard to fit and re-scale the window to show all the keyframes in the clip, regardless of which ones are selected. This is useful if you want to view the whole timeline while preserving your current selection
这里提到按A可以合理的展示一个AnimationClip里所有的keyframe的property对应的曲线,不过我用的版本好像没有这个功能(2018.2.0f试验的按F和按A好像是一样的效果)

2.1.3 Playback and frame navigation controls
这里提供了一些UI,用于帮助编辑和预览AnimationClip:在这里插入图片描述
从左到右依次是:

  • Preview mode (toggle on/off) 是否开启预览模式
  • Record mode (toggle on/off) Note: Preview mode is always on if record mode is on
  • Move playback head to the beginning of the clip:点击后会把白色线(这里叫playback head)移到timeline的最左边
  • Move playback head to the previous keyframe::点击后会把白色线(这里叫playback head)移到上一帧
  • Play Animation:播放Animation Clip
  • Move playback head to the next keyframe:同上
  • Move playback head to the end of the clip:同上

看了一下,当我选中特定的keyframe时,如果选中Preview,那么角色也会显示对应的keyframe的动作,就算我关闭了preview,选中特定keyframe,preview栏会自动开启,然后展示对应的动作,唯一一眼看不出来的就是这个record mode,record mode是用于帮助animating GameObjects的,后面会提到

这里提供了四个快捷键:

  • 移到上一帧:,
  • 移到下一帧:.
  • 移到上一个关键帧:Alt + ,
  • 移到下一个关键字:Alt + .

2.1.4 Locking the window
Unity的Window应该都有这个功能,右上角有一个小锁,点击后对应的AnimationWindow会一直显示当前AnimationClip的信息


2.2 Creating a new Animation Clip
Animation Clip本质上是在一段时间内对不同的property的记录,在Unity里,GameObject是场景里存储Property的载体,所以创建Animation Clip的时候,需要选中一个GameObject,再打开Animation窗口,如下图所示,在Scene下面创建了一个Cube,选中后打开Animation窗口:
在这里插入图片描述

点击上图所示的Create后,Unity会蹦出来一个窗口,让你存储对应的AnimationClip文件,文件后缀为.anim,如下图所示:
在这里插入图片描述
输入自定义的名字后保存就可以了,这一段操作,Unity会为我们做以下事情:

  • 建立一个新的Animation Controller Asset
  • 把在这里创建的AnimationClip作为创建的Controller的默认State
  • 会为这里选中的Cube添加Animator组件,并把前面的Controller赋给Animator组件

也就是说,为GameObject创建空的AnimationClip的时候,系统会默认赠送一个Animator组件和动画状态机。

2.2.1 Adding another Animation Clip
一个GameObject可以挂载多个AnimationClip,都会挂载在如下图所示的Column里面,点击Create New Clip可以创建新的动画clip,如下图所示:
在这里插入图片描述

2.2.2 How it fits together
这里主要是梳理一下AnimationClip、Animation Controller、Animator Component和GameObject的关系

Animation Clip记录的是GameObject身上的属性随时间变化的一段波动的数据,Animation Controller是动画状态机,会存储至少一个AnimationClip(存储的引用),而Animator Component是一个组件,这个组件存储了动画状态机的引用,Animator会被挂载在GameObject上,其关系如下图所示:
在这里插入图片描述

如下图所示,是此次创建多出来的内容:一个后缀为.controller的animator controller文件和一个后缀为.anim的Animation Clip文件
在这里插入图片描述


2.3 Animating a GameObject
有两种在Animation窗口下制作动画的模式:Record ModePreview Mode

Record Mode(Also referred to as auto-key mode),从名字可以看出来,这种模式下创建的动画,其关键帧数据是Unity自行添加的,其思路是,在Record状态下,一旦物体的对应的property发生了改变,那么该物体对应的property稳定下来时(我理解的是短时间内不变时),就会自动为其添加关键帧数据,在Record Mode下,Timeline是红色的,如下图所示:
在这里插入图片描述

举个简单的例子,按下红色的录制按钮,然后在Scene视角下,拖动GameObject沿X轴平移一段距离,然后再按一下红色按钮终止录制,就能得到GameObject的一段沿x轴平移的动画。

In record mode, Unity automatically creates keyframes at the playback head when you move, rotate, or otherwise modify any animatable property on your animated GameObject. Press the button with the red circle to enable record mode. The Animation window time line is tinted red when in record mode.

Preview Mode 这种模式与Record Mode的核心区别就是,这种模式下,关键帧都是自行手动创建的,在Preview Mode下,Timeline是蓝色的,如下图所示:
在这里插入图片描述

2.3.1 Recording Keyframes
前面提到了,按下红色的record按钮,就会把changes to gameobject记录到Animation Clip里,如下图所示是一个用record mode记录光源变化的动画,可以看到,这些会被记录到Animation Clip里的光源的property也都是红色的,在Record Mode下,在Inspector里直接调整参数也可以自动创建出关键帧数据(This applies to any animatable property in the inspector, including numeric values, checkboxes, colours, and most other values):
在这里插入图片描述

通过Add Property界面可以选择对物体的哪些Property进行Animate:
在这里插入图片描述

2.3.2 Timeline
Timeline上方的数字,前面的代表秒数,后面的代表帧数,比如1:05代表了1s后的第五帧,如下图所示,timeline上方的白针代表一帧:
在这里插入图片描述

2.3.3 Creating keyframes in preview mode
通过点击timeline上方的白针可以定位到具体的帧,然后更改对应的数据,此时的数据会变为红色,这里的红色代表数据还未被保存进Animation Clip,如下图所示:
在这里插入图片描述

为了保存这一帧的数据,需要创建对应的关键帧保存。

2.3.4 Preview mode下创建关键帧数据
基于上面的步骤,有三种方法可以创建关键帧,保存红色区域的数据:

  • 直接在Inspector这里右键选择Add Key
  • 在Animation Window里点击Add Key对应的logo
  • 使用快捷键K或shift+K,K是把当前所有在AnimationWindow里的Property全记录下来,而shift +K是只记录修改的property

如下图所示:
在这里插入图片描述

在这里插入图片描述


2.4 Using Animation Curves

2.4.1The Property List
如果说AnimationClip记录的是物体多个property随时间而变化的具体数据,那么Animation Curve就是记录的物体一个property随时间变化的曲线。(能否把AnimationClip理解为物体多个Property的Animation Curve的组合呢?)

2.4.2 Understanding Curves, Keys and Keyframes
Property的Curve曲线是根据Key值得到的,这里的Key值对应在Curve上就是一个小的菱形,如下图所示:
在这里插入图片描述

2.4.3 Adding and Moving Keyframes
这里主要是在CurveMode下添加关键帧的操作,可以选中多个Curve,点击添加帧按钮或右键AddKey,即可在白色竖线对应的帧处添加关键帧数据,也就是会多菱形的点,这些点可以在竖直方向上进行拖拽调整数值。

2.4.4 Supported Animatable Properties
这里只提最基本的primitives,因为复杂的property都可以由这些内容组成:

  • Color
  • Float
  • Vector2
  • Vector3
  • Vector4
  • Quaternion
  • Boolean

基于上述可以被Animate的property,可以利用Animation Window进行如下操作:

  • 灯光闪烁、跳动的动画:Animate the Color and Intensity of a Light to make it blink, flicker, or pulsate.
  • 声音音调不断变化的音频,比如风声:Animate the Pitch and Volume of a looping Audio Source to bring life to blowing wind, running engines, or flowing water while keeping the sizes of the sound assets to a minimum.
  • Animate the Texture Offset of a Material to simulate moving belts or tracks, flowing water, or special effects.
  • Animate the Emit state and Velocities of multiple Ellipsoid Particle Emitters to create spectacular fireworks or fountain displays.
  • Animate variables of your own script components to make things behave differently over time.

2.4.5 Rotation Interpolation Types
Unity内部是用四元数存储和处理旋转变换的,由于Unity的AnimationWindow会自动对关键帧之间的数据进行插值,而旋转可以用欧拉角表示,也可以用四元数表示,所以这里可以指定rotation插值的方式,为Euler Angles还是Quaternion,需要注意的是,不管具体插值用的欧拉角还是四元数的方式,具体绘制出来的时候还是显示欧拉角的变化(因为四元数的数值并不直观),如下图所示(不过为什么这里有两个Euler Angles?):
在这里插入图片描述

2.4.6 Quaternion Interpolation
四元数能为旋转提供很好的插值效果,也不会像欧拉旋转那样出现万向锁,但四元数不可以表示值大于180°的旋转,因为它相当于总是在球面上寻找最近的旋转路线。

Quaternion interpolation always generates smooth changes in rotation along the shortest path between two rotations. This avoids rotation interpolation artifacts such as Gimbal Lock. However, Quaternion interpolation cannot represent rotations larger than 180 degrees, due to its behaviour of always finding the shortest path. (You can picture this by picking two points on the surface of a sphere - the shortest line between them will never be more than half-way around the sphere).

所以当角度大于180°时,虽然图中绘制的是大于180°的变化,但实际上是按四元数的最短路线算的,如下图所示,从290°到0°的插值Curve(实际上应该是290°到360°的变化,对应的黄色曲线,不过实际的Editor里,只会出现紫红色的Curve):
在这里插入图片描述

2.4.7 Euler Angles Interpolation
人们实际工作的时候,更多的是用欧拉角插值的方法,因为这样更直观,但实际上的运算还是交给了四元数去做的(When Euler Angles interpolation is used, Unity internally bakes the curves into the Quaternion representation used internally),Note that this curve baking may add extra keys in the process and that tangents with the Constant tangent type may not be completely precise at a sub-frame level.


2.5 Editing Curves
Unity里大概有四个地方会用到Curve和其编辑的界面:

  • Animation Window:也就是Curve Mode下展示Property的曲线
  • Script components can have member variables of type Animation Curve ,脚本组件里面可以定义Animation Curve,可以在对应的编辑器里调整Curve,如下所示:
public class Test : MonoBehaviour {
    public AnimationCurve cur;
	// Use this for initialization

在这里插入图片描述
在这里插入图片描述

  • Audio Source组件:
    21

  • Paricle System,用于调整粒子随时间的property变化:
    在这里插入图片描述

2.5.1 给Curve添加关键帧数据的操作
双击曲线在该帧对应的点,或者右键AddKey都可以添加关键帧的点,添加之后就可以自行拖动调整数据了,这里还提供了框选多个key点、按ctrl和shift多选key点等常规的图线编辑操作。另外的一些放大缩小试图、按F合适比例显示Curve就不多说了。

2.5.2 Editing Tangents
关键帧对应的property在Curve上以一个点的形式存在,这个点就相当于曲线上的拐点,该点有两个方向的曲线,一条是左边的进切线,一条是右边的出切线,如下图所示:
在这里插入图片描述

这里的切线类型有五种:

  • Clamped Auto:默认的关键帧的切线的类型,会自动调整关键帧的点的切线,使得整个Curve是smooth的
  • Auto:老版的Unity的Legacy的动画的切线类型,留着主要是为了兼容老的工程
  • Free Smooth:可以随意定义关键帧处的切线的方向,为了保证smooth,左切线和右切线共线
  • Flat:关键帧处的切线方向都是水平的
  • Broken:只有这种类型下,曲线在关键帧对应的点处是不平滑的,也就是左切线可以跟右切线方向不同

补充一下Auto类型相较于Clamped Auto的区别:

  • The tangents do not adjust automatically when the key’s position or time is edited; they only adjust when initially setting the key to this mode.(修改key数据时不会自动smooth)
  • When Unity calculates the tangent, it does not take into account avoiding “overshoot” of the target value of the key.

Broken还能细分为Free、Linear和Constant三种类型,分别如下图所示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.6 Key manipulation in Dopesheet mode
主要提到的是窗口中对Dopesheet模式的关键帧数据的编辑操作,主要是:

  • 支持框选多个关键帧数据
  • 支持以帧为单位移动单个或多个关键帧数据(有两种选择,一种是只移动选中的关键帧,另外的一种会移动其他帧(Ripple Edit),比如选中的关键帧往右移2帧,那么右边所有的其他帧也向右移2帧
  • 当选中多帧的数据时,支持拖拽实现这一区间关键帧的缩放

2.7 Key manipulation in Curve mode
主要提到的是窗口中对Curve模式的关键帧数据的编辑操作,主要是:

  • 同样支持框选多个关键帧数据
  • 同样支持移动关键帧数据(也有Ripple Edit的方法)
  • 同样支持数据的缩放,不过这里可以对x和y轴分别进行缩放(而Dopesheet模式下没有y轴这个概念)
  • 由于Curve模式下支持XY两个方向的缩放,为了方便编辑,额外提供了Manipulation Bar这个东西,如下图所示:
    在这里插入图片描述

2.8 Objects with Multiple Moving Parts
当一个GameObject,其本身和其child对应的GameObject都需要被Animate的时候,往往是在Parent的GameObject上制作对应的Animation窗口的动画(特殊情况下可能也会对child添加Animation Clip),如下图所示,三角型可以展开其child:
在这里插入图片描述

2.10 Using Animation Events
如果需要动画播放到某个特定的点,触发脚本的逻辑,比如说实现人物脚部落在地面时播放脚部音效,则需要在特定的AnimationClip里添加事件,由这个事件会触发一个函数,而这个函数只能接受0个或1个参数,参数的类型只可以为:floatstringintobject reference和Animation Event object,如下图所示是在Animation Clip里添加Animation Event的操作:
在这里插入图片描述

当点击添加的Animation Event的时候,会在Inspector出现一些参数(不过我看2018.2f只能看到函数名的enum,最多也只能设定一个参数,看不到这么多参数),可以把要调用的函数名和参数值填进去,如下图所示:
在这里插入图片描述

当鼠标点击对应的Event的时候,会自动显示出调用的函数名,同样,这里的Animation Event也支持多选操作

注意,这里AnimationEvent具体能调用哪些函数,需要说明,也就是说,它的函数来自哪里?
调用的函数需要满足以下几点:

  • 该函数需要在自定义的脚本Component里面,而且这个Component需要和Animator挂在同一个GameObject上
  • 函数的返回类型需要是public void类型,而且不能为Start、Update这样的特殊函数
  • 函数的参数个数为0或1
  • the supported types for the parameter are int, float, string, bool or UnityEngine.Object(应该还有Animation Event object)

如下所示是我做的实验,Test1被挂在Cube上,然后这是基于Cube的Animation Clip,版本是Unity2018.2.0f,脚本是:

using UnityEngine;
public class Test : MonoBehaviour {
	// Use this for initialization
	public void Start () {
        Debug.Log(1);
	}

    public void Start1()
    {
        Debug.Log(1);
    }
}

下图显示只能选择到Start1,不可以选择到Start函数,注意这里一帧可以加好多个Event,有点意思:
在这里插入图片描述



Animation Controllers

Unity提供的动画状态机系统,存储了里面用到的Animation Clip的reference

一. The Animator Controller Asset
Unity的状态机文件,后缀为.controller,对应的窗口叫Animator Window,Animator Controller一般是放在Animator组件里,挂载在GameObject上实现动画效果的.

二. The Animator Window
此窗口用于编辑Animator Controller,默认布局如下,窗口由一个参数Panel和状态机的layout构成,左边的eye icon用于隐藏参数panel:
在这里插入图片描述
关于左边的参数Panel,其中的Layer很重要,不同的动画Layer可以在同一时间按照各自的权重进行混合,也可以方便动画状态的分类和整理,比如把地面的状态机作为Ground Layer,然后制作攻击Layer,攻击的时候把攻击Layer的权重拉到1,Ground Layer权重拉到0。再比如说,有一个Ground Layer负责行走,一个UpperBody Layer负责人物上半身动画,比如现在有一个原地招手的动画,那么对于两个Layer,前者使用屏蔽人物上半身动画的AvatarMask,后者使用屏蔽人物下半身动画的AvatarMask,再把两个Layer混合,就可以得到人物边走边招手的混合动画,如下图所示(此时两个Layer权重都是1):
在这里插入图片描述

三. Animation State Machines
前面提到的Animator下窗口的流程图的layout就是这里的动画状态机

3.1 State Machine Basics
游戏里的人物,经常处于不同的动作,比如idle,比如攻击,比如奔跑,这些动作就叫states,而这些state之间的播放是有逻辑的,下图所示是一个简单的人物动作的状态机逻辑:
在这里插入图片描述

3.2 Animation Parameters
这里的参数只有四类:bool、trigger、int和float,其中参数可以用Animation Curve和脚本来控制,脚本控制的方法的Get到对应的Animator,然后使用Animator对应的接口SetFloat, SetInteger, SetBool, SetTrigger and ResetTrigger,代码如下:

using UnityEngine;
using System.Collections;

public class SimplePlayer : MonoBehaviour {
    Animator animator;
    // Use this for initialization
    void Start () {
        animator = GetComponent<Animator>();
    }
    
    // Update is called once per frame
    void Update () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        bool fire = Input.GetButtonDown("Fire1");

        animator.SetFloat("Forward",v);
        animator.SetFloat("Strafe",h);
        animator.SetBool("Fire", fire);
    }

    void OnCollisionEnter(Collision col) {
        if (col.gameObject.CompareTag("Enemy"))
        {
            animator.SetTrigger("Die");
        }
    }
}

3.3 State Machine Transitions
每个状态机都默认有Entry和Exit两个节点,相当于流程图的起点和终点:
在这里插入图片描述
这里除了state machine,还有sub-state machine,状态机与状态机的转态与state与state的转态的设置方法差不多,后面会再提到sub-state machine。

3.4 State Machine Behaviour
Unity里设置了MonoBehaviour,作为脚本的基类,继承该脚本的脚本都可以作为组件挂在GameObject上面,在这里同样有一个类似的东西,叫做State Machine Behaviour,不过它挂载的对象是一个State Machine里的一个具体的state,如下图所示:
在这里插入图片描述
这个类里面也有一些函数,不过是在进入这个State、退出这个state和Update这个state的时候调用的,具体的可用函数如下(后面两个接口不太熟,以后再研究):

using UnityEngine;

// State Machine Behaviour scripts have access to a number of events that are called when the Animator enters, updates and exits 
// different states (or sub-state machines). There are also events which allow you to handle the Root motion and Inverse Kinematics calls.
public class AttackBehaviour : StateMachineBehaviour
{
    public GameObject particle;
    public float radius;
    public float power;

    protected GameObject clone;
    // Called on the first Update frame when a state machine evaluate this state.
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        clone = Instantiate(particle, animator.rootPosition, Quaternion.identity) as GameObject;
        Rigidbody rb = clone.GetComponent<Rigidbody>();
        rb.AddExplosionForce(power, animator.rootPosition, radius, 3.0f);
    }
	// Called on the last update frame when a state machine evaluate this state.
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        Destroy(clone);
    }
	// Called at each Update frame except for the first and last frame.
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        Debug.Log("On Attack Update ");
    }
	// Called right after MonoBehaviour.OnAnimatorMove.
    override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        Debug.Log("On Attack Move ");
    }
    
	// Called right after MonoBehaviour.OnAnimatorIK.
    override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        Debug.Log("On Attack IK ");
    }
}

具体的用途可能有这些:

  • 当进入或离开state时处理对应的逻辑,比如播放音效,处理数值
  • Perform certain tests (eg, ground detection) only when in appropriate states
  • Activate and control special effects associated with specific states(播放特效,比如攻击时加帅气的特效)

3.5 Sub-State Machines
这东西主要还是为了方便动画状态机的Layout布局,比如说有一个花样射击的动作,蹲下,举枪射击,再站起来,这一个动作由三个片段组成,那就可以把这三个动画放在一个叫做Trickshot的sub-state machine里,如下图所示,注意sub-state machine的形状不是圆角矩形,两边是三角形:
在这里插入图片描述
在这里插入图片描述

缺点也比较明显,当转态到一个sub-state machine的时候,需要明确转态到里面的哪个一个state,而这些东西从外部看上去是很不直观的:
在这里插入图片描述

3.6 Animation Layers
前面也提到了,主要是为了结合AvatarMask,实现人物不同的部位播放不同Layer的动画的效果。

关于Blending Type,Override means information from other layers will be ignored, while Additive means that the animation will be added on top of previous layers. 另外,这里在挂了起作用的AvatarMask的地方加了个M字母,如下图所示:
在这里插入图片描述

关于Synce,Synce是同步的意思,当在Layer的设置里勾选Sync时,会出现一个下拉菜单展示其他的Source Layer,如下图所示:
在这里插入图片描述
Synce是目的是实现动画状态机的复用,举个例子,我有一个Base Layer,可以实现idle、走、跑、跳和攻击等正常动画,然后我想加一个Layer,叫做WoundedLayer,这个Layer是角色受伤时候的Layer,它与Base Layer相比,只有在idle和走的动画的时候,会捂着肚子,从而表现一个受伤的动画,也就是说,Wounded Layer相较于Base Layer,只更改了idle和walk的动画,其他的动画和处理逻辑是不变的。

You can click the Sync checkbox on one of your layers, and then select the layer you want to sync with. The state machine structure will then be the same, but the actual animation clips used by the states will be distinct.

也就是说,这里的WoundedLayer的状态机,也就是layout,其实就是Source Layer的状态机的Layout,只是这里面记录的state不一样而已,如果在WoundedLayer里改变状态机的布局与逻辑(eg, adding/deleting states or transitions) ,那么SourceLayer的状态机布局一样会改。The only changes that are unique to the synced layer are the selected animations used within each state.

关于Timing,只有开启Sync时,才可以勾选Timing选项,这个选项跟两个相同layout的状态机的layer的相同动画的播放时长不同有关,还是拿上面的SourceLayer和WoundedLayer举例,受伤时播放的动画与正常状态播放的动画,很可能长度不一样。

如果没有勾选Timing,If Timing is unselected then animations on the synced layer will be adjusted. 动画的长度会被拉到与原本Layer的动画相同的长度(The adjustment will be stretched to the length of the animation on the original layer)。
如果勾选Timing,则会根据权重调整动画的长度,If the option is selected the animation length will be a balance for both animations, based on weight.

结论是,不管是否勾选Timing,动画状态机都会自动调整动画的长度,如果没勾选,那么Source Layer不改,Synced Layer基于Source Layer改,如果勾选了,那么会基于权重对两个的长度都进行调整。(In both cases (chosen and not chosen) the animator adjusts the length of the animations. If not chosen then the original layer is the sole master. If chosen, it is then a compromise.)

如下图所示,左边的字母S代表这是一个Synced Layer
在这里插入图片描述

3.7 Solo and Mute functionality
Solo和Mute是用于形容动画States之间的转态的,点击这些带箭头的线,可以看一个转态的属性,如下图所示,solo相当于enabled,mute相当于禁用:
在这里插入图片描述
点击state也可以看对应的所有转态的属性,如下图所示,solo代表可以走的transition,用绿色箭头表示,mute代表不可以走的transition,用红色箭头表示:
在这里插入图片描述
在这里插入图片描述

3.8 Target Matching
在游戏里面常常会有这样的问题,比如说一段动画的位移是固定的,然而实际上人物的跳跃动画可能需要调整其跳跃的距离,比如说从A点跳到B点,给一个人物的向前跳的动画,如何精准的控制,使人物从A点起跳,正好在B点落地?

这里需要两个条件:

  • 在跳跃的动画里,人物起跳的时间点和人物脚落地的时间点(时间要用normalized表示)
  • 调用Unity的Animator组件下的MatchTarget函数

假设已经知道起跳的时间点是0.141f,落地是0.78f,那么脚本可以这么写:

using UnityEngine;
using System;

// 确保挂载了Animator组件,有这个header时,就算本身没有Animator组件,添加此component时也会附赠一个Animator
[RequireComponent(typeof(Animator))]
public class TargetCtrl : MonoBehaviour {
    protected Animator animator;    
  
    //the platform object in the scene
    public Transform jumpTarget = null; 
    void Start () {
        animator = GetComponent<Animator>();
    }
    
    void Update () {
        if(animator) {
            if(Input.GetButton("Fire1"))         
            	// 输入落地点的位置和方向,标记为左脚先落地
            	// Bear in mind that the result of using MatchTarget will generally only make sense if it is called at the right point in gameplay.
                animator.MatchTarget(jumpTarget.position, jumpTarget.rotation, AvatarTarget.LeftFoot, 
                                                       new MatchTargetWeightMask(Vector3.one, 1f), 0.141f, 0.78f);
        }       
    }
}

3.9 Inverse Kinematics
绝大多数的动画都是将关节旋转到特定的角度组成的,旋转关节的时候会带动所有的子骨骼部位进行运动,这叫做forward kinematics,也就是从父节点的运动正推到子节点的运动上,反过来,根据点判断各个关节的位置,就是反向动力学IK。一般用于,让角色触摸某个物体,或者把人物放置在一个不平整的地面,让其足部自动匹配地面。

Inverse Kinematics (IK) is supported in Mecanim for any humanoid character with a correctly configured Avatar.

下面看看如何实现角色伸手抓住一个物体的效果:

  1. 首先需要一个具有valid avatart的角色

  2. 为这个角色创建一个Animator Controller,里面放入至少一个AnimationClip,比如Idle动画,然后需要在对应的Layer里勾选IK Pass,如下图所示:
    在这里插入图片描述

  3. 然后把角色拖拽到Scene下面,挂载一个Animator组件,把前面创建的Animator Controller和avatar指派进去,如下图所示:
    在这里插入图片描述

  4. 具体到IK的设置,就需要调用到Animator里面提供的关于IK的函数了,可以在角色上添加自己创建的脚本组件,代码如下:

using UnityEngine;
using System;
using System.Collections;

[RequireComponent(typeof(Animator))] 
public class IKControl : MonoBehaviour {
    protected Animator animator;
    public bool ikActive = false;
    public Transform rightHandObj = null;// rightHandObj用于调整右手,使得右手抓取传入的obj
    public Transform lookObj = null;// lookObj用于调整头部的IK,使得人物看向传入的obj

    void Start () 
    {
        animator = GetComponent<Animator>();
    }
    
    //a callback for calculating IK, 应该只能叫这个名字
    void OnAnimatorIK()
    {
        if(animator) {
            //if the IK is active, set the position and rotation directly to the goal. 
            if(ikActive) {
                // Set the look target position, if one has been assigned
                if(lookObj != null) {
                    animator.SetLookAtWeight(1);// 这是干什么用的?
                    animator.SetLookAtPosition(lookObj.position);
                }    

                // Set the right hand target position and rotation, if one has been assigned
                if(rightHandObj != null) {
                    animator.SetIKPositionWeight(AvatarIKGoal.RightHand,1);
                    animator.SetIKRotationWeight(AvatarIKGoal.RightHand,1);  
                    animator.SetIKPosition(AvatarIKGoal.RightHand,rightHandObj.position);
                    animator.SetIKRotation(AvatarIKGoal.RightHand,rightHandObj.rotation);
                }        
            }
            
            //if the IK is not active, set the position and rotation of the hand and head back to the original position
            else {          
                animator.SetIKPositionWeight(AvatarIKGoal.RightHand,0);
                animator.SetIKRotationWeight(AvatarIKGoal.RightHand,0); 
                animator.SetLookAtWeight(0);
            }
        }
    }    
}

然后设置两个GameObject,一个作为触摸对象,一个作为LookAt对象,就可以出现如下图所示的效果,人物朝右看,因为LookTarget在右边:
在这里插入图片描述
具体这些API的用法,后面会再提到。

3.10 Root Motion- how it works
相关的内容的理解可以参考知乎的这篇文章:https://zhuanlan.zhihu.com/p/44714595和https://www.cnblogs.com/wantnon/p/5163513.html

Body Transform是身体的重心(mass center)It is used in Mecanim’s retargeting engine and provides the most stable displacement model
其身体朝向Body Orientation是在Avatar T-Pose姿势下,基于角色上半身和下半身的方向的总和

模型的Body Transform和BodyOrientation是以World Space Curve的形式存储在AnimationClip的数据里的,其他的组件存储的都是LocalTransform(Everything else: muscle curves and IK goals (Hands and Feet) are stored relative to the body transform)

Root Transform是物体质心对应的Body Transform在一个水平平面上的投影,至于此水平平面是哪个平面,取决于Based Upon的设置。it is computed at runtime,每一帧里,通过计算Root Tranform的改变,将其应用到角色的位移上,使其移动。At every frame, a change in the Root Transform is computed. This change in transform is then applied to the Game Object to make it move.

Animation Clip Inspector
这里解读一下一个AnimationClip文件在Inspector窗口下显示的内容,窗口下主要有三个内容:Root Transform Rotation, Root Transform Position (Y) 和 Root Transform Position (XZ),这三个是为了帮助控制从Body Transform投影得到Root Transform的过程(let you control the Root Transform projection from the Body Transform),如下图所示:
在这里插入图片描述

For example you can decide if you want the motion Y position to be part of the Root Motion (trajectory) or part of the pose (body transform), which is known as Baked into Pose.

Root Transform Rotation

  • Bake Into Pose:The orientation will stay on the body transform (or Pose). The Root Orientation will be constant and delta Orientation will be identity. This means that the Game Object will not be rotated at all by that AnimationClip. 就是说这种模式下,物体不会被此AnimationClip的旋转影响
    只有起始帧和结束帧的Root Orientation相近的时候才可以使用此选项,此时会亮绿灯,不然这个旋转衔接不起来,会亮红灯。(Only AnimationClips that have similar start and stop Root Orientation should use this option. You will have a Green Light in the UI
    telling you that an AnimationClip is a good candidate. A suitable candidate would be a straight walk or a run.)

举个例子,什么样的AnimationClip需要勾选Bake Into Pose呢? 比如直行的走路动画或Idle动画,我们都不需要它改变GameObject在Transform里的Rotation,所以需要勾选这一项,而如果这个AnimationClip本身,播放完后其rotation改变了,那么说明这个动画片段是带有旋转动作的,那么就会红灯报警

  • Based Upon: Root Transform Rotation下的Based Upon有两个选项:Original和BodyOrientation,总之是确认RootMotion的方向的基准,如果是Original,则以原动画的正方向为基准,否则以T-pose得到的BodyOrientation为基准

Root Transform Position (Y)
与上面的Rotation相似,不过这里是关注于动画Clip带来的y轴上的位移,绝大多数动画都会使用BakeIntoPose,除非那种上跳的带来位移的动作,

注意, 参数Animator.gravityWeight与播放动画的Bake Into Pose position Y参数有关,当播放动画勾选了Bke Into Pose positionY的时候,gravityWeight = 1,

Note: the Animator.gravityWeight is driven by Bake Into Pose position Y. When enabled, gravityWeight = 1, when disabled = 0. gravityWeight is blended for clips when transitioning between states.

Root Transform Position (XZ)
Bake Into Pose will usually be used for “Idles” where you want to force the delta Position (XZ) to be 0. It will stop the accumulation of small deltas drifting after many evaluations. It can also be used for a Keyframed clip with Based Upon Original to force an authored position that was set by the artist.

Generic Root Motion and Loop Pose
对于Generic类型的动画,如果要看到上面的内容,需要在导入设置里指定其RootBone

This works in essentially the same as Humanoid Root Motion, but instead of using the Body Transform to compute/project a Root Transform, the transform set in Root Node
is used. The Pose (all the bones which transform below the Root Motion bone) is made relative to the Root Transform.

总结RootMotion
主要就是对BakeIntoPose和Based Upon的理解,当勾选BakeIntoPose的时候,代表这个动画的东西会Bake进角色的姿势里面,动作会应用到姿势上,但是不会改变其GameObject的Transform,而不勾选,则会应用其RootMotion的位移,而这个RootMotion的位移是在一个水平面上的,具体是哪个水平面,由BasedUpon决定,如果是Original,那就是动画原本RootMotion的水平面,如果是Center Of Mass,那就是人物重心的水平面,如果是Feet,那就是以脚部为基准的水平面,offset则是基于Based Upon进行微调的选项

按照我的理解,如果不需要动画参与y轴方向上的运动,只需要其水平面的运动,就勾选Bake Into Pose Root Transform Position(Y),只勾选Root Transform Position(XZ),而上跳的动作,则就不勾选其BakeIntoPose Position Y,因为要使用动画带来的y轴上的位移。

Tutorial: Scripting Root Motion for “in-place” humanoid animations
由于RootMotion相对复杂一点,所以这里Manual里面提供了一个小的tutorial。

有的动画是自带root motion位移的,而有的没有做root motion(应该叫Treadmill动画),对于后者,为了实现其RootMotion,可以有很多种方法,这里介绍一种,可以使用脚本实现其RootMotion。

具体步骤如下:

  • 在Project里选中含有对应的In-place动画的fbx文件,在Inpsector里选择Animation Tab.
  • 确认模型的Avatar的Muscle Definition设置的是正确的(Make sure the Muscle Definition is set to the Avatar you intend to control (let’s say this avatar is called Dude, and it has already been added to the Hierarchy View).)
  • 选中对应的AnimationClip
  • 勾选Loop Pose,而且确保后面亮了绿灯,如下图所示:
    在这里插入图片描述
  • 在下面的Curve栏里加一条曲线,用来表示动画向前行进的速度,如下图所示:
    在这里插入图片描述
  • 创建新的Controller,把上面的AnimationClip拖进去,而且要在参数栏里加一个参数,名字要跟前面曲线的名字一模一样(这里应该会曲线应该会自动匹配和修改同名的参数值吧)
    在这里插入图片描述
  • 最后在Runtime用脚本读取状态机里参数的值,作为速度直接调整人物的position就可以了,不过一定要注意在OnAnimatorMove里执行代码(在Update里执行是不是也可以?),代码如下:
using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Animator))]
    
public class RootMotionScript : MonoBehaviour {
            
    void OnAnimatorMove()
    {
            Animator animator = GetComponent<Animator>(); 
                              
            if (animator)
            {
     Vector3 newPosition = transform.position;
               newPosition.z += animator.GetFloat("Runspeed") * Time.deltaTime; 
     transform.position = newPosition;
            }
    }
}

四. Blend Trees
这里要搞清楚动画Transition和动画Blend的区别:Transition是从动画A平滑过渡到动画B,而Blend是根据权重把多个动画混合在一起。Blend的动画之间也有一定的要求,the motions that are blended must be of similar nature and timing。(比如说都在特定的normalized的时间点抬脚)

但二者本质上却是相同的,都是动画的混合,Transition是两个动画的混合,两个动画的权重因子随着时间的变化,一个从0到1,一个从1到0,而Blend则可以有多个动画,而且对动画的同步有一定要求

4.1 Using Blend Trees
比较常用的Blend动画的操作有:根据人物的速度判断人物处于走或跑或idle或其中的混合状态、在人物奔跑拐弯的时候配上人物倾斜的动画,如下图示,展示了随着方向倾斜人物的Blend Tree:
在这里插入图片描述

举个例子,如果要Blend一个Run和Walk的动画,那么它们抬脚和落脚的Timing需要是相同的,这里的Timing是NormalizedTime,所以参与Blend的动画不一定需要同样的长度,但需要是在同样的NormalizedTime,发生同样的行为。

Unity支持1D Blend Tree和2D Blend Tree,2D的支持五个Animation Clip进行混合,如下图所示:
在这里插入图片描述

4.2 Blend Trees and Root Motion
Blend的时候,动画的属性是根据权重进行线性插值的,但Root Motion的插值并不一定是这样插值的,后面会具体提到。

4.3 1D Blending
这里的1D的1是指的参数个数,1D Blending只需要一个参数,来决定是用哪些动画,如下图所示,应该可以加非常多的AnimationClip,每个AnimationClip的蓝色顶峰都可以水平拖拽进行移动,当没有勾选Automate Threshold的时候,可以编辑具体的Threshold的值,比如可以让五个AnimationClip的thresholds分别为-90,-45,0,45,90,而不是原来的0~1:
在这里插入图片描述

关于Compute Thresholds选项:这里会根据动画片段的root motion的信息自动计算其threshold,一共有以下六种类型:

  • Speed
  • Velocity X
  • Velocity Y
  • Velocity Z
  • Angular Speed(Rad)
  • Angular Speed(Deg)
    举个例子,如果有三个不同动画,其root motion的速率分别为每秒1.5 units、每秒2.3 units和每秒3.5 units,那么会自动生成1.5、2.3和3.5的threshold。

关于Adjust Time Scale选项:方便调整各个动画的播放速度的选项,官方文档里没有怎么介绍

4.4 2D Blending
2D Blending这里的2代表着两个参数,Blend Tree的类型可以在Inspector的Blend Type里设置,2D的Blending一共有四种Blend Type:

  • 2D Simple Directional: 一个方向上只能对应一个AnimationClip
  • 2D Freeform Directional: 2D Simple Directional的升级版,一个方向上可以对应多个AnimationClip
  • 2D Freeform Cartsian:Cartsian是笛卡尔的意思,所以这就是一个2D的坐标系,与方向有关,可以自行设计对应的动画Clip
  • Direct:完全让用户自行控制每个节点的权重,一般用于facial shapes or random idle blending

这里解释一下2D Simple Directional,它适用于,单一方向对应单一动画片段,比如走路,X = 1 ,Y = 0就是往前走,X = 0, Y =1就是往左走,但是这里往前只能有一个走的动画,如果要设计X = 0.5, Y = 0 是往前走,X = 1, Y = 0 是往前跑,就不可以用2D Simple Directional,而是得用2D Freeform Directional

The 2D Blending Diagram(图表)
如下图所示,红色的点代表当前参数的值(点击Play可以拖动红点,来看不同位置播放不同动画的情况),灰色点代表没有具体的AnimationClip的点,当拖入具体的动画片段时,点会变为蓝色,当参数X和Y的值吻合任何一个动画片段的坐标时,该动画此刻的权重为1,其他动画都为0
在这里插入图片描述

有意思的是,这个蓝色点的半径大小代表了它对红色点的动画的权重占比程度,如下图所示,红点靠近上方蓝点时,上方的半径更大:
在这里插入图片描述
在这里插入图片描述
仔细看看上面的图会发现它不是一张均匀的蓝色的图,这是因为每个节点的是有一定影响范围的,仔细看看可以发现 ,一般距离蓝色点最近的地方,蓝色也越明显,如下图所示是选中中间点的影响范围:
在这里插入图片描述

下面的Compute Positions也与前面的1D Blending差不多,都是从Root Motion里得到数据来自动生成对应的Thresholds,详情参考https://docs.unity3d.com/Manual/BlendTree-2DBlending.html


4.5 Direct Blending
这种模式下,每一个动画节点的权重值都是自行设置的了,这样可以更精确掌控各个动画的权重值,某种程度上,这里是2D Blending的更高级版,我理解为N D Blending,因为它可以支持更多的参数,而这个参数都是在Parameter窗口里的参数,每一个参数的权重由一个float参数来直接设置,来进行多个动画的Blend,其界面也简单了很多,如下图所示:

在这里插入图片描述

这个一般用于facial shapes or random idle blending,下面是一个面部的例子,Animator的参数窗口里有五个参数,分别对应五个表情:
在这里插入图片描述

4.6 Additional Blend Tree Options
这里解释了Blend Tree里额外的两个选项:Time ScalingMirror,TimeScale提供了控制动画片段播放速度的选项,里面的Adjust Time Scale > Homogeneous Speed可以在所有的Blend的child为AnimationClip而不是Blend Tree时,自动调整所有动画片段的播放速度,从而rescales the speeds of the clips so that they correspond with the chosen minimum and maximum values of the parameter but keep the same relative speeds they initially had.(没理解什么意思),而Mirror选项提供了镜像的动画,而不用占用额外内存


五. Working with Blend Shapes

5.1 Preparing the artwork
一般是在3D美术建模软件里(比如Maya)设置好blend shapes,具体步骤如下:

  1. In your 3D modeling application, enable these export settings:
    Enable exporting animation.
    Enable exporting blend shapes for deformed models.
  2. Export your selection to an FBX file.
  3. Import your FBX file into Unity.
  4. 在Unity选择导入的模型,Inspector里displays the BlendShapes section containing all the blend shapes under the SkinnedMeshRenderer component.
  5. 在列出来一堆BlendShapes里,每一个BlendShape都可以调整其对default blend shape的权重影响,0代表没影响,100代表满影响。

5.2 Create animations In Unity
Unity创建blend animation的步骤如下:

  1. 打开Animation窗口
  2. 在窗口左边,click Add Curve and add a blend shape,The Inspector window displays the new blend shape in the BlendShapes section under the SkinnedMeshRenderer component.

Create the animation you want by adjusting the keyframes
and blend weights.

To preview your animation, click Play in the Editor window or the Animation window.


5.3 Scripting access

  • 提供了BlendShape权重的get和set方法GetBlendShapeWeightSetBlendShapeWeight
  • 可以用blendShapeCount变量知道一个Mesh有多少个blendshape

下面看一个脚本:

// This code example demonstrates how to blend a default shape into two other blend shapes over time when attached to a GameObject
// with three or more blend shapes:
using UnityEngine;
using System.Collections;
 
public class BlendShapeExample : MonoBehaviour
{
    int blendShapeCount;
    SkinnedMeshRenderer skinnedMeshRenderer;
    Mesh skinnedMesh;
    float blendOne = 0f;
    float blendTwo = 0f;
    float blendSpeed = 1f;
    bool blendOneFinished = false;

    void Awake ()
    {
        skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer> ();
        skinnedMesh = GetComponent<SkinnedMeshRenderer> ().sharedMesh;
    }

    void Start ()
    {
        blendShapeCount = skinnedMesh.blendShapeCount; 
    }

    void Update ()
    {
        if (blendShapeCount > 2) {
            if (blendOne < 100f) {
                skinnedMeshRenderer.SetBlendShapeWeight (0, blendOne);
                blendOne += blendSpeed;
            } else {
                blendOneFinished = true;
            }

            if (blendOneFinished == true && blendTwo < 100f) {
                skinnedMeshRenderer.SetBlendShapeWeight (1, blendTwo);
                blendTwo += blendSpeed;
            }
        }
    }
}

六. Animator Override Controllers
这是一种asset文件,可以用来extend原有的Animator Controller,可以把原本的Animator Controller当做基类,然后进行override得到具体的子类动画状态机,原有的Animator Controller和Animator Override Controllers的动画逻辑、参数完全相同,只是里面具体state对应的AnimationClip不同罢了。

这个很有用,举个例子,游戏里面,很多NPC的动画状态机的逻辑是一样的,都是那些Idle动画,攻击和挨打的逻辑也是一样的,唯一不同的就是他们的具体的动画clip不一样,这时候就可以create multiple variants of the same basic state machine, but with each using different sets of animations。

在Project视图下面可以创建Animator Override Controller,其文件后缀为.overrideController,二者的图标也有少许区别,如下图所示:在这里插入图片描述
创建之后,需要指定其base的Controller:
在这里插入图片描述
选中之后,就会出现原本的controller用到的动画片段,在这里可以进行替换:
在这里插入图片描述
在Component组件下,就可以看到显示的是overrideController,感觉这跟代码里的继承非常像:
在这里插入图片描述



Retargeting of Humanoid animations

Unity的动画重定向只支持人物模型,是通过借助Avatar映射原有个骨骼实现的

Recommended Hierarchy structure
当使用Unity的关于人形动画重定向的Mecanim的时候,一般需要以下内容:

  • 导入的人物模型,模型里面包含了Avatar
  • 第二个人物模型,模型里面也有Avatar
  • The Animator Component, referencing an Animator Controller asset.
  • A set of animation clips, referenced from the Animator Controller.
  • 为角色设计的脚本
  • Character-related components, such as the Character Controller

下面主要是介绍了关于重定向的Demo的操作介绍,内容都在https://docs.unity3d.com/Manual/Retargeting.html,就是两个都带Avatar的人形模型,使用同样的Animator Controller,进行相同的动作。



Performance and optimization

内容不多,都在这里https://docs.unity3d.com/Manual/MecanimPeformanceandOptimization.html



Animator Component

如下图所示,前面都已经提过了,需要提及的重点就是后面的Update Mode、Culiing Mode和方框里面的东西:
在这里插入图片描述

关于Update Mode:This allows you to select when the Animator updates, and which timescale it should use.告诉了Animator何时Update,有以下三个选项:

  • Normal:与Update函数同步, and the animator’s speed matches the current timescale. If the timescale is slowed, animations will slow down to match.
  • Animate Physics:与FixedUpdate函数同步(i.e. in lock-step with the physics system),如果动画涉及到物理交互应该用这个(such as characters which can push rigidbody
    objects around)
  • Unscaled Time:与Update函数同步,but the animator’s speed ignores the current timescale and animates at 100% speed regardless,常用于用normal speed模拟GUI动画(This is useful for animating a GUI system at normal speed while using modified timescales for special effects or to pause gameplay)

关于Culling Mode,有三种模式:

  • Always Animate:会一直播放动画,相当于没有Culling
  • Cull Update Transforms:当看不到renderers时,Retarget, IK and write of Transforms are disabled
  • Cull Completely:当看不到renderers时,完全disable动画

关于Animation curve information
下面的方框里可以看到被该Animator Controller控制的clips的信息,而每一个AnimationClip相当于是多个Curve的组成,每一个Curve代表的被Animate的Property,以下是具体是参数解释:

  • Clip Count:很好理解,controller里包含的AnimationClip的数量
  • Curves (Pos, Rot & Scale):关于GameObject的Transform的三个属性的Curve的数量,这个参数一般用于非人类骨骼部分的模拟,当该动画是用于humanoid的模型时,这个属性往往代表着a count for extra non-muscle bones,比如尾巴,或者人物身上漂浮的布料。(If you have a humanoid animation and you notice unexpected non-muscle animation curves, you might have unnecessary animation curves in your animation files.)
  • Muscles:当使用Humanoid模型时,Muscle Animation Curve的数量,这些Curve用于Animate人物avatar的肌肉。( As well as the standard muscle movements for all the humanoid bones in Unity’s standard avatar, this also includes two “muscle curves” which store the root motion position and rotation animation.)
  • Generic:numeric(float)曲线的数量,一般用于Animate像Material Color这样的属性
  • PPtr:sprite animation curves的数量,用于2D
  • Curves Count:所有AnimationCurve的总和
  • Constant:值不变的AnimationCurve的数量
  • Dense:使用dense方法记录Curve数据(discrete values which are interpolated between linearly)的Curve的数量,这种Curve数据占用内存比Stream少
  • Stream:使用Steam方法记录Curve数据(values with time and tangent data for curved interpolation),占用内存比Dense多

PS: If your animation clips are imported with “Anim Compression” set to “Optimal” in the Animation import reference, Unity will use a heuristic algorithm to determine whether it is best to use the dense or stream method to store the data for each curve.



Animator Controller

在Animator窗口中,选中一个或多个Clip,按F,能自动调整到合适的窗口,而如果按A,则可以自动调整到预览所有Clip的合适的窗口。

Animation State
动画状态机的单元是State,它可以是一段AnimationClip,也可以是一个BlendTree,其窗口如下所示:
在这里插入图片描述
主要的参数解释:

  • Motion: The animation clip assigned to this state
  • Foot IK: Should Foot IK be respected for this state. Applicable to humanoid animations. state是否遵守Foot IK
  • Write Defaults:(Whether or not the AnimatorStates writes back the default values for properties that are not animated by its Motion.)
  • Mirror: 是否镜像播放动画,只可以用于Humanoid动画
  • Transitions:The list of transitions originating from this state

Any State
Animator界面里除了默认有一个Entry和Exit外,还有个Any State,Any State is a special state which is always present. It exists for the situation where you want to go to a specific state regardless of which state you are currently in. This is a shorthand way of adding the same outward transition to all states in your machine. Note that the special meaning of Any State implies that it cannot be the end point of a transition (ie, jumping to “any state” cannot be used as a way to pick a random state to enter next).

Any State状态可以代表任意的状态,当我们希望某个条件发生时物体不论在何种状态都转移至另一种状态时可以用到,比如角色死亡,相当于用这个Any State全称其实是If it is at any state,如下图所示,state A是死亡动画,白色的箭头上有角色生命值为0的条件
在这里插入图片描述



Animation FAQ

Mecanim名字的由来
文章最开始介绍了,就不再提了

Import
为什么imported mesh会挂载一个animator组件?

When Unity detectes that an imported file has animation in its timeline, it will add an animation component on import. You can modify this in the asset’s import settings by setting the “Animation Type” to None in the import settings under the Rig tab. If necessary you can do this with several files at once.

Layers

  • Layers的顺序重要吗?

  • Yes. Layers are evaluated from top to bottom in order. Layers set to override will always override the previous layers (based on their mask, if they have a mask).

  • Should the weight value of the base layer always be set to one or should the weight be zero when using another layer?

  • The base layer weight is always 1 and override layers will completely override the base layer.(Base Layer权重始终为1)

  • Is there any way to get a variable value from the controller without using the name string?

  • You can use integers to identify the states and parameters. Use the Animator.StringToHash function to get the integer identifier values. For example:

runState = Animator.StringToHash("Base Layer.Run");
animator.SetBool(runState, false);
  • What happens if a state on a Sync layer has a different length compared to the corresponding state in the base layer?
  • If layers have different lengths then they will become unsynchronized(两个Layer播放时间不同步). Enable the Timing option to force the timing of the states on the current layer, on the source layer.

自己突然想到个问题,感觉Sync Layer和Animator Override Controller很像,二者有啥区别(Remain)?

Avatar Masks

  • Is there a way to create AvatarIKGoals other than LeftFoot, RightFoot, LeftHand, RightHand?

  • Yes, knee and elbow IK is supported.

  • Is there a way to define what transforms are part of the AvatarMask?

  • Yes, for Generic clips you can define which transform animation is imported or not. For Humanoid clips, all human transforms are always imported and extra transforms can de defined.

Animations curves

  • How do animations that have Curves blend with those that don’t?
  • When you have an animation with a curve and another animation without a curve, Unity will use the default value of the parameter connected to the curve to do blending. You can set default values for your parameters, so when blending takes place between a State that has a Curve Parameter and one that does not have one, it will blend between the curve value and the default parameter value. To set a default value for a Parameter, simply set its value in the Animator Tool window while not in LiveLink.


Playables API

这篇文章太长了,单开一篇文章讲一讲Playables API吧,我写的文章在这里

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值