xiangtingsl 发表于 2022-9-7 08:39

Unity RootMotion简单尝试记录

找了一大圈资料,基本都是各种copy,讲的基本都是unity怎么使用~为此,我还特意去看了ue的源码,想着对比看看!
这里本来是想要说明工作的整个过程的,但是因为结果不理想,我也不敢说这是在说原理。
本文只是在对unity root motion的一个简单的尝试记录!
Root Motion 工作原理

官方文档的说明
https://docs.unity3d.com/cn/current/Manual/RootMotion.html
下面就是一套瞎操作!
资源导入及简单设置

模型导入的时候使用的是Humanoid


动画导入也要选择Humanoid


Animation页签


在Root Motion Node中使用的是< None >的时候,界面就和网上google或者官方的界面样式一致了!
like this! https://docs.unity3d.com/cn/current/Manual/RootMotion.html
Apply Root Motion 在Root Motion Node为none的测试



直接运动到帧末的时候,GameObject在Z轴的位置是 -3.99 !
展开一下动作资源,在使用Root Motion Node为none时只有Root T和Root Q,这两个curve的最后数值!(获取的代码在文后)


居然有差异!!!
排查差异



把关于Aniomation的优化全关掉!
运行得到的结果没有变化!!
这个看情况的,如果本来和动作同学设定的值变成较大,关掉这些优化后,还是有变化的。咨询了一下动作的同学,得到设置的值


这一下子就懵逼了我。
https://forum.unity.com/threads/mecanim-root-motion-for-generic-rig-quadruped.169891/ https://forum.unity.com/threads/is-there-a-way-to-extract-rootmotion-curves-from-a-clip.610579/ https://forum.unity.com/threads/make-root-motion-in-animation-clip.250723/


问题是我在Animation中没有看到Motion!!!
Apply Root Motion 在Root Motion Node为Root的测试

尝试将Root Motion Node为Root


然后再Animation中就能找到Motion Curve


尝试获取一下Root T和Root Q(或者Motion T和Motion Q)的Curve,然后读取一下数据,也测试一下Apply Root Motion的执行结果!
Apply Root Motion的执行结果:


Curve读取的结果:


展开Curve看看


基本就是-3.7呀!!怎么Unity的Apply Root Motion成了-4呢?而且3dmax中设置也是-4!!!(Apply Root Motion的结果更加逼近3dmax)
自己在Unity中搞一个Animaion试试




赞,我设置的10呀!!
去掉Apply Root Motion


这就一样了!!!
晕了,等其他大佬分享吧!现在资料有点少~或者以后看UE的源码再分析一下。
代码:
if (Clip.hasMotionCurves)
{
    var bindings = AnimationUtility.GetCurveBindings(Clip);
    // 也可以改成Root测试!
    var pName = "Motion";
    foreach (var bind in bindings)
    {
      if (bind.propertyName == $"{pName}T.x")
      {
            curve_x = AnimationUtility.GetEditorCurve(Clip, bind);
            x = curve_x.Evaluate(7);
      }
      if (bind.propertyName==$"{pName}T.y")
      {
            curve_y = AnimationUtility.GetEditorCurve(Clip, bind);
            y = curve_y.Evaluate(7f);
      }
      if (bind.propertyName==$"{pName}T.z")
      {
            curve_z = AnimationUtility.GetEditorCurve(Clip, bind);
            z = curve_z.Evaluate(7f);
      }
      if (bind.propertyName==$"{pName}Q.x")
      {
            curve_Qx = AnimationUtility.GetEditorCurve(Clip, bind);
            qx = curve_Qx.Evaluate(7f);
      }
      if (bind.propertyName==$"{pName}Q.y")
      {
            curve_Qy = AnimationUtility.GetEditorCurve(Clip, bind);
            qy = curve_Qy.Evaluate(7f);
      }
      if (bind.propertyName==$"{pName}Q.z")
      {
            curve_Qz = AnimationUtility.GetEditorCurve(Clip, bind);
            qz = curve_Qz.Evaluate(7f);
      }
      if (bind.propertyName==$"{pName}Q.w")
      {
            curve_Qw = AnimationUtility.GetEditorCurve(Clip, bind);
            qw = curve_Qw.Evaluate(7f);
      }
    }
}

TheLudGamer 发表于 2022-9-7 08:40

动画输出不准的问题之前也有注意到过,比如导进max里面正常,导进Unity那边就Shake(即使关了压缩+不Loop),或者一些小幅度运动有明显差异,尤其是ApplyRootMotion这种每一帧算差量apply一次的状况,还有就是长父子链矩阵要乘很多次的状况

个人理解是Unity实时运行的采样输出+滤波,和DCC那边是有差异的,再加上计算机浮点不精确,最后输出就是会有点不准,但对于RootMotion而言基本已经够用了,能保证人物不滑步,动画有基本正确的表现就好

消除Shake,可以优化父子结构(所有节点优化为Root的一阶子物体,靠Max那边绑定追踪到原本骨架的节点运动),取消压缩,不Loop/LoopPose,或者DCC确保初末Pose一致

如果有过分精确的动作要求,应该是由Unity这边用计算动画,或者参数化的一些方式来做

LiteralliJeff 发表于 2022-9-7 08:46

我是要做帧同步用,所以才想看看怎么提取数据[捂脸]

kirin77 发表于 2022-9-7 08:52

引擎专家,厉害。[赞]

BlaXuan 发表于 2022-9-7 08:53

[捂脸]title而已,就是学习一下
页: [1]
查看完整版本: Unity RootMotion简单尝试记录