123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- using UnityEngine;
- using System.Collections;
- using System;
- namespace RootMotion.FinalIK {
- /// <summary>
- /// %IK system for multiple branched %FABRIK chains.
- /// </summary>
- [System.Serializable]
- public class IKSolverFABRIKRoot : IKSolver {
-
- #region Main Interface
- /// <summary>
- /// Solver iterations.
- /// </summary>
- public int iterations = 4;
- /// <summary>
- /// The weight of all chains being pinned to root position.
- /// </summary>
- [Range(0f, 1f)]
- public float rootPin = 0f;
- /// <summary>
- /// The %FABRIK chains.
- /// </summary>
- public FABRIKChain[] chains = new FABRIKChain[0];
- public override bool IsValid(ref string message) {
- if (chains.Length == 0) {
- message = "IKSolverFABRIKRoot contains no chains.";
- return false;
- }
- foreach (FABRIKChain chain in chains) {
- if (!chain.IsValid(ref message)) return false;
- }
- for (int i = 0; i < chains.Length; i++) {
- for (int c = 0; c < chains.Length; c++) {
- if (i != c && chains[i].ik == chains[c].ik) {
- message = chains[i].ik.name + " is represented more than once in IKSolverFABRIKRoot chain.";
- return false;
- }
- }
- }
- // Check the children
- for (int i = 0; i < chains.Length; i++) {
- for (int c = 0; c < chains[i].children.Length; c++) {
- int childIndex = chains[i].children[c];
- if (childIndex < 0) {
- message = chains[i].ik.name + "IKSolverFABRIKRoot chain at index " + i + " has invalid children array. Child index is < 0.";
- return false;
- }
- if (childIndex == i) {
- message = chains[i].ik.name + "IKSolverFABRIKRoot chain at index " + i + " has invalid children array. Child index is referencing to itself.";
- return false;
- }
- if (childIndex >= chains.Length) {
- message = chains[i].ik.name + "IKSolverFABRIKRoot chain at index " + i + " has invalid children array. Child index > number of chains";
- return false;
- }
- // Check if the child chain doesn't have this chain among it's children
- for (int o = 0; o < chains.Length; o++) {
- if (childIndex == o) {
- for (int n = 0; n < chains[o].children.Length; n++) {
- if (chains[o].children[n] == i) {
- message = "Circular parenting. " + chains[o].ik.name + " already has " + chains[i].ik.name + " listed as it's child.";
- return false;
- }
- }
- }
- }
- // Check for duplicates
- for (int n = 0; n < chains[i].children.Length; n++) {
- if (c != n && chains[i].children[n] == childIndex) {
- message = "Chain number " + childIndex + " is represented more than once in the children of " + chains[i].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 (!initiated) return;
- root.localPosition = rootDefaultPosition;
- for (int i = 0; i < chains.Length; i++) chains[i].ik.solver.FixTransforms();
- }
-
- #endregion Main Interface
-
- private bool zeroWeightApplied;
- private bool[] isRoot;
- private Vector3 rootDefaultPosition;
- protected override void OnInitiate() {
- for (int i = 0; i < chains.Length; i++) chains[i].Initiate();
- isRoot = new bool[chains.Length];
- for (int i = 0; i < chains.Length; i++) {
- isRoot[i] = IsRoot(i);
- }
- }
- // Is the chain at index a root chain (not parented by any other chains)?
- private bool IsRoot(int index) {
- for (int i = 0; i < chains.Length; i++) {
- for (int c = 0; c < chains[i].children.Length; c++) {
- if (chains[i].children[c] == index) return false;
- }
- }
- return true;
- }
- protected override void OnUpdate() {
- if (IKPositionWeight <= 0 && zeroWeightApplied) return;
- IKPositionWeight = Mathf.Clamp(IKPositionWeight, 0f, 1f);
-
- // Set weight of all IK solvers
- for (int i = 0; i < chains.Length; i++) chains[i].ik.solver.IKPositionWeight = IKPositionWeight;
-
- if (IKPositionWeight <= 0) {
- zeroWeightApplied = true;
- return;
- }
-
- zeroWeightApplied = false;
-
- for (int i = 0; i < iterations; i++) {
- // Solve trees from their targets
- for (int c = 0; c < chains.Length; c++) {
- if (isRoot[c]) chains[c].Stage1(chains);
- }
-
- // Get centroid of all tree roots
- Vector3 centroid = GetCentroid();
- root.position = centroid;
- // Start all trees from the centroid
- for (int c = 0; c < chains.Length; c++) {
- if (isRoot[c]) chains[c].Stage2(centroid, chains);
- }
- }
- }
-
- public override IKSolver.Point[] GetPoints() {
- IKSolver.Point[] array = new IKSolver.Point[0];
- for (int i = 0; i < chains.Length; i++) AddPointsToArray(ref array, chains[i]);
- return array;
- }
-
- public override IKSolver.Point GetPoint(Transform transform) {
- IKSolver.Point p = null;
- for (int i = 0; i < chains.Length; i++) {
- p = chains[i].ik.solver.GetPoint(transform);
- if (p != null) return p;
- }
-
- return null;
- }
-
- private void AddPointsToArray(ref IKSolver.Point[] array, FABRIKChain chain) {
- IKSolver.Point[] chainArray = chain.ik.solver.GetPoints();
- Array.Resize(ref array, array.Length + chainArray.Length);
-
- int a = 0;
- for (int i = array.Length - chainArray.Length; i < array.Length; i++) {
- array[i] = chainArray[a];
- a++;
- }
- }
-
- /*
- * Gets the centroid position of all chains respective of their pull weights
- * */
- private Vector3 GetCentroid() {
- Vector3 centroid = root.position;
- if (rootPin >= 1) return centroid;
- float pullSum = 0f;
- for (int i = 0; i < chains.Length; i++) {
- if (isRoot[i]) pullSum += chains[i].pull;
- }
-
- for (int i = 0; i < chains.Length; i++) {
- if (isRoot[i] && pullSum > 0) centroid += (chains[i].ik.solver.bones[0].solverPosition - root.position) * (chains[i].pull / Mathf.Clamp(pullSum, 1f, pullSum));
- }
- return Vector3.Lerp(centroid, root.position, rootPin);
- }
- }
- }
|