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.
		
		
		
		
		
			
		
			
				
	
	
		
			197 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			197 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C#
		
	
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
 | 
						|
namespace RootMotion.FinalIK {
 | 
						|
 | 
						|
	/// <summary>
 | 
						|
	/// Grounding for BipedIK characters.
 | 
						|
	/// </summary>
 | 
						|
	[HelpURL("http://www.root-motion.com/finalikdox/html/page9.html")]
 | 
						|
	[AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder Biped")]
 | 
						|
	public class GrounderBipedIK: Grounder {
 | 
						|
 | 
						|
		// Open the User Manual URL
 | 
						|
		[ContextMenu("User Manual")]
 | 
						|
		protected override void OpenUserManual() {
 | 
						|
			Application.OpenURL("http://www.root-motion.com/finalikdox/html/page9.html");
 | 
						|
		}
 | 
						|
		
 | 
						|
		// Open the Script Reference URL
 | 
						|
		[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");
 | 
						|
		}
 | 
						|
 | 
						|
		#region Main Interface
 | 
						|
		
 | 
						|
		/// <summary>
 | 
						|
		/// The BipedIK componet.
 | 
						|
		/// </summary>
 | 
						|
		[Tooltip("The BipedIK componet.")]
 | 
						|
		public BipedIK ik;
 | 
						|
		/// <summary>
 | 
						|
		/// The amount of spine bending towards upward slopes.
 | 
						|
		/// </summary>
 | 
						|
		[Tooltip("The amount of spine bending towards upward slopes.")]
 | 
						|
		public float spineBend = 7f;
 | 
						|
		/// <summary>
 | 
						|
		/// The interpolation speed of spine bending.
 | 
						|
		/// </summary>
 | 
						|
		[Tooltip("The interpolation speed of spine bending.")]
 | 
						|
		public float spineSpeed = 3f;
 | 
						|
 | 
						|
		#endregion Main Interface
 | 
						|
 | 
						|
		public override void ResetPosition() {
 | 
						|
			solver.Reset();
 | 
						|
			spineOffset = Vector3.zero;
 | 
						|
		}
 | 
						|
		
 | 
						|
		private Transform[] feet = new Transform[2];
 | 
						|
		private Quaternion[] footRotations = new Quaternion[2];
 | 
						|
		private Vector3 animatedPelvisLocalPosition, solvedPelvisLocalPosition;
 | 
						|
		private Vector3 spineOffset;
 | 
						|
		private float lastWeight;
 | 
						|
 | 
						|
		// Can we initiate the Grounding?
 | 
						|
		private bool IsReadyToInitiate() {
 | 
						|
			if (ik == null) return false;
 | 
						|
			if (!ik.solvers.leftFoot.initiated) return false;
 | 
						|
			if (!ik.solvers.rightFoot.initiated) return false;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		// Initiate once we have a BipedIK component
 | 
						|
		void Update() {
 | 
						|
			weight = Mathf.Clamp(weight, 0f, 1f);
 | 
						|
			if (weight <= 0f) return;
 | 
						|
 | 
						|
			if (initiated) return;
 | 
						|
			if (!IsReadyToInitiate()) return;
 | 
						|
			
 | 
						|
			Initiate();
 | 
						|
		}
 | 
						|
		
 | 
						|
		private void Initiate() {
 | 
						|
			// Gathering both foot bones from the BipedIK
 | 
						|
			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;
 | 
						|
 | 
						|
			// Adding to the delegates to get call at certain points in the solving process
 | 
						|
			ik.solvers.spine.OnPreUpdate += OnSolverUpdate;
 | 
						|
			ik.solvers.rightFoot.OnPostUpdate += OnPostSolverUpdate;
 | 
						|
 | 
						|
			// Store the default localPosition of the pelvis
 | 
						|
			animatedPelvisLocalPosition = ik.references.pelvis.localPosition;
 | 
						|
 | 
						|
			// Initiate the Grounding
 | 
						|
			solver.Initiate(ik.references.root, feet);
 | 
						|
			
 | 
						|
			initiated = true;
 | 
						|
		}
 | 
						|
 | 
						|
		// Weigh out the limb solvers properly when the component is disabled
 | 
						|
		void OnDisable() {
 | 
						|
			if (!initiated) return;
 | 
						|
 | 
						|
			ik.solvers.leftFoot.IKPositionWeight = 0f;
 | 
						|
			ik.solvers.rightFoot.IKPositionWeight = 0f;
 | 
						|
		}
 | 
						|
 | 
						|
		// Called before updating the spine IK solver
 | 
						|
		private void OnSolverUpdate() {
 | 
						|
			if (!enabled) return;
 | 
						|
 | 
						|
			if (weight <= 0f) {
 | 
						|
				if (lastWeight <= 0f) return;
 | 
						|
 | 
						|
				// Weigh out the limb solvers properly
 | 
						|
				OnDisable();
 | 
						|
			}
 | 
						|
 | 
						|
			lastWeight = weight;
 | 
						|
 | 
						|
			if (OnPreGrounder != null) OnPreGrounder();
 | 
						|
 | 
						|
			// If the pelvis local position has not changed since last solved state, consider it unanimated
 | 
						|
			if (ik.references.pelvis.localPosition != solvedPelvisLocalPosition) animatedPelvisLocalPosition = ik.references.pelvis.localPosition;
 | 
						|
			else ik.references.pelvis.localPosition = animatedPelvisLocalPosition;
 | 
						|
 | 
						|
			// Update the Grounding
 | 
						|
			solver.Update();
 | 
						|
 | 
						|
			// Move the pelvis
 | 
						|
			ik.references.pelvis.position += solver.pelvis.IKOffset * weight;
 | 
						|
 | 
						|
			// Update IKPositions and IKPositionWeights of the feet
 | 
						|
			SetLegIK(ik.solvers.leftFoot, 0);
 | 
						|
			SetLegIK(ik.solvers.rightFoot, 1);
 | 
						|
 | 
						|
			// Bending the spine
 | 
						|
			if (spineBend != 0f && ik.references.spine.Length > 0) {
 | 
						|
				spineSpeed = Mathf.Clamp(spineSpeed, 0f, spineSpeed);
 | 
						|
 | 
						|
				Vector3 spineOffseTarget = GetSpineOffsetTarget() * weight;
 | 
						|
				spineOffset = Vector3.Lerp(spineOffset, spineOffseTarget * spineBend, Time.deltaTime * spineSpeed);
 | 
						|
 | 
						|
				// Store upper arm rotations to revert them after we rotate the spine
 | 
						|
				Quaternion leftArmRotation = ik.references.leftUpperArm.rotation;
 | 
						|
				Quaternion rightArmRotation = ik.references.rightUpperArm.rotation;
 | 
						|
 | 
						|
				// Get the offset rotation for the spine
 | 
						|
				Vector3 up = solver.up;
 | 
						|
				Quaternion f = Quaternion.FromToRotation(up, up + spineOffset);
 | 
						|
 | 
						|
				// Rotate the spine
 | 
						|
				ik.references.spine[0].rotation = f * ik.references.spine[0].rotation;
 | 
						|
 | 
						|
				// Revert the upper arms
 | 
						|
				ik.references.leftUpperArm.rotation = leftArmRotation;
 | 
						|
				ik.references.rightUpperArm.rotation = rightArmRotation;
 | 
						|
 | 
						|
                ik.solvers.lookAt.SetDirty();
 | 
						|
			}
 | 
						|
 | 
						|
			if (OnPostGrounder != null) OnPostGrounder();
 | 
						|
		}
 | 
						|
 | 
						|
		// Set the IK position and weight for a limb
 | 
						|
		private void SetLegIK(IKSolverLimb limb, int index) {
 | 
						|
			footRotations[index] = feet[index].rotation;
 | 
						|
 | 
						|
			limb.IKPosition = solver.legs[index].IKPosition;
 | 
						|
			limb.IKPositionWeight = weight;
 | 
						|
		}
 | 
						|
 | 
						|
		// Rotating the feet after IK has finished
 | 
						|
		private void OnPostSolverUpdate() {
 | 
						|
			if (weight <= 0f) return;
 | 
						|
			if (!enabled) return;
 | 
						|
 | 
						|
			for (int i = 0; i < feet.Length; i++) {
 | 
						|
				feet[i].rotation = Quaternion.Slerp(Quaternion.identity, solver.legs[i].rotationOffset, weight) * footRotations[i];
 | 
						|
			}
 | 
						|
 | 
						|
			// Store the local position of the pelvis so we know it it changes
 | 
						|
			solvedPelvisLocalPosition = ik.references.pelvis.localPosition;
 | 
						|
 | 
						|
            if (OnPostIK != null) OnPostIK();
 | 
						|
		}
 | 
						|
 | 
						|
		// Cleaning up the delegates
 | 
						|
		void OnDestroy() {
 | 
						|
			if (initiated && ik != null) {
 | 
						|
				ik.solvers.spine.OnPreUpdate -= OnSolverUpdate;
 | 
						|
				ik.solvers.rightFoot.OnPostUpdate -= OnPostSolverUpdate;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 |