【问题标题】:Blender to Unity Animation - Jumps In FramesBlender 到 Unity 动画 - 跳帧
【发布时间】:2019-05-15 07:02:09
【问题描述】:

我决定尝试将带有动画的 FBX 中的 Blender 模型导出到 Unity。该模型的顶门有两个动画,打开和关闭。事情是这样的——我的模型似乎喜欢在模型开始时跳入两个动画的起源,即。如果我导入模型并且门是打开的,并且我决定触发关闭它,它将正确关闭 - 但是,当我尝试打开它时,它决定它需要保持与关闭门动画相同的原点首先,然后它打开 - 基本上导致门在模型之外移动得太远。

我还特意尝试在 Mecanim 动画器控件中依靠 ONE 动画 - 但它似乎在向相反方向移动时回到门的正确位置时,它并没有这样做速度相同,但速度不规律。最后,当我尝试将一个门动画过渡到具有相反速度的 SAME 门动画时(即门接近关门,一个速度为 1,一个速度为 -1),它仍然会不规律地跳跃。

这是我尝试的最后一个 Mecanim 动画师设置:

这是尝试在其他状态下使用相同动画的方法,但速度为负速度而不是正速度。它不像你想象的那样工作。

我在下面的代码中使用状态触发器在这些状态之间进行转换:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;

public class TriggerAnimation : MonoBehaviour {

    public Transform cockPit;
    // Use this for initialization
    void Start () {


    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown("t"))
        {
            //AnimationPlayableUtilities.PlayClip("CockPit_ExtDoor|Open");
            Debug.Log("I'm being pressed");
            //GetComponent<Animator>().SetTrigger("ExtDoorOpen");
            GetComponent<Animator>().SetTrigger("IntDoorOpen");
            //GetComponent<Animator>().SetTrigger("CockPit_Door|Open");

        }
        if (Input.GetKeyDown("u"))
        {
            //PlayableGraph graph = new PlayableGraph();
            //AnimationPlayableUtilities.PlayAnimatorController(GetComponent<Animator>(), GetComponent<RuntimeAnimatorController>(), out graph);
            Debug.Log("I'm being pressed");
            //GetComponent<Animator>().SetTrigger("ExtDoorClose");
            GetComponent<Animator>().SetTrigger("IntDoorClose");
            //GetComponent<Animator>().SetTrigger("CockPit_Door|Close");

        }
        if (Input.GetKeyDown("x"))
        {
            GetComponent<Animation>().Play("CockPit_IntDoor|Open");
        }
        if (Input.GetKeyDown("z"))
        {
            GetComponent<Animation>().Play("CockPit_IntDoor|Close");
        }
    }
}

谁能告诉我是否有更好的方法来解决这个问题以及如何处理?我试过在这方面的几篇文章之间跳转,包括他们网站上关于 Mecanim for Unity 的演示教程 - 没有骰子......

【问题讨论】:

    标签: c# unity3d animation blender unity3d-mecanim


    【解决方案1】:

    我不知道您的动画剪辑和过渡效果如何,但这里有一些提示:

    if (Input.GetKeyDown("x"))
    {
        GetComponent<Animation>().Play("CockPit_IntDoor|Open");
    }
    
    if (Input.GetKeyDown("z"))
    {
        GetComponent<Animation>().Play("CockPit_IntDoor|Close");
    }
    

    Animator.Play 直接“跳转”到目标状态,没有任何转换。但是每次按键都会重新开始动画。

    Triggers 被堆叠所以如果你按下例如打开按钮多次,然后按下关闭按钮,您将在两种状态之间进行两次(甚至多次)转换,因为 Trigger 仅在使用时被重置(或在脚本中使用 Animator.ResetTrigger 主动重置) )。

    我看到的另一个问题是,目前您使用解耦的 if 语句......所以理论上可以同时按下所有 4 个键,这可能会导致一些问题(Play 调用会直接跳转到目标状态,但之前 Settrigger 调用的触发器仍然存在并堆叠,因此您的动画师可能会从下一帧开始进行各种转换。)您宁愿使用 if-else 语句只允许处理一个一次按键。


    对于只有两种状态且在它们之间没有复杂动画的简单门,我建议采用不同的方法:

    1. 不要只从 Blender 中导出动画模型

    2. 对于旋转门,请确保枢轴位于您要旋转的轴上

    3. 在动画师中只有两种状态,例如Opened | Closed

    4. 使用布尔值代替触发器,例如IsOpen

    5. 创建您的“动画”,使两者都只有 1 关键帧并在检查器中禁用 Loop Time。 Unity 会自动在两个动画之间进行插值,因此如果每个动画只有一个关键帧,则所有值(位置、颜色、旋转等)之间的插值都由 Unity 自己自动处理。

    6. 按照以下方式进行转换

      • ExitTime -> 1
        我们实际上不会使用退出时间,但这修复了一个引发警告的小错误

        状态之间的有效长度差异太大。过渡预览将被禁用。 UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

        如果你让它0

      • HasExittime -> false
        这意味着不要等到动画完成或在某个帧完成过渡,而是立即进行(只有关键帧的动画自动默认长度为 1 秒)
      • FixedDuration -> true(我们想在几秒钟内完成配置)
      • TransitionDuration(s) -> 您现在可以在此处配置您希望转换需要多长时间(打开和关闭也可以不同)
      • TransitionOffset -> 0(动画只有一个关键帧,所以我们不想在另一帧开始)

      • 最后是你的两个条件

        • 打开 -> 关闭:条件:IsOpen == false
        • 关闭 -> 打开:条件:IsOpen == true

    在后面的代码中你会使用

    // Store the component frerence instead of getting it everytime again
    private Animator _animator;
    
    private void Awake()
    {
        _animator = GetComponent<Animator>();
    }
    
    private void Update()
    {
        if (Input.GetKeyDown("t"))
        {
            Debug.Log("t is being pressed");
            _animator.SetBool("IsOpen", true);
        }
        // use if-else in order to process only one of the buttons at a time
        else if (Input.GetKeyDown("u"))
        {
            Debug.Log("u is being pressed");
            _animator.SetBool("IsOpen", false);
        }
        // you still can keep those for jumping to a state directly without the transition
        else if (Input.GetKeyDown("x"))
        {
            _animator.Play("Opened");
        }
        else if (Input.GetKeyDown("z"))
        {
            _animator.Play("Closed");
        }
    }
    

    现在使用 Bool 值而不是触发器,您不必关心堆栈调用。我希望这 1 个关键帧动画方法符合您的要求。


    如果您需要在打开和关闭过程中有多个“步骤”,例如因为在门实际移动之前有一些复杂的解锁动画,我建议

    • 为每一步使用一个状态
    • HasExitTime = trueExitTime = 1链接所有一个方向
    • 使用前面提到的设置在这些状态之间进行插值
    • 最后在每个“步骤对”之间有两个过渡条件,因此每个动画要么在IsOpen = true 上过渡到“更开放”,要么在IsOpen = false 上过渡到“更封闭”

    为了更好地理解这里是一个示例,更复杂的设置可能看起来像只使用这样的 1 个关键帧动画

    【讨论】:

    • 谢谢。你在我过去的帖子中也很有帮助,但这是非常有用的信息,即使我必须承认我没有完成你建议的一切。老实说,这样做的目的更多是让我练习创建一个简单的驾驶舱,并练习从 Blender 本身导入它的门动画——但我想你用 Unity 代替了一个很好的观点。尽管如此,我还是特别记下了 1.) 您关闭“退出时间”参数的建议和 2.) 您更改过渡持续时间的建议。这些我可以完美应用!
    【解决方案2】:

    将搅拌机中的动画整合到统一中时遇到了很多困难。有很多陷阱。这是我会尝试的几件事。让我知道这些是否对您有用。

    在搅拌机中为模型制作动画时,经常会发生模型的起源 在两个动画之间被意外移动或不在完全相同的位置 当它被导入统一时,它就会弄乱你的动画。 因此,只需仔细检查您的动画,并确保原点没有 在两个动画之间切换
    • 确保您没有在 unity animator 中应用 RootMotion



    应用根运动的文档here

    基本上,如果启用它的作用是针对发生在您的 动画它将动画中发生的任何运动添加到其当前位置 因此,如果门的根对象在打开时向左移动了 2 个单位并且您 应用根运动,对象将在您想要的位置左侧 2 个单位 预计。而且它会继续堆叠,越来越左。
    • 确保删除动画剪辑中的所有 transform.position 键。
    我假设您不想实际移动门的位置,但是 而是让动画让它看起来好像门在移动。如果是这样的话 假设您的对象设置正确。在我看来,如果它是一扇推拉门,它会 有一个像这样的对象树 RootObject>Frame>Door。既然如此,唯一的 应该有任何动画键的对象应该是门对象。另一位家长 物体应该是静止的。
    • 小建议。我会使用布尔而不是触发器。这样就更容易跟踪门的状态。 (即,您的动画基于“isClosed”布尔值)

    这些只是我在过去发现的一些有用的故障排除技巧。

    【讨论】:

    • 我想你提出的建议一样好 - 我特别要记住布尔值的建议。您能否在答案的要点 1、2 和 3 中详细说明您的意思?
    • 希望编辑有所帮助。如果您有任何其他问题,请告诉我。
    • 您好,是的,这非常有帮助。解决提示 #1 的最佳方法是什么?我对这个场景还是很陌生,所以我非常感谢这一切
    • 我在第一点添加了一个有用的链接,用于调整搅拌机的原点。祝你好运
    猜你喜欢
    • 2022-08-19
    • 2021-01-17
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 2022-08-23
    相关资源
    最近更新 更多