Unity3D 的 Mecanim 动画系统可以直接复用 3DS MAX 中制作的动画文件中的位移,这个就是通过 applyRootMotion 来达成的,我们只需要在使用 Animator 控制动画播放的同时,设置 Animator 的 applyRootMotion 字段为 True 就 OK 了。

那么怎么来利用这个特性达成我们想要的一些效果呢?这个 applyRootMotion 到底指的是啥呢?

ApplyRootMotion,从字面上理解来看,是『应用根节点的运动』,听起来貌似像那么一回事。可是我们可以从官方文档上看到这样一段话:

The Root Transform is a projection on the Y plane of the Body Transform and is computed at runtime. 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.

翻译过来的意思,应该是这样的:

根节点的运动变换其实就是整个物体运动变换通过 Y 轴垂直在水平面上的一个投影。根节点的运动变换在动画的每一帧中都会进行计算。计算出来的根节点变换结果都会应用在播放动画的对象上,让该对象按照根节点的运动变换进行移动。

这段话大体的意思就是,RootMotion 这个玩意就是作用于动画物体在 X 轴和 Z 轴上的位移的,而且这个位移是根据实际播放的动画中每一帧物体的位移在 X 和 Z 轴上投影计算出来的。

这个特性非常赞特别是对于某些技能动画,整个动画是有一定位移的,但是动画的位移是动作设计师在设计时根据动作需要调出来的,位移是跟动作的幅度直接相关和匹配的。

那么在释放技能的时候就只需要直接播放动画,并且应用这个 Root Motion 的特性就可以很好的完成角色在播放攻击动作的同时进行移动,动作播放完毕之后就在动画结束帧角色所在的位置,切换为待机动作就 OK 了。

看起来很牛逼的样子对不对?是的,确实很牛逼。但是还有很多事情需要我们都一一了解以后,我们才能做出我们想要的东西的。

下面我们先岔开一下话题,好好说说这个 Animation Import Settings 中『Animations』Tab 页中各项设置的作用。

  • Import Animation,勾选这个才可以导入动画到 Unity 工程中;
  • Bake Animations,这个选项只在使用 Humanoid 动画并且使用到了 IK 特性的时候才可用;
  • Anim.Compression,这个是关于动画压缩选项的,默认会选择 Keyframe Reduction 这个是『压缩关键帧』,就是 Unity 会自行重采样动画的关键帧,还有两个选项『Off 和 Optimal』,一个是关闭动画压缩,一个是最优化压缩(应该是压缩效率最高,动画效果失真度可能也较高)
  • 选择了 Keyframe Reduction 或者 Optimal 压缩选项,就会有三个用于控制压缩选项的系数配置, Rotation Error,Position Error 和 Scale Error,这个三个参数默认都是 0.5,越小呢精度就越高也就是说动画的失真度越小。
  • Clips,这个下面列出了这个 FBX 文件下包含的所有动画,我们在默认的动画文件基础上新建和删除动画片段 (Animation Clip),当然每个动画片段都是可以指定起始帧和结束帧的; 以下的设置都是针对单个动画片段滴:
    • Loop Time,勾选这个选项之后,如果 Animator 处于播放这个动画状态时,在播放完第一遍这个动画片段之后,会自动循环从起始帧再次开始播放动画,如此循环往复。如果我们不勾选这个选项,例如 Animator 一直处于播放这个动画的状态,那么动画会定格在动画的结束帧,直到我们通过 Animator 切换这个 Animator 状态机的状态,切换到其他的动画;

      • Loop Pose 和 Cycle Offset,在勾选了 Loop Time 之后生效的两个选项,Loop Pose 用于控制动画循环播放时,从结束帧切换到起始帧时,动画的动作可以无缝的衔接上,Cycly Offset 就是用于控制循环的时候起始帧偏移用的;
    • Root Transform Rotation,根节点的旋转信息
      • Bake Into Pose,勾选后会将根节点每一帧的旋转方向信息烘焙到动画的骨骼运动中,在整个动画播放的过程中,根节点的旋转信息就不会在通过 Root Motion 作用到播放该动画的 GameObject 上了,这就意味着这个动画播放的过程中,该物体的 Transform 中的 Rotation 值不会因为动画中物体做了任何旋转而发生改变,而是会保持一个恒定的值,和该动画播放之前的旋转值保持一致;
      • Based Upon (at Start) 或者 Based Upon,根节点旋转的参考基准,有两个选项『Original 和 Root Node Rotation』这两个分别指的是动画文件中指定的旋转值和根节点旋转信息,其实我更愿意将 Original 理解为动画中原点的旋转值,因为在整个动画播放的过程中,所有骨骼肯定都会有旋转和位移的变换,但是动画的原点其实一定都是确定的,这样理解感觉更简单也更形象一些,勾选了 Bake Into Pose 之后,就会变成 Based Upon 而不勾选 Bake Into Pose 就会保持为 Based Upon (at Start),这个目前还木有理解为啥;
      • Offset,旋转角度与参考基准的偏移(以度为单位);
    • Root Transform Position(Y),根节点位移信息(Y 轴)
      • Bake Into Pose,勾选后会将根节点每一帧在垂直 Y 轴方向上的运动信息烘焙到动画的骨骼运动中,在整个动画播放的过程中,根节点在 Y 轴方向的所有位移信息不会通过 Root Motion 作用到播放该动画的 GameObject 上,这就意味着我们在场景中看到物体在 Y 轴上有位移,例如向上或者向下移动,但是该物体的 Transform 中的 Position 信息不会发生改变,会跟动画播放之前的 Position 信息保持一致;
      • Based Upon 或者 Based Upon (at Start),这个貌似有点不一样哦,在选中 Bake Into Pose 之后会变成 Based Upon (at Start),不勾选的时候是 Based Upon,不过这个就能理解了。不烘焙的话,那么 Root Motion 中 Y 轴的变化就依赖于选择的『Original 或者 Root Node Position』的 Y 轴位移变化,如果选择烘焙的话,那么就以这个动画的起始帧的 Y 轴作为整个动画 Root Motion 的 Y 轴位移,在整个动画播放的过程中,Y 轴的位移都是恒定不变的;
      • Offset,垂直方向上的偏移;
    • Root Transform Position(XZ),根节点位移信息(水平面,XZ 轴)
      • Bake Into Pose,勾选后会将根节点每一帧在水平面(X 和 Z 轴)方向上的运动信息烘焙到动画的骨骼运动中,在整个动画播放的过程中,根节点在 X 和 Z 轴方向的所有位移信息不会通过 Root Motion 作用到播放该动画的 GameObject 上,这就意味着我们在场景中看到物体在水平面上移动,但是该物体的 Transform 中的 Position 信息不会发生改变,会跟动画播放之前的 Position 信息保持一致,假如动画中物体会向前移动 3 米,我们会看到物体在整个动画播放过程中确实在向前移动,播放到最后一帧时确实向前移动了 3 米,但是当这个动画播放完毕之后,切换到任何其他的动画时,物体会直接闪回这个动画播放前物体所在的位置,所以通常我们需要保留动作位移的动画都不会勾选这个选项。那这个选项有神马用捏?例如某些待机动画,我们其实希望物体只是做一个待机动作,但是实际上不想让物体在水平方向上有位移,这个时候就可以勾选这个选项了,到时候看起来物体就像是钉在水平面上了;
    • Mask,这个掩码主要是用于控制动画播放过程中,各个骨骼之间的运动变换的
      • Definition,可以选择从动画文件创建也可以选择使用其他动画文件中已经创建好的配置;
      • Transform,这个就是动画文件中所有骨骼的层级关系,可以选择勾选那些需要应用动画中运动变换的骨骼;
    • Curves,这个主要用于设置某些跟动画相关的参数用,例如控制整个动画播放过程中的速度参数之类的,在动画播放的过程中可以通过 Animator.GetFloat(ParamName) 函数来读取曲线的值,曲线的 X 轴为动画的时间轴,Y 轴为曲线的值,曲线可以通过曲线编辑器进行增加关键点,调整曲线斜率进行编辑,读取时默认会根据当前动画播放的进度作为 X 轴的值进行读取,一个动画片段可以有多个曲线;
    • Events,这个是用于在动画播放的过程中触发事件的,例如整个动画中有起跳和落地两个事件需要在准确的时间点触发并通知到游戏中其他的对象,那么就可以在 Events 时间轴上新增事件通知,设置好触发的方法名称和参数,在播放该动画的 GameObject 上确保有某个脚本中有与该事件通知的方法签名一致的方法就好了,当动画播放到触发通知时间时,就会向 GameObject 广播该时间通知,脚本中方法签名一致的方法就会被回调了,那我们就可以做我们需要做的事情了。

说了这么多貌似跟 Root Motion 不是很相关的东西,那么究竟我们今天的主题是啥呢?肯定还是 Root Motion 这货。主要因为动画导入时的设置对于 Root Motion 的应用影响非常直接,所以前面絮絮叨叨地把这个动画导入设置都罗列了一遍。

回到正题,Generic 动画应用 Root Motion 有以下几个特点:

  1. Root Motion 仅仅作用于 GameObject 在 X 和 Z 轴上的位移变换,不影响 Y 轴上的位移。例如现在播放一个从地上向前空翻之后落地的动画,设置 Animator 的 applyRootMotion 为 True,也就是应用 Root Motion,那么动画在播放过程中,物体会在水平方向和垂直方向上都按照实际动画的运动轨迹进行运动,如果将 applyRootMotion 设置为 False,那么我们就只能看到动画在原地起跳然后再落地,动画中原本应有的在水平方向的位移就没有了;
  2. Root Motion 与导入动画时设置 Root Transform Position(XZ) 是直接相关的,如果我们选择了将 X 和 Z 轴方向上根节点的位移烘焙到动画骨骼运动中的话,那么动画播放过程中不论我们是否将 Animator 的 applyRootMotion 设置为 True 还是 False,动画播放过程中物体在 X 和 Z 上的移动是一定的,因为这个已经被烘焙到骨骼动画中,只要动画播放,物体就会移动,但是在动画播放的过程中 GameObject 的 Position 值不会改变,在动画结束后我们切换到其他动画的时候,其他动画开始播放时的 GameObject 的位置会回到这个动画播放前的位置,所以如果我们需要对某个动画应用 Root Motion 的话,那么这个动画在导入的时候就不要烘焙其在 X 和 Z 轴方向上的 Root Transform Position,让 Unity 自行根据动画中根节点的位移进行位移计算 GameObject 的位置信息;
  3. 注意 Root Motion 与 Rigidbody.Velocity 属性的关系,如果有两个动画 A 和 B,播放 A 动画的时候,希望 A 动画应用 Root Motion,而在播放 B 动画的时候不想应用 Root Motion,那么就直接在切换到动画 B 的时候,将 Animator 的 applyRootMotion 设置为 False 就 OK 了。但是如果播放动画的 GameObject 带有 Rigidbody 组件,那么需要注意一点,在播放 A 动画时 Rigidbody 的 Velocity 并不会在切换到 B 动画时清零,也就是说如果 A 动画的运动速度较快,那么切换到 B 动画的时候,如果希望 B 动画播放的时候 GameObject 按照自己的设定轨迹运动,就需要自行手动在切换到 B 动画之前将 Rigidbody 的 Velocity 属性清零,防止 GameObject 按照 A 动画的运动惯性继续运动。这个问题在没有 Rigidbody 组件的 GameObject 上不会存在;

这边再岔开一下,说说这个动画跟 Rigidbody 之间的关系:

  1. 如果我们没有将 Root Transform Position 的 Y 和 XZ 轴进行烘焙的话,那么在动画播放的过程中,Rigidbody 将会自动获得动画中物体运动的速度信息,直接通过 Rigidbody.Velocity 属性就可以获得;
  2. 如果我们将 Y 轴进行烘焙,那么 Rigidbody.Velocity 在 Y 轴上的值将会一直为 0,对于 XZ 轴也是一样的,如果烘焙了 XZ 轴的位移,那么整个动画播放过程中,Rigidbody.Velocity 在 X 和 Z 轴上的值都会为 0;
  3. 如果播放动画的物体没有 Rigidbody 组件,那么动画的运动都会仅仅按照动画实际的位移来进行逐帧播放,不会出现上文中提到的动画播放切换之后还存在的运动惯性问题,因为物理引擎依赖于 Rigidbody 组件,如果没有该组件,所有动画的播放都只是逐帧播放动画,不会存在速度的概念只有移动位移。
  4. Rigidbody 使用使用重力对于动画在 Y 轴上的位移没有任何影响,不论是否对 Root Transform Position 的 Y 轴进行了烘焙。

转自:http://7dot9.com/?p=528

Unity3D 中 Generic 动画导入设置和 Root Motion 之间的关系的更多相关文章

  1. (转)在Unity3D中控制动画播放

    用Unity3D也算是好久了,但是每次做项目总还是能学到新的东西.这次做一个TPS的项目就遇到了这样一个问题,如何同时在上下半身播放不同的动画?解决方法其实是很简单,但由于对于动画资源的了解不足导致问 ...

  2. Linux中的文件描述符与打开文件之间的关系

    Linux中的文件描述符与打开文件之间的关系 导读 内核(kernel)利用文件描述符(file descriptor)来访问文件.文件描述符是非负整数.打开现存文件或新建文件时,内核会返回一个文件描 ...

  3. EF Core中如何正确地设置两张表之间的关联关系

    数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...

  4. Linux中的文件描述符与打开文件之间的关系------------每天进步一点点系列

    http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录文件. ...

  5. JavaScript中的 原型 property 构造函数 和实例对象之间的关系

    1 为什么要使用原型? /* * javascript当中 原型 prototype 对象 * * */ //首先引入 prototype的意义,为什么要使用这个对象 //先来写一个构造函数的面向对象 ...

  6. 通俗易懂理清mybatis中SqlSessionSql、SqlSessionTemplate、SessionFactory和SqlSessionFactoryBean之间的关系

    我潇洒的灰大狼又回来啦.今天送大家的一句话是: 保持耐心,永远年轻,永远热泪盈眶. 前言 先容我哭一会儿,呜呜呜~昨晚写了一半的文章,还没保存就盖上盖子准备回家,拔下电源准备把电脑塞进书包带回家完成时 ...

  7. (转)Linux中的文件描述符与打开文件之间的关系

    转:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录文 ...

  8. Unity3D 之3D动画机设置

    新建一个动画机 然后创建一些动画的属性 每根线都是一个动画到下一个动画的转变,动画的转变是基于条件的. 1.通过建立Parameters设定动画的转换条件 2.右边的Conditions设定可以设定是 ...

  9. unity3D中一些有用的设置

    edit-project setting-time:可以设置fixed update()每一帧执行的时间 timescale:时间流动速度,设置为0则运用了time.deltatime的动画计时器均停 ...

随机推荐

  1. 调研一类软件的发展演变—聊天软件( 1000-2000 words, in Chinese)

    因为本人平时对聊天软件的涉及比周边其他同学而言所涉及的是比较多的.所以说想写写这个东西.(ps本文里面的具体通讯信息的时间安排不分先后) 也许最起初的通讯信息的传达是利用.烽火狼烟这一类可以远距离视觉 ...

  2. 基于javascript实现图片懒加载(亲测有效)

    这篇文章主要介绍了javascript实现图片懒加载的方法及思路,有时我们需要用懒加载,也就是延迟加载图片的方式,来提高网站的亲和力,需要的朋友可以参考下! 一.定义 图片延迟加载也称为懒加载,延迟加 ...

  3. [python爬虫] Selenium定向爬取海量精美图片及搜索引擎杂谈

    我自认为这是自己写过博客中一篇比较优秀的文章,同时也是在深夜凌晨2点满怀着激情和愉悦之心完成的.首先通过这篇文章,你能学到以下几点:        1.可以了解Python简单爬取图片的一些思路和方法 ...

  4. SSDB安装配置

    1.下载ssdb wget -O ssdb-master.zip https://codeload.github.com/ideawu/ssdb/zip/master 2.编译安装 unzip ssd ...

  5. [读书笔记]C#学习笔记四: C#2.0泛型 可控类型 匿名方法和迭代器

    前言 C#1.0的委托特性使方法作为其他方法的参数来传递,而C#2.0 中提出的泛型特性则使类型可以被参数化,从而不必再为不同的类型提供特殊版本的实现方法.另外C#2.0还提出了可空类型,匿名方法和迭 ...

  6. Shell脚本学习入门(一)

    1.Shell脚本是解释型的语言. 2.Shell脚本建立的基本步骤: 3.Shell脚本文件的第一行一般可以是:"#! 路径名 -(选项)", 为了要使Shell脚本有移植性,请 ...

  7. Redis info参数总结(转)

    Redis官网对 info 已经讲解的比较清楚的,参考文档 . 可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一 ...

  8. android recycleview 中禁止多点触发

    int currentapiVersion = android.os.Build.VERSION.SDK_INT; if (currentapiVersion >= android.os.Bui ...

  9. AsyncTask实现多线程断点续传

    前面一篇博客<AsyncTask实现断点续传>讲解了如何实现单线程下的断点续传,也就是一个文件只有一个线程进行下载.   对于大文件而言,使用多线程下载就会比单线程下载要快一些.多线程下载 ...

  10. tbb flow graph node types