0

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

我还特意尝试在 Mecanim 动画器控件中依靠 ONE 动画 - 但是当它朝相反方向移动时,它似乎回到了门的正确位置,但它并没有以相同的速度完成,但这样做不规律。最后,当我尝试让一个门动画过渡到具有相反速度的相同门动画(即门接近关门,一个速度为 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 的演示教程 - 没有骰子......

4

2 回答 2

1

我不知道您的动画剪辑是什么样子以及您的过渡是什么样子,但这里有一些提示:

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

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

Animator.Play直接“跳转”到目标状态而不进行任何转换。但是每次你按键时动画都会重新开始。

Triggers堆叠起来,因此如果您多次按下例如打开按钮而不是按下关闭按钮,您将在两种状态之间进行两次(甚至多次)转换,因为 aTrigger仅在使用时重置(或在脚本中主动重置)使用Animator.ResetTrigger)。

我看到的另一个问题是,目前您使用解耦if语句......所以理论上可以同时按下所有 4 个键,这可能会导致一些问题(Play调用将直接跳转到目标状态,但来自beforeSettrigger调用将仍然存在并堆叠,因此您的动画师可能会从下一帧开始进行各种转换。)您宁愿使用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(动画只有 1 个关键帧,所以我们不想在另一帧开始)

    • 最后是你的两个条件

      • 打开 -> 关闭:条件: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 值而不是 Triggers,您不必关心堆栈调用。我希望这 1 个关键帧动画方法符合您的要求。


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

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

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

在此处输入图像描述

于 2018-12-14T07:50:43.887 回答
1

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

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

在此处输入图像描述

在此处应用根运动的文档

基本上,如果启用它的作用是针对发生在您的
 动画它将动画中发生的任何运动添加到其当前位置
 因此,如果门的根对象在打开时向左移动了 2 个单位并且您
 应用根运动,对象将在您想要的位置左侧 2 个单位
 预计。而且它会继续堆叠,越来越左。

  • 确保删除动画剪辑中的所有 transform.position 键。
我假设您不想实际移动门的位置,但是
 而是让动画让它看起来好像门在移动。如果是这样的话
 假设您的对象设置正确。在我看来,如果它是一扇推拉门,它会
 有一个像这样的对象树 RootObject>Frame>Door。既然如此,唯一的
 应该有任何动画键的对象应该是门对象。另一位家长
 物体应该是静止的。


  • 小建议。我会使用布尔而不是触发器。这样就更容易跟踪门的状态。(IE将您的动画基于“isClosed”布尔值)

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

于 2018-12-14T02:46:42.287 回答