在Cutscene之间进行的动画融合,Cutscene 动画Clip没有根动画选项,根据官方BakePosition的原理,复刻一个

核心思想是在Enter的时候,将动画全部根据时间存储位置,BakeRootMotion();

然后再正式的Update中 应用ApplyBakedRootMotion(time);

Slate官方给的是在Track中进行的根位置烘焙,而我们是要在Clip中进行烘焙,所以在细节上有一些需要注意的地方,

  1. 推进烘焙时间的函数 EvaluateTrackClips 其中的Enter 与Exit 不能推进,否则会出现递归,栈溢出
  2. Update中不能推进Graph时间,否则烘焙位置会出现偏差,人物会漂移
  3. 使用不当 人物会螺旋升天。。。

参考代码

using Sirenix.OdinInspector;
using Slate;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;[Name("播放动画Playable")]
[Attachable(typeof(AnimTrack))]
public class PlayAnimPlayableClip : CutsceneClip<Animator>, IDirectable
{private const int ROOTMOTION_FRAMERATE = 60;public AnimationClip animationClip;[LabelText("播放速度")][SerializeField]public float PlaySpeed = 1;[LabelText("循环播放(动画长度超过原动作片段时,循环动作)")][SerializeField]public bool Loop = false;[HideInInspector][SerializeField] private float _length = 1 / 30f;private AnimationClipPlayable playableClip;private PlayableGraph playableGraph;//bake Positionpublic bool useRootMotion = true;private bool useBakedRootMotion;[SerializeField, HideInInspector]public bool isRootMotionPreBaked;[SerializeField, HideInInspector]private List<Vector3> rmPositions;[SerializeField, HideInInspector]private List<Quaternion> rmRotations;private Animator _animator;public Animator animator{get{if (_animator == null || _animator.gameObject != actor.gameObject){_animator = ActorComponent;}return _animator;}}protected override void OnCreate(){Refresh();}protected override bool OnInitialize(){//EventManager.OnNewMessage += GetMessage;return base.OnInitialize();}protected override void OnEnter(){playableGraph = PlayableGraph.Create();var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", ActorComponent);// 将剪辑包裹在可播放项中playableClip = AnimationClipPlayable.Create(playableGraph, animationClip);// 将可播放项连接到输出playableOutput.SetSourcePlayable(playableClip);// 播放该图。playableGraph.Play();playableClip.SetPlayState(PlayState.Paused);//使时间停止自动前进。//是否烘焙position 位置if (useRootMotion){BakeRootMotion();}}private void BakeRootMotion(){if (isRootMotionPreBaked){animator.applyRootMotion = false;useBakedRootMotion = true;return;}var rb = animator.GetComponent<Rigidbody>();if (rb != null){rb.MovePosition(animator.transform.localPosition);rb.MoveRotation(animator.transform.localRotation);}useBakedRootMotion = false;animator.applyRootMotion = true;rmPositions = new List<Vector3>();rmRotations = new List<Quaternion>();var tempActiveClips = 0;var updateInterval = (1f / ROOTMOTION_FRAMERATE);for (var time = startTime - updateInterval; time <= endTime + updateInterval; time += updateInterval){EvaluateTrackClips(time, time - updateInterval, ref tempActiveClips);if (tempActiveClips > 0){playableGraph.Evaluate(updateInterval);}//apparently animator automatically sets rigidbody pos/rot if attached on same go when evaluated.//thus we read pos/rot from rigidbody in such cases.var pos = rb != null ? rb.position : animator.transform.localPosition;var rot = rb != null ? rb.rotation : animator.transform.localRotation;rmPositions.Add(pos);rmRotations.Add(rot);}animator.applyRootMotion = false;useBakedRootMotion = true;}void EvaluateTrackClips(float time, float previousTime, ref int tempActiveClips){IDirectable clip = this;if (time >= clip.startTime && previousTime < clip.startTime){tempActiveClips++;//clip.Enter();}if (time >= clip.startTime && time <= clip.endTime){clip.Update(time - clip.startTime, previousTime - clip.startTime);}if ((time > clip.endTime || time >= this.endTime) && previousTime <= clip.endTime){tempActiveClips--;//clip.Exit();}}protected override void OnUpdate(float time){var curClipLength = animationClip.length;float normalizedBefore = time * PlaySpeed;if (Loop && time > curClipLength){//要跳转到的动画时长 ,根据Update Time 取余 ,需要归一化时间normalizedBefore = time * PlaySpeed % curClipLength;}playableClip.SetTime(normalizedBefore);if (useRootMotion && useBakedRootMotion){ApplyBakedRootMotion(time);}}private void ApplyBakedRootMotion(float time){var frame = Mathf.FloorToInt(time * ROOTMOTION_FRAMERATE);var nextFrame = frame + 1;nextFrame = nextFrame < rmPositions.Count ? nextFrame : rmPositions.Count - 1;var tNow = frame * (1f / ROOTMOTION_FRAMERATE);var tNext = nextFrame * (1f / ROOTMOTION_FRAMERATE);var posNow = rmPositions[frame];var posNext = rmPositions[nextFrame];var pos = Vector3.Lerp(posNow, posNext, Mathf.InverseLerp(tNow, tNext, time));animator.transform.localPosition = pos;var rotNow = rmRotations[frame];var rotNext = rmRotations[nextFrame];var rot = Quaternion.Lerp(rotNow, rotNext, Mathf.InverseLerp(tNow, tNext, time));animator.transform.localRotation = rot;}protected override void OnExit(){base.OnExit();}[Button("刷新", 40)]public override void Refresh(){length = animationClip.length / PlaySpeed;}//Todo OnGui 红色表示动画长度public override string info{get { return animationClip != null ? animationClip.name : base.info; }}public override float length{get { return _length; }set { _length = value; }}public override bool canCrossBlend{get { return false; }}
}

Slate轨道工具使用(四)—根动画与位置相关推荐

  1. Java开发人员必须掌握的两个Linux魔法工具(四)

    子曰:"工欲善其事,必先利其器." 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 学习应该是快乐的,在这个乐园中我努力让自己能用简洁易懂(搞笑有趣) ...

  2. 我的前端工具集(四)树状结构后篇

    我的前端工具集(四)树状结构后篇   liuyuhang原创,未经允许禁止转载 目录 我的前端工具集 上文连接 我的前端工具集(四)树状结构前偏 1.数据组织 在3.2.节有截图 2.树状结构代码 2 ...

  3. 耳机四根线的图解_type c数据线拆解及接线图文详解

    不少新一代手机开始支持Type-C接口,比如乐视.PPTV.努比亚Z11.小米4C和三星Note7等.和普通Micro USB相比,Type-C数据线因为正反插的关系对品质要求更高,不然随时有短路烧毁 ...

  4. C语言练习1-判断四根木棍是否可以摆成三角形

    题目 分析 1.输入四根木棍的长度,输出三角形判断结果. 2.限制条件 三角形判断条件: (1)正常三角形的判断,两短边之和大于第三边,最大的两条边之差小于第三边. (2)伪三角形的判断,两短边之和等 ...

  5. 笔试编程题 拼凑正方形 Java题解 牛牛有4根木棍,长度分别为a,b,c,d。羊羊家提供改变木棍长度的服务,如果牛牛支付一个硬币就可以让一根木棍的长度加一或者减一。牛牛需要用这四根木棍拼凑一个正方

    题目描述 牛牛有4根木棍,长度分别为a,b,c,d.羊羊家提供改变木棍长度的服务,如果牛牛支付一个硬币就可以让一根木棍的长度加一或者减一.牛牛需要用这四根木棍拼凑一个正方形出来,牛牛最少需要支付多少硬 ...

  6. 使用keytool工具产生带根CA和二级CA的用户证书

    使用keytool工具产生带根CA和二级CA的用户证书 1 生成根CA 1.1 生成根CA证书 根CA实际是一张自签CA,自签CA的使用者和颁发者都是它自己.使用下面的命令生成根证书,如果没有指定ke ...

  7. PyQt5之QGraphics 008 QGraphicsItem四连杆机构动画

    首先看一下效果: 机械相关专业的同学,在学习机械原理这门课的时候一定做过四连杆方面的运动分析, 以下,用PyQt做四连杆的动画.先不考虑有死点等特殊机构的情况. 其中,l4杆是固定的,其它三根是活动的 ...

  8. 什么是三相四线制,四根线为何也称为三相电,与三根线有什么关系

    什么是三相四线制,四根线为何也称为三相电,与三根线有什么关系 [三相四线制] 在低压配电网中,输电线路一般采用三相四线制,其中三条相线线路分别代表A,B,C三相,另一条是中性线N(区别于零线,在进入用 ...

  9. Android 安卓动画 补间动画 - 组合(四个动画) 动画

    补间动画之组合动画 - 介绍 顾名思义,就是四种动画(平移动画,旋转动画,缩放动画,渐变动画)一起实现效果,四种动画有着共同的属性,也有各自的特有属性,下面列出来的四种动画的共有属性 实现目标:点击按 ...

  10. 【python+情人节】玩个俄罗斯方块都是爱你的形状——四、动画展示

    本项目效果如图 动画过程已投稿b站:https://www.bilibili.com/video/av88671119 目录 一.思路分析 二.手动拼图 三.自动拼图 四.动画展示 ========= ...

最新文章

  1. 风电功率预测matlab,一种基于二十四节气的风电功率预测方法与流程
  2. python第三天(dictionary应用)转
  3. Windows 8下看漫画的程序发布
  4. Promise 上手
  5. 深入Java核心:JVM中的栈和局部变量
  6. Linux之使用MobaXterm远程连接Linux前提条件
  7. 装饰器python3 默认_python3【基础】-装饰器
  8. vue init失败解决方案-终极版
  9. 阶段3 3.SpringMVC·_05.文件上传_3 文件上传之Springmvc方式上传原理分析
  10. 考研数学——求极限方法总结
  11. Java IO与NIO的区别
  12. Oracle连接pg,pg连接oracle.sql
  13. 可怜的博主跟小豆人杠起来啦!Python制作的吃豆人小游戏,快来围观!!
  14. R语言将文件写入CSV,并读取
  15. IOS证书申请最新版2021
  16. 关于植物大战僵尸| Plants VS Zombies 运行时 Fatal Error
  17. 威纶通定时循环操作宏_数控铣床编程操作,四个实例助你快速入门
  18. 回顾2019年度京东集团10件大事:不忘初心,坚定前行
  19. 中南大学2021年博士研究生招生简章
  20. 人类产生负面情绪 根源在贪嗔痴三毒

热门文章

  1. 编译原理-4-上下文无关文法
  2. ssh和ssm的区别,好处
  3. CUDA10.0网盘下载
  4. 电脑上win10的mysql软件老闪退,技术编辑应对win10系统Mysql闪退的修复办法
  5. oracle数据库max使用,Oracle / PLSQL MAX函数
  6. 抖音一个老人和一个机器人歌曲_抖音M哥很火的歌曲有哪些
  7. 物联网技术在智慧城市建设应用中的难点与疑点
  8. 基于RFID的图书馆管理
  9. 【labelme】制作标签数据的完整流程
  10. 代码抛出异常后进行事务回滚的两种方式(Spring @Transactional注解)