187 lines
5.0 KiB
C#
187 lines
5.0 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace RootMotion.FinalIK
|
|
{
|
|
[HelpURL("http://www.root-motion.com/finalikdox/html/page9.html")]
|
|
[AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder Biped")]
|
|
public class GrounderBipedIK : Grounder
|
|
{
|
|
[Tooltip("The BipedIK componet.")]
|
|
public BipedIK ik;
|
|
|
|
[Tooltip("The amount of spine bending towards upward slopes.")]
|
|
public float spineBend = 7f;
|
|
|
|
[Tooltip("The interpolation speed of spine bending.")]
|
|
public float spineSpeed = 3f;
|
|
|
|
private Transform[] feet = new Transform[2];
|
|
|
|
private Quaternion[] footRotations = new Quaternion[2];
|
|
|
|
private Vector3 animatedPelvisLocalPosition;
|
|
|
|
private Vector3 solvedPelvisLocalPosition;
|
|
|
|
private Vector3 spineOffset;
|
|
|
|
private float lastWeight;
|
|
|
|
[ContextMenu("User Manual")]
|
|
protected override void OpenUserManual()
|
|
{
|
|
Application.OpenURL("http://www.root-motion.com/finalikdox/html/page9.html");
|
|
}
|
|
|
|
[ContextMenu("Scrpt Reference")]
|
|
protected override void OpenScriptReference()
|
|
{
|
|
Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_final_i_k_1_1_grounder_biped_i_k.html");
|
|
}
|
|
|
|
public override void ResetPosition()
|
|
{
|
|
solver.Reset();
|
|
spineOffset = Vector3.zero;
|
|
}
|
|
|
|
private bool IsReadyToInitiate()
|
|
{
|
|
if (ik == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (!ik.solvers.leftFoot.initiated)
|
|
{
|
|
return false;
|
|
}
|
|
if (!ik.solvers.rightFoot.initiated)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
weight = Mathf.Clamp(weight, 0f, 1f);
|
|
if (!(weight <= 0f) && !base.initiated && IsReadyToInitiate())
|
|
{
|
|
Initiate();
|
|
}
|
|
}
|
|
|
|
private void Initiate()
|
|
{
|
|
feet = new Transform[2];
|
|
footRotations = new Quaternion[2];
|
|
feet[0] = ik.references.leftFoot;
|
|
feet[1] = ik.references.rightFoot;
|
|
footRotations[0] = Quaternion.identity;
|
|
footRotations[1] = Quaternion.identity;
|
|
IKSolverFABRIK spine = ik.solvers.spine;
|
|
spine.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(spine.OnPreUpdate, new IKSolver.UpdateDelegate(OnSolverUpdate));
|
|
IKSolverLimb rightFoot = ik.solvers.rightFoot;
|
|
rightFoot.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(rightFoot.OnPostUpdate, new IKSolver.UpdateDelegate(OnPostSolverUpdate));
|
|
animatedPelvisLocalPosition = ik.references.pelvis.localPosition;
|
|
solver.Initiate(ik.references.root, feet);
|
|
base.initiated = true;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (base.initiated)
|
|
{
|
|
ik.solvers.leftFoot.IKPositionWeight = 0f;
|
|
ik.solvers.rightFoot.IKPositionWeight = 0f;
|
|
}
|
|
}
|
|
|
|
private void OnSolverUpdate()
|
|
{
|
|
if (!base.enabled)
|
|
{
|
|
return;
|
|
}
|
|
if (weight <= 0f)
|
|
{
|
|
if (lastWeight <= 0f)
|
|
{
|
|
return;
|
|
}
|
|
OnDisable();
|
|
}
|
|
lastWeight = weight;
|
|
if (OnPreGrounder != null)
|
|
{
|
|
OnPreGrounder();
|
|
}
|
|
if (ik.references.pelvis.localPosition != solvedPelvisLocalPosition)
|
|
{
|
|
animatedPelvisLocalPosition = ik.references.pelvis.localPosition;
|
|
}
|
|
else
|
|
{
|
|
ik.references.pelvis.localPosition = animatedPelvisLocalPosition;
|
|
}
|
|
solver.Update();
|
|
ik.references.pelvis.position += solver.pelvis.IKOffset * weight;
|
|
SetLegIK(ik.solvers.leftFoot, 0);
|
|
SetLegIK(ik.solvers.rightFoot, 1);
|
|
if (spineBend != 0f && ik.references.spine.Length != 0)
|
|
{
|
|
spineSpeed = Mathf.Clamp(spineSpeed, 0f, spineSpeed);
|
|
Vector3 vector = GetSpineOffsetTarget() * weight;
|
|
spineOffset = Vector3.Lerp(spineOffset, vector * spineBend, Time.deltaTime * spineSpeed);
|
|
Quaternion rotation = ik.references.leftUpperArm.rotation;
|
|
Quaternion rotation2 = ik.references.rightUpperArm.rotation;
|
|
Vector3 up = solver.up;
|
|
Quaternion quaternion = Quaternion.FromToRotation(up, up + spineOffset);
|
|
ik.references.spine[0].rotation = quaternion * ik.references.spine[0].rotation;
|
|
ik.references.leftUpperArm.rotation = rotation;
|
|
ik.references.rightUpperArm.rotation = rotation2;
|
|
ik.solvers.lookAt.SetDirty();
|
|
}
|
|
if (OnPostGrounder != null)
|
|
{
|
|
OnPostGrounder();
|
|
}
|
|
}
|
|
|
|
private void SetLegIK(IKSolverLimb limb, int index)
|
|
{
|
|
footRotations[index] = feet[index].rotation;
|
|
limb.IKPosition = solver.legs[index].IKPosition;
|
|
limb.IKPositionWeight = weight;
|
|
}
|
|
|
|
private void OnPostSolverUpdate()
|
|
{
|
|
if (!(weight <= 0f) && base.enabled)
|
|
{
|
|
for (int i = 0; i < feet.Length; i++)
|
|
{
|
|
feet[i].rotation = Quaternion.Slerp(Quaternion.identity, solver.legs[i].rotationOffset, weight) * footRotations[i];
|
|
}
|
|
solvedPelvisLocalPosition = ik.references.pelvis.localPosition;
|
|
if (OnPostIK != null)
|
|
{
|
|
OnPostIK();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (base.initiated && ik != null)
|
|
{
|
|
IKSolverFABRIK spine = ik.solvers.spine;
|
|
spine.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(spine.OnPreUpdate, new IKSolver.UpdateDelegate(OnSolverUpdate));
|
|
IKSolverLimb rightFoot = ik.solvers.rightFoot;
|
|
rightFoot.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(rightFoot.OnPostUpdate, new IKSolver.UpdateDelegate(OnPostSolverUpdate));
|
|
}
|
|
}
|
|
}
|
|
}
|