Files
2026-03-04 09:37:33 +08:00

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));
}
}
}
}