C# Unity 3D animation.MatchTarget,根运动仅影响位置或旋转
背景 在Unity 3D引擎版本2017.3.1f1中,我正在制作一个由Mecaim根运动驱动的3D角色。我需要将角色绕Y轴(向上)精确旋转180°,这样它就可以向左或向右行走(这是2D游戏)。因为它是mecanim,角度并不总是精确的,角色有时会转向177°,有时会转向181°。这是不必要的错误,导致角色在行走时沿Z轴移动。因此,我决定使用内置的animator.MatchTarget()函数()纠正最终角度 问题 Animator.MatchTarget没有重载函数仅匹配旋转,因此我需要输入旋转动画片段的最终位置(旋转动画具有根运动和位置更改)。我假设成员变量Animator.TargetPositon执行以下任务:C# Unity 3D animation.MatchTarget,根运动仅影响位置或旋转,c#,animation,unity3d,unity3d-mecanim,C#,Animation,Unity3d,Unity3d Mecanim,背景 在Unity 3D引擎版本2017.3.1f1中,我正在制作一个由Mecaim根运动驱动的3D角色。我需要将角色绕Y轴(向上)精确旋转180°,这样它就可以向左或向右行走(这是2D游戏)。因为它是mecanim,角度并不总是精确的,角色有时会转向177°,有时会转向181°。这是不必要的错误,导致角色在行走时沿Z轴移动。因此,我决定使用内置的animator.MatchTarget()函数()纠正最终角度 问题 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 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);
}
}
但它不涉及根运动,因此角色在开始转弯动画时会在准确的位置结束。还有另一个变量Animator.RootPosition(),但它只保存当前角色的位置
解决方法
我能想到的唯一解决方案是在编辑器模式下读取动画数据,存储根运动偏移,然后在运行时应用于每个动画。这个解决方案过于复杂,我正在寻找一个简单的替代方案,以“仅匹配旋转并从动画中的根运动读取目标位置”
感谢您以下解决方案(无需在编辑模式下访问动画曲线)。请注意,使用OnStateMove而不是OnStateUpdate。当覆盖OnStateMove时,根运动在状态中被忽略,并且必须手动应用() 用这种方法。不知何故,它比Animator.MatchTarget()做得更好
您确定不应该使用Vector3.zero而不是Vector3.one来仅在旋转时应用匹配吗<代码>新的匹配TargetWeightMask(Vector3.one,1f),
// 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();
}
}
}