简体   繁体   中英

Unity 3D animation.MatchTarget with root motion affecting only position or only rotation

Background

In the Unity 3D engine version 2017.3.1f1, I'm working on a 3D character driven by mecanim root motion. I need to rotate the character exactly 180° around the Y-axis (up) so it then walks left or right (it's 2D game). Because it's mecanim, angles are not always precise and character turns sometimes 177°, sometimes 181°. This is unwanted error causing the character to traverse in the Z-axis while walking. So I decided to correct the final angle with the built-in animator.MatchTarget() function ( https://docs.unity3d.com/ScriptReference/Animator.MatchTarget.html ).

Problem

Animator.MatchTarget doesn't have overloaded function to match only rotation so I need to enter the final position of the turn animation clip (the rotate animation has root motion and position change). I assumed member variable Animator.TargetPositon does the job:

// following script is attached to the character rotation Animator state
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericState : StateMachineBehaviour {

     public float targetAngle_ = 180.0f;

     override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){

         Quaternion targetRotation_ = Quaternion.Euler(0, targetAngle_, 0); 
         animator.MatchTarget(animator.targetPosition, 
                              targetRotation_, 
                              AvatarTarget.Root, 
                              new MatchTargetWeightMask(Vector3.one, 1f),
                              0f,
                              1f);
     }
}

But it doesn't involve the root motion so the character ends at the exact position as it started the turn animation. There is another variable Animator.RootPosition ( https://docs.unity3d.com/ScriptReference/Animator-rootPosition.html ), but that just holds current character position.

Workaround

The only solution I can think of is to read the animation data in the editor mode, store the root motion offset, then apply for each animation at runtime. This solution is overcomplicated and I'm looking for a simple alternative to "match just rotation and read target position from the root motion in the animation".

Thank you

Following workaround works (without accessing animation curves in edit mode). Please note OnStateMove is used instead of OnStateUpdate . When OnStateMove is overridden, root motion is ignored in the state and must be applied manually ( https://docs.unity3d.com/ScriptReference/Animator.ApplyBuiltinRootMotion.html ) in this method. Somehow it does the trick better than Animator.MatchTarget()

// following script is attached to the character rotation Animator state
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericState : StateMachineBehaviour {

    public bool _SnapEnabled;

    Quaternion _enterRotation;
    public float targetAngle_ = 180.0f;

    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
        _enterRotation = animator.rootRotation;
    }

    override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
        float normalizedTime_ = Mathf.Clamp(
                               (stateInfo.normalizedTime - _matchMin) /
                               (_matchMax - _matchMin), 0f, 1f);

        if ( _SnapEnabled && normalizedTime_ > 0 ){
            Quaternion snappedRotation_ = Quaternion.Euler(0, targetAngle_, 0);
            Quaternion targetRotation_ = Quaternion.Lerp(_enterRotation,
                                              snappedRotation_,
                                              normalizedTime_);

            animator.transform.position = animator.rootPosition;
            animator.transform.rotation = targetRotation_;
        } else {
            animator.ApplyBuiltinRootMotion();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM