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

245 lines
5.3 KiB
C#

using System;
using UnityEngine;
namespace RootMotion.FinalIK
{
[Serializable]
public class IKSolverFABRIKRoot : IKSolver
{
public int iterations = 4;
[Range(0f, 1f)]
public float rootPin;
public FABRIKChain[] chains = new FABRIKChain[0];
private bool zeroWeightApplied;
private bool[] isRoot;
private Vector3 rootDefaultPosition;
public override bool IsValid(ref string message)
{
if (chains.Length == 0)
{
message = "IKSolverFABRIKRoot contains no chains.";
return false;
}
FABRIKChain[] array = chains;
for (int i = 0; i < array.Length; i++)
{
if (!array[i].IsValid(ref message))
{
return false;
}
}
for (int j = 0; j < chains.Length; j++)
{
for (int k = 0; k < chains.Length; k++)
{
if (j != k && chains[j].ik == chains[k].ik)
{
message = chains[j].ik.name + " is represented more than once in IKSolverFABRIKRoot chain.";
return false;
}
}
}
for (int l = 0; l < chains.Length; l++)
{
for (int m = 0; m < chains[l].children.Length; m++)
{
int num = chains[l].children[m];
if (num < 0)
{
message = chains[l].ik.name + "IKSolverFABRIKRoot chain at index " + l + " has invalid children array. Child index is < 0.";
return false;
}
if (num == l)
{
message = chains[l].ik.name + "IKSolverFABRIKRoot chain at index " + l + " has invalid children array. Child index is referencing to itself.";
return false;
}
if (num >= chains.Length)
{
message = chains[l].ik.name + "IKSolverFABRIKRoot chain at index " + l + " has invalid children array. Child index > number of chains";
return false;
}
for (int n = 0; n < chains.Length; n++)
{
if (num != n)
{
continue;
}
for (int num2 = 0; num2 < chains[n].children.Length; num2++)
{
if (chains[n].children[num2] == l)
{
message = "Circular parenting. " + chains[n].ik.name + " already has " + chains[l].ik.name + " listed as it's child.";
return false;
}
}
}
for (int num3 = 0; num3 < chains[l].children.Length; num3++)
{
if (m != num3 && chains[l].children[num3] == num)
{
message = "Chain number " + num + " is represented more than once in the children of " + chains[l].ik.name;
return false;
}
}
}
}
return true;
}
public override void StoreDefaultLocalState()
{
rootDefaultPosition = root.localPosition;
for (int i = 0; i < chains.Length; i++)
{
chains[i].ik.solver.StoreDefaultLocalState();
}
}
public override void FixTransforms()
{
if (base.initiated)
{
root.localPosition = rootDefaultPosition;
for (int i = 0; i < chains.Length; i++)
{
chains[i].ik.solver.FixTransforms();
}
}
}
protected override void OnInitiate()
{
for (int i = 0; i < chains.Length; i++)
{
chains[i].Initiate();
}
isRoot = new bool[chains.Length];
for (int j = 0; j < chains.Length; j++)
{
isRoot[j] = IsRoot(j);
}
}
private bool IsRoot(int index)
{
for (int i = 0; i < chains.Length; i++)
{
for (int j = 0; j < chains[i].children.Length; j++)
{
if (chains[i].children[j] == index)
{
return false;
}
}
}
return true;
}
protected override void OnUpdate()
{
if (IKPositionWeight <= 0f && zeroWeightApplied)
{
return;
}
IKPositionWeight = Mathf.Clamp(IKPositionWeight, 0f, 1f);
for (int i = 0; i < chains.Length; i++)
{
chains[i].ik.solver.IKPositionWeight = IKPositionWeight;
}
if (IKPositionWeight <= 0f)
{
zeroWeightApplied = true;
return;
}
zeroWeightApplied = false;
for (int j = 0; j < iterations; j++)
{
for (int k = 0; k < chains.Length; k++)
{
if (isRoot[k])
{
chains[k].Stage1(chains);
}
}
Vector3 centroid = GetCentroid();
root.position = centroid;
for (int l = 0; l < chains.Length; l++)
{
if (isRoot[l])
{
chains[l].Stage2(centroid, chains);
}
}
}
}
public override Point[] GetPoints()
{
Point[] array = new Point[0];
for (int i = 0; i < chains.Length; i++)
{
AddPointsToArray(ref array, chains[i]);
}
return array;
}
public override Point GetPoint(Transform transform)
{
Point point = null;
for (int i = 0; i < chains.Length; i++)
{
point = chains[i].ik.solver.GetPoint(transform);
if (point != null)
{
return point;
}
}
return null;
}
private void AddPointsToArray(ref Point[] array, FABRIKChain chain)
{
Point[] points = chain.ik.solver.GetPoints();
Array.Resize(ref array, array.Length + points.Length);
int num = 0;
for (int i = array.Length - points.Length; i < array.Length; i++)
{
array[i] = points[num];
num++;
}
}
private Vector3 GetCentroid()
{
Vector3 position = root.position;
if (rootPin >= 1f)
{
return position;
}
float num = 0f;
for (int i = 0; i < chains.Length; i++)
{
if (isRoot[i])
{
num += chains[i].pull;
}
}
for (int j = 0; j < chains.Length; j++)
{
if (isRoot[j] && num > 0f)
{
position += (chains[j].ik.solver.bones[0].solverPosition - root.position) * (chains[j].pull / Mathf.Clamp(num, 1f, num));
}
}
return Vector3.Lerp(position, root.position, rootPin);
}
}
}