Files
2026-03-04 10:03:45 +08:00

401 lines
7.9 KiB
C#

using System;
using UnityEngine;
namespace RootMotion.FinalIK
{
[Serializable]
public class IKSolverFullBody : IKSolver
{
[Range(0f, 10f)]
public int iterations = 4;
public FBIKChain[] chain = new FBIKChain[0];
public IKEffector[] effectors = new IKEffector[0];
public IKMappingSpine spineMapping = new IKMappingSpine();
public IKMappingBone[] boneMappings = new IKMappingBone[0];
public IKMappingLimb[] limbMappings = new IKMappingLimb[0];
public bool FABRIKPass = true;
public UpdateDelegate OnPreRead;
public UpdateDelegate OnPreSolve;
public IterationDelegate OnPreIteration;
public IterationDelegate OnPostIteration;
public UpdateDelegate OnPreBend;
public UpdateDelegate OnPostSolve;
public UpdateDelegate OnStoreDefaultLocalState;
public UpdateDelegate OnFixTransforms;
public IKEffector GetEffector(Transform t)
{
for (int i = 0; i < effectors.Length; i++)
{
if (effectors[i].bone == t)
{
return effectors[i];
}
}
return null;
}
public FBIKChain GetChain(Transform transform)
{
int chainIndex = GetChainIndex(transform);
if (chainIndex == -1)
{
return null;
}
return chain[chainIndex];
}
public int GetChainIndex(Transform transform)
{
for (int i = 0; i < chain.Length; i++)
{
for (int j = 0; j < chain[i].nodes.Length; j++)
{
if (chain[i].nodes[j].transform == transform)
{
return i;
}
}
}
return -1;
}
public Node GetNode(int chainIndex, int nodeIndex)
{
return chain[chainIndex].nodes[nodeIndex];
}
public void GetChainAndNodeIndexes(Transform transform, out int chainIndex, out int nodeIndex)
{
chainIndex = GetChainIndex(transform);
if (chainIndex == -1)
{
nodeIndex = -1;
}
else
{
nodeIndex = chain[chainIndex].GetNodeIndex(transform);
}
}
public override Point[] GetPoints()
{
int num = 0;
for (int i = 0; i < chain.Length; i++)
{
num += chain[i].nodes.Length;
}
Point[] array = new Point[num];
int num2 = 0;
for (int j = 0; j < chain.Length; j++)
{
for (int k = 0; k < chain[j].nodes.Length; k++)
{
array[num2] = chain[j].nodes[k];
num2++;
}
}
return array;
}
public override Point GetPoint(Transform transform)
{
for (int i = 0; i < chain.Length; i++)
{
for (int j = 0; j < chain[i].nodes.Length; j++)
{
if (chain[i].nodes[j].transform == transform)
{
return chain[i].nodes[j];
}
}
}
return null;
}
public override bool IsValid(ref string message)
{
if (chain == null)
{
message = "FBIK chain is null, can't initiate solver.";
return false;
}
if (chain.Length == 0)
{
message = "FBIK chain length is 0, can't initiate solver.";
return false;
}
for (int i = 0; i < chain.Length; i++)
{
if (!chain[i].IsValid(ref message))
{
return false;
}
}
IKEffector[] array = effectors;
for (int j = 0; j < array.Length; j++)
{
if (!array[j].IsValid(this, ref message))
{
return false;
}
}
if (!spineMapping.IsValid(this, ref message))
{
return false;
}
IKMappingLimb[] array2 = limbMappings;
for (int j = 0; j < array2.Length; j++)
{
if (!array2[j].IsValid(this, ref message))
{
return false;
}
}
IKMappingBone[] array3 = boneMappings;
for (int j = 0; j < array3.Length; j++)
{
if (!array3[j].IsValid(this, ref message))
{
return false;
}
}
return true;
}
public override void StoreDefaultLocalState()
{
spineMapping.StoreDefaultLocalState();
for (int i = 0; i < limbMappings.Length; i++)
{
limbMappings[i].StoreDefaultLocalState();
}
for (int j = 0; j < boneMappings.Length; j++)
{
boneMappings[j].StoreDefaultLocalState();
}
if (OnStoreDefaultLocalState != null)
{
OnStoreDefaultLocalState();
}
}
public override void FixTransforms()
{
if (base.initiated && !(IKPositionWeight <= 0f))
{
spineMapping.FixTransforms();
for (int i = 0; i < limbMappings.Length; i++)
{
limbMappings[i].FixTransforms();
}
for (int j = 0; j < boneMappings.Length; j++)
{
boneMappings[j].FixTransforms();
}
if (OnFixTransforms != null)
{
OnFixTransforms();
}
}
}
protected override void OnInitiate()
{
for (int i = 0; i < chain.Length; i++)
{
chain[i].Initiate(this);
}
IKEffector[] array = effectors;
for (int j = 0; j < array.Length; j++)
{
array[j].Initiate(this);
}
spineMapping.Initiate(this);
IKMappingBone[] array2 = boneMappings;
for (int j = 0; j < array2.Length; j++)
{
array2[j].Initiate(this);
}
IKMappingLimb[] array3 = limbMappings;
for (int j = 0; j < array3.Length; j++)
{
array3[j].Initiate(this);
}
}
protected override void OnUpdate()
{
if (IKPositionWeight <= 0f)
{
for (int i = 0; i < effectors.Length; i++)
{
effectors[i].positionOffset = Vector3.zero;
}
}
else if (chain.Length != 0)
{
IKPositionWeight = Mathf.Clamp(IKPositionWeight, 0f, 1f);
if (OnPreRead != null)
{
OnPreRead();
}
ReadPose();
if (OnPreSolve != null)
{
OnPreSolve();
}
Solve();
if (OnPostSolve != null)
{
OnPostSolve();
}
WritePose();
for (int j = 0; j < effectors.Length; j++)
{
effectors[j].OnPostWrite();
}
}
}
protected virtual void ReadPose()
{
for (int i = 0; i < chain.Length; i++)
{
if (chain[i].bendConstraint.initiated)
{
chain[i].bendConstraint.LimitBend(IKPositionWeight, GetEffector(chain[i].nodes[2].transform).positionWeight);
}
}
for (int j = 0; j < effectors.Length; j++)
{
effectors[j].ResetOffset(this);
}
for (int k = 0; k < effectors.Length; k++)
{
effectors[k].OnPreSolve(this);
}
for (int l = 0; l < chain.Length; l++)
{
chain[l].ReadPose(this, iterations > 0);
}
if (iterations > 0)
{
spineMapping.ReadPose();
for (int m = 0; m < boneMappings.Length; m++)
{
boneMappings[m].ReadPose();
}
}
for (int n = 0; n < limbMappings.Length; n++)
{
limbMappings[n].ReadPose();
}
}
protected virtual void Solve()
{
if (iterations > 0)
{
for (int i = 0; i < ((!FABRIKPass) ? 1 : iterations); i++)
{
if (OnPreIteration != null)
{
OnPreIteration(i);
}
for (int j = 0; j < effectors.Length; j++)
{
if (effectors[j].isEndEffector)
{
effectors[j].Update(this);
}
}
if (FABRIKPass)
{
chain[0].Push(this);
if (FABRIKPass)
{
chain[0].Reach(this);
}
for (int k = 0; k < effectors.Length; k++)
{
if (!effectors[k].isEndEffector)
{
effectors[k].Update(this);
}
}
}
chain[0].SolveTrigonometric(this);
if (FABRIKPass)
{
chain[0].Stage1(this);
for (int l = 0; l < effectors.Length; l++)
{
if (!effectors[l].isEndEffector)
{
effectors[l].Update(this);
}
}
chain[0].Stage2(this, chain[0].nodes[0].solverPosition);
}
if (OnPostIteration != null)
{
OnPostIteration(i);
}
}
}
if (OnPreBend != null)
{
OnPreBend();
}
for (int m = 0; m < effectors.Length; m++)
{
if (effectors[m].isEndEffector)
{
effectors[m].Update(this);
}
}
ApplyBendConstraints();
}
protected virtual void ApplyBendConstraints()
{
chain[0].SolveTrigonometric(this, calculateBendDirection: true);
}
protected virtual void WritePose()
{
if (IKPositionWeight <= 0f)
{
return;
}
if (iterations > 0)
{
spineMapping.WritePose(this);
for (int i = 0; i < boneMappings.Length; i++)
{
boneMappings[i].WritePose(IKPositionWeight);
}
}
for (int j = 0; j < limbMappings.Length; j++)
{
limbMappings[j].WritePose(this, iterations > 0);
}
}
}
}