You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
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 its 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 its 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);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |