Blender 到 Unity 动画 - 跳帧

Posted

技术标签:

【中文标题】Blender 到 Unity 动画 - 跳帧【英文标题】:Blender to Unity Animation - Jumps In Frames 【发布时间】: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 的演示教程 - 没有骰子......

【问题讨论】:

【参考方案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 语句只允许处理一个一次按键。


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

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

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

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

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

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

    按照以下方式进行转换

    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】:

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

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

应用根运动的文档here

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

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

【讨论】:

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

以上是关于Blender 到 Unity 动画 - 跳帧的主要内容,如果未能解决你的问题,请参考以下文章

为啥从 Blender 导出到 Unity (.fbx) 后动画会这样 [关闭]

blender 和unity3D的一个问题

无法将动画从 Blender 导出到 Unity

如何从 Blender 导出到 unity3d

将 Fbx 从 Blender 导出到 Unity

Blender/UE4骨骼转换插件:Uefy v1.2.1 For UE4 BL 2.8+使用教程