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#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								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;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |