Blender到Unity动画-跳入帧

时间:2018-12-14 01:33:44

标签: c# unity3d animation blender unity3d-mecanim

我决定尝试将带有动画的FBX中的Blender模型导出到Unity。此模型的上门有两个动画,分别是打开和关闭。就是这样-看起来我的模型喜欢在模型启动时跳入BOTH动画的起源。如果我导入模型并且门是打开的,并且我决定触发它来关闭,它将正确关闭-但是,当我尝试打开它时,它决定它需要保持在相同的原点作为关闭门的动画首先,然后将其打开-基本上导致门向模型外移动太多。

我也提出了要尝试依靠Mecanim动画器控件中的ONE动画的观点-但似乎在朝相反方向移动时,它回到了门的正确位置,但并没有这样做相同的速度,但是却很不稳定。最后,当我尝试将一个门动画以相反的速度(即门靠近门关闭,一个门的速度为1而另一个门的速度为-1)过渡到相同的门动画时,它仍然跳动不正常。

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

enter image description here

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

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

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的演示教程-没有骰子...

2 个答案:

答案 0 :(得分:1)

在将来自搅拌机的动画统一化方面,我遇到了许多困难。有很多陷阱。这是我会尝试的几件事。让我知道这些方法是否对您有用。

 When animating a model in blender it often happens that the origin of  your model
 has accidentally been moved or is not in the exact same place between your two animations
 and when that gets imported into unity it has a way of messing with your animations.
 So just double check between your animations and make sure that the origin has not 
 shifted between the two animations
  • 确保您未在​​统一动画器中应用RootMotion

enter image description here

适用于根运动here

的文档
 basically what it does if enabled is for any movement that takes place in your
 animation it adds whatever movement transpired in the animation to its current position
 Therefore if the root object of the door moved left by 2units when it opens and your are 
 applying root motion the object would then be 2 units left of where you would
 expect. And it would just continue to stack getting further and further left.

  • 确保删除动画剪辑中的所有transform.position关键点。
 I am assuming that you do not want to actually have the position of the door move but 
 instead just have the animation make it appear as if the door is moving. If so in that case
 Assuming that your object is setup right. Which in my mind if it was a sliding door it would
 have an object tree like this RootObject>Frame>Door. With that being the case the only 
 object that should have any animation keys on it should be the door object. the other parent
 objects should be stationary.


  • 次要建议。我会用布尔代替触发器。这样,更容易跟踪门的状态。 (即,您的动画基于“ isClosed”布尔值)

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

答案 1 :(得分: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仅在使用时才被重置(或在脚本中使用{ {1}}。

我看到的另一个问题是,当前您使用解耦的Animator.ResetTrigger语句...因此,理论上可以同时按下所有四个键,这可能会导致某些问题(if调用将直接跳转到目标状态,但是之前Play个调用的触发器仍将保留并堆叠,因此您的动画师有可能从下一帧开始进行各种转换。)您应该使用{{1 }}语句,一次只能处理一个按键。


对于一个只有两个状态且门之间没有复杂动画的简单门,我建议采用另一种方法:

  1. 不要仅从Blender导出模型

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

  3. 在动画制作器中只有两个状态,例如Settrigger | if-else

  4. 例如使用bool代替触发器Opened

  5. 以仅具有完全正确的Closed关键帧并在检查器中禁用IsOpen的方式创建“动画”。 Unity会自动在两个动画之间进行插值,因此,如果每个动画只有一个关键帧,则值(位置,颜色,旋转等)之间的所有插值都将由Unity本身自动处理。

  6. 通过以下方式进行转换

    • 1-> Loop Time
      我们实际上不会使用退出时间,但这可以解决引发警告的小错误

        

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

      如果您将其放在ExitTime

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

    • 最后是您的两个条件

      • 打开->关闭:条件:TransitionOffset
      • 关闭->打开:条件:0

稍后,您将在代码中使用

IsOpen == false

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


如果您在优化和关闭过程中需要执行多个“步骤”,例如由于在门实际移动之前会有一些复杂的解锁动画,所以我建议

  • 为每个步骤使用状态
  • 将一个方向的所有链接与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"); } }
  • 使用前面提到的设置在这些状态之间进行插值
  • 最后,在每个“步骤对”之间都有两个过渡条件,因此每个动画要么在HasExitTime = true过渡到“更开放”,要么在ExitTime = 1过渡到“更加封闭”

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

enter image description here