holopy3/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Scripts/AnimationWarping.cs

129 lines
4.5 KiB
C#
Raw Permalink Normal View History

2020-12-10 14:25:12 +00:00
using UnityEngine;
using System.Collections;
using RootMotion.FinalIK;
namespace RootMotion.Demos {
/// <summary>
/// Warping an effector from animation space to world space.
/// The weight curve of the warp is used to add the offset from "Warp From" to "Warp To" to the effector.
/// "Warp From" should be a Transform parented to the root of the character, hence in animation space (virtual position where a soccer player's foot hits the ball in the animation).
/// "Warp To" should be a Transform in the world space (the actual ball).
/// </summary>
public class AnimationWarping : OffsetModifier {
/// <summary>
/// Definition of a warp from 'warpFrom' to 'warpTo' by normalized time of the animation
/// </summary>
[System.Serializable]
public struct Warp {
[Tooltip("Layer of the 'Animation State' in the Animator.")]
public int animationLayer;
[Tooltip("Name of the state in the Animator to warp.")]
public string animationState;
[Tooltip("Warping weight by normalized time of the animation state.")]
public AnimationCurve weightCurve;
[Tooltip("Animated point to warp from. This should be in character space so keep this Transform parented to the root of the character.")]
public Transform warpFrom;
[Tooltip("World space point to warp to.")]
public Transform warpTo;
[Tooltip("Which FBBIK effector to use?")]
public FullBodyBipedEffector effector;
}
/// <summary>
/// Using effector.positionOffset or effector.position with effector.positionWeight?
/// </summary>
[System.Serializable]
public enum EffectorMode {
PositionOffset,
Position,
}
[Tooltip("Reference to the Animator component to use")]
public Animator animator;
[Tooltip("Using effector.positionOffset or effector.position with effector.positionWeight? " +
"The former will enable you to use effector.position for other things, the latter will weigh in the effectors, hence using Reach and Pull in the process.")]
public EffectorMode effectorMode;
[Space(10)]
[Tooltip("The array of warps, can have multiple simultaneous warps.")]
public Warp[] warps;
private EffectorMode lastMode;
protected override void Start() {
base.Start();
lastMode = effectorMode;
}
/// <summary>
/// Gets the current warping weight of the warp at the specified index.
/// </summary>
public float GetWarpWeight(int warpIndex) {
if (warpIndex < 0) {
Debug.LogError("Warp index out of range.");
return 0f;
}
if (warpIndex >= warps.Length) {
Debug.LogError("Warp index out of range.");
return 0f;
}
if (animator == null) {
Debug.LogError("Animator unassigned in AnimationWarping");
return 0f;
}
// Get the animator state info
AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(warps[warpIndex].animationLayer);
// If not currently playing the animation state of the warp, return
if (!info.IsName(warps[warpIndex].animationState)) return 0f;
// Evaluate the weight of the warp by the current normalized time of the state
return warps[warpIndex].weightCurve.Evaluate(info.normalizedTime - (int)info.normalizedTime);
}
// Called each time before FBBIK solves
protected override void OnModifyOffset() {
// Go through all the warps...
for (int i = 0; i < warps.Length; i++) {
float warpWeight = GetWarpWeight(i);
// Get the offset form warpFrom to warpTo
Vector3 offset = warps[i].warpTo.position - warps[i].warpFrom.position;
// Add that offset to the effector (using positionOffset additively, because it will be reset to Vector3.zero by FBBIK after each update)
switch(effectorMode) {
case EffectorMode.PositionOffset:
ik.solver.GetEffector(warps[i].effector).positionOffset += offset * warpWeight * weight;
break;
case EffectorMode.Position:
ik.solver.GetEffector(warps[i].effector).position = ik.solver.GetEffector(warps[i].effector).bone.position + offset;
ik.solver.GetEffector(warps[i].effector).positionWeight = weight * warpWeight;
break;
}
}
// Switching modes safely, weighing out effector positionWeights
if (lastMode == EffectorMode.Position && effectorMode == EffectorMode.PositionOffset) {
foreach (Warp warp in warps) {
ik.solver.GetEffector(warp.effector).positionWeight = 0f;
}
}
lastMode = effectorMode;
}
// Set effector positionWeights to 0 if in "Position" effector mode
void OnDisable() {
if (effectorMode != EffectorMode.Position) return;
foreach (Warp warp in warps) {
ik.solver.GetEffector(warp.effector).positionWeight = 0f;
}
}
}
}