Blender to Unity Animation - прыжки в кадрах
Я решил попробовать экспортировать модель Blender в FBX с анимацией в Unity. Есть две анимации, открытые и закрытые для верхней двери этой модели. Вот в чем дело - кажется, моя модель любит прыгать в начало ОБА анимаций, когда модель запущена, т.е. если я импортирую модель, и дверь открыта, и я решаю активировать, чтобы ЗАКРЫТЬ ее, она закроется должным образом - но затем, когда я пытаюсь ОТКРЫТЬ ее, она решает, что должна остаться в том же источнике, что и анимация закрывающейся двери во-первых, ТОГДА он открывается - в основном это приводит к тому, что дверь заходит слишком далеко за пределы модели.
Я также постарался опереться на ОДНУ анимацию в элементе управления аниматором Mecanim - но, кажется, что когда он движется в противоположном направлении, он возвращается в нужное место для двери, он не делает это с той же скоростью, но делает это беспорядочно. Наконец, когда я пытаюсь сделать анимацию одной двери на ту же анимацию двери с противоположной скоростью (т. Е. Дверь рядом с дверью закрыта, одна со скоростью 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 для Unity на их веб-сайте - без кубиков...
2 ответа
Я не знаю, как выглядят ваши анимационные клипы и как выглядят ваши переходы, но вот несколько советов:
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
Вместо триггеров используйте bool, например
IsOpen
Создайте свою "анимацию" так, чтобы обе
1
ключевой кадр и отключитьLoop Time
в инспекторе. Unity интерполирует между двумя анимациями автоматически, поэтому, если в анимации имеется только один ключевой кадр, вся интерполяция между значениями (позициями, цветами, поворотами и т. Д.) Автоматически обрабатывается самим Unity.Сделайте ваши переходы следующим образом
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 вместо триггеров, вам не нужно заботиться о сложенных вызовах. Я надеюсь, что этот подход с использованием 1 ключевого кадра соответствует вашим требованиям.
Если вам требуется несколько "шагов" в процессе открытия и закрытия, например, из-за наличия сложной анимации разблокировки до того, как дверь фактически сдвинется, я бы порекомендовал
- использовать состояние для каждого шага
- связать все в одном направлении с
HasExitTime = true
а такжеExitTime = 1
- Используйте вышеупомянутую настройку для интерполяции между этими состояниями
- И, наконец, есть два условия перехода между каждой "парой шагов" на пути, поэтому каждая анимация либо переходит в "более открытую" на
IsOpen = true
или "более закрыто" наIsOpen = false
Для лучшего понимания здесь приведен пример того, как более сложные настройки могут выглядеть только при использовании такой анимации с 1 ключевым кадром.
У меня было много трудностей с приведением анимаций из блендера в единство. Здесь много подводных камней. Вот пара вещей, которые я бы попробовал. дайте мне знать, если что-то из этого работает для вас.
- Убедитесь, что ваши источники находятся в тех же положениях в Blender, когда они вводятся в Документах о том, как настроить происхождение здесь
При анимации модели в блендере часто случается, что происхождение вашей модели случайно перемещен или находится не в том же месте между вашими анимациями и когда это импортируется в единство, у него есть способ испортить ваши анимации. Так что просто дважды проверьте анимацию и убедитесь, что источник не имеет переключается между двумя анимациями
- Убедитесь, что вы не применяете RootMotion в аниматоре Unity.
Документы для применения корневого движения здесь
в основном то, что он делает, если включен для любого движения, которое происходит в вашем анимация добавляет любое текущее движение анимации к его текущей позиции Поэтому, если корневой объект двери сдвинулся на 2 единицы, когда она открывается, и вы применяя корневое движение, объект будет в 2 единицах от того места, где вы бы ожидать. И это будет просто продолжать складываться все дальше и дальше влево.
- Убедитесь, что вы удалили все ключи transform.position, которые есть в анимационном клипе.
Я предполагаю, что вы на самом деле не хотите, чтобы положение двери двигалось, но вместо этого просто сделайте так, чтобы анимация выглядела так, будто дверь движется. Если так в этом случае Предполагая, что ваш объект настроен правильно. Что на мой взгляд, если бы это была раздвижная дверь, это было бы есть дерево объектов, подобное этому RootObject>Frame>Door. В таком случае единственным объект, который должен иметь какие-либо ключи анимации, должен быть объектом двери. другой родитель объекты должны быть стационарными.
- Незначительное предложение. Я бы использовал bool вместо триггера. Таким образом, было бы легче отслеживать состояние двери. (IE основывает вашу анимацию на "isClosed" bool)
Это всего лишь несколько полезных советов по устранению неполадок, которые я нашел полезными в прошлом.