128 lines
4.5 KiB
C#
128 lines
4.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|