initial upload
This commit is contained in:
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24b4e6f1f9c204bc5bd16676aecf434d
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,317 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %IK system for standard biped characters that is designed to replicate and enhance the behaviour of the Unity's built-in character %IK setup.
|
||||
/// </summary>
|
||||
[HelpURL("http://www.root-motion.com/finalikdox/html/page4.html")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/IK/Biped IK")]
|
||||
public class BipedIK : SolverManager {
|
||||
|
||||
// Open the User Manual URL
|
||||
[ContextMenu("User Manual")]
|
||||
private void OpenUserManual() {
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/page4.html");
|
||||
}
|
||||
|
||||
// Open the Script Reference URL
|
||||
[ContextMenu("Scrpt Reference")]
|
||||
private void OpenScriptReference() {
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_final_i_k_1_1_biped_i_k.html");
|
||||
}
|
||||
|
||||
// Link to the Final IK Google Group
|
||||
[ContextMenu("Support Group")]
|
||||
void SupportGroup() {
|
||||
Application.OpenURL("https://groups.google.com/forum/#!forum/final-ik");
|
||||
}
|
||||
|
||||
// Link to the Final IK Asset Store thread in the Unity Community
|
||||
[ContextMenu("Asset Store Thread")]
|
||||
void ASThread() {
|
||||
Application.OpenURL("http://forum.unity3d.com/threads/final-ik-full-body-ik-aim-look-at-fabrik-ccd-ik-1-0-released.222685/");
|
||||
}
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// References to character bones.
|
||||
/// </summary>
|
||||
public BipedReferences references = new BipedReferences();
|
||||
/// <summary>
|
||||
/// The %IK solvers.
|
||||
/// </summary>
|
||||
public BipedIKSolvers solvers = new BipedIKSolvers();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK position weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public float GetIKPositionWeight(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKPositionWeight();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK rotation weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// IK Goal.
|
||||
/// </param>
|
||||
public float GetIKRotationWeight(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKRotationWeight();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK position weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetIKPositionWeight(AvatarIKGoal goal, float weight) {
|
||||
GetGoalIK(goal).SetIKPositionWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK rotation weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetIKRotationWeight(AvatarIKGoal goal, float weight) {
|
||||
GetGoalIK(goal).SetIKRotationWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK position.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='IKPosition'>
|
||||
/// Position.
|
||||
/// </param>
|
||||
public void SetIKPosition(AvatarIKGoal goal, Vector3 IKPosition) {
|
||||
GetGoalIK(goal).SetIKPosition(IKPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK rotation.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='IKRotation'>
|
||||
/// Rotation.
|
||||
/// </param>
|
||||
public void SetIKRotation(AvatarIKGoal goal, Quaternion IKRotation) {
|
||||
GetGoalIK(goal).SetIKRotation(IKRotation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK position.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public Vector3 GetIKPosition(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKPosition();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK rotation.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public Quaternion GetIKRotation(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKRotation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the look at weight.
|
||||
/// </summary>
|
||||
/// <param name='weight'>
|
||||
/// Master Weight.
|
||||
/// </param>
|
||||
/// <param name='bodyWeight'>
|
||||
/// Body weight.
|
||||
/// </param>
|
||||
/// <param name='headWeight'>
|
||||
/// Head weight.
|
||||
/// </param>
|
||||
/// <param name='eyesWeight'>
|
||||
/// Eyes weight.
|
||||
/// </param>
|
||||
/// <param name='clampWeight'>
|
||||
/// Clamp weight for body and head.
|
||||
/// </param>
|
||||
/// <param name='clampWeightEyes'>
|
||||
/// Clamp weight for eyes.
|
||||
/// </param>
|
||||
public void SetLookAtWeight(float weight, float bodyWeight , float headWeight, float eyesWeight, float clampWeight, float clampWeightHead, float clampWeightEyes) {
|
||||
solvers.lookAt.SetLookAtWeight(weight, bodyWeight, headWeight, eyesWeight, clampWeight, clampWeightHead, clampWeightEyes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the look at target.
|
||||
/// </summary>
|
||||
/// <param name='lookAtPosition'>
|
||||
/// Look at position.
|
||||
/// </param>
|
||||
public void SetLookAtPosition(Vector3 lookAtPosition) {
|
||||
solvers.lookAt.SetIKPosition(lookAtPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spine %IK position.
|
||||
/// </summary>
|
||||
/// <param name='spinePosition'>
|
||||
/// Spine %IK position.
|
||||
/// </param>
|
||||
public void SetSpinePosition(Vector3 spinePosition) {
|
||||
solvers.spine.SetIKPosition(spinePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spine weight.
|
||||
/// </summary>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetSpineWeight(float weight) {
|
||||
solvers.spine.SetIKPositionWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the limb solver for the %IK Goal.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The solver.
|
||||
/// </returns>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public IKSolverLimb GetGoalIK(AvatarIKGoal goal) {
|
||||
switch(goal) {
|
||||
case AvatarIKGoal.LeftFoot: return solvers.leftFoot;
|
||||
case AvatarIKGoal.RightFoot: return solvers.rightFoot;
|
||||
case AvatarIKGoal.LeftHand: return solvers.leftHand;
|
||||
case AvatarIKGoal.RightHand: return solvers.rightHand;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Re)Initiates the biped IK solvers.
|
||||
/// </summary>
|
||||
public void InitiateBipedIK() {
|
||||
InitiateSolver();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updating BipedIK
|
||||
/// </summary>
|
||||
public void UpdateBipedIK() {
|
||||
UpdateSolver();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set default solver values.
|
||||
* */
|
||||
public void SetToDefaults() {
|
||||
// Limbs
|
||||
foreach (IKSolverLimb limb in solvers.limbs) {
|
||||
limb.SetIKPositionWeight(0f);
|
||||
limb.SetIKRotationWeight(0f);
|
||||
limb.bendModifier = IKSolverLimb.BendModifier.Animation;
|
||||
limb.bendModifierWeight = 1f;
|
||||
}
|
||||
|
||||
solvers.leftHand.maintainRotationWeight = 0f;
|
||||
solvers.rightHand.maintainRotationWeight = 0f;
|
||||
|
||||
// Spine
|
||||
solvers.spine.SetIKPositionWeight(0f);
|
||||
solvers.spine.tolerance = 0f;
|
||||
solvers.spine.maxIterations = 2;
|
||||
solvers.spine.useRotationLimits = false;
|
||||
|
||||
// Aim
|
||||
solvers.aim.SetIKPositionWeight(0f);
|
||||
solvers.aim.tolerance = 0f;
|
||||
solvers.aim.maxIterations = 2;
|
||||
|
||||
// LookAt
|
||||
SetLookAtWeight(0f, 0.5f, 1f, 1f, 0.5f, 0.7f, 0.5f);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
/*
|
||||
* Fixes all the Transforms used by the solver to their default local states.
|
||||
* */
|
||||
protected override void FixTransforms() {
|
||||
solvers.pelvis.FixTransforms();
|
||||
solvers.lookAt.FixTransforms();
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) solvers.limbs[i].FixTransforms();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiates the %IK solver
|
||||
* */
|
||||
protected override void InitiateSolver() {
|
||||
string message = "";
|
||||
if (BipedReferences.SetupError(references, ref message)) {
|
||||
Warning.Log(message, references.root, false);
|
||||
return;
|
||||
}
|
||||
solvers.AssignReferences(references);
|
||||
|
||||
// Initiating solvers
|
||||
if (solvers.spine.bones.Length > 1) solvers.spine.Initiate(transform);
|
||||
solvers.lookAt.Initiate(transform);
|
||||
solvers.aim.Initiate(transform);
|
||||
foreach (IKSolverLimb limb in solvers.limbs) limb.Initiate(transform);
|
||||
|
||||
// Initiating constraints
|
||||
solvers.pelvis.Initiate(references.pelvis);
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the solvers. If you need full control of the execution order of your IK solvers, disable this script and call UpdateSolver() instead.
|
||||
* */
|
||||
protected override void UpdateSolver() {
|
||||
// Storing Limb bend and rotation before %IK
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) {
|
||||
solvers.limbs[i].MaintainBend();
|
||||
solvers.limbs[i].MaintainRotation();
|
||||
}
|
||||
|
||||
// Updating constraints
|
||||
solvers.pelvis.Update();
|
||||
|
||||
// Updating %IK solvers
|
||||
if (solvers.spine.bones.Length > 1) solvers.spine.Update();
|
||||
solvers.aim.Update();
|
||||
solvers.lookAt.Update();
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) solvers.limbs[i].Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs the warning if no other warning has beed logged in this session.
|
||||
/// </summary>
|
||||
public void LogWarning(string message) {
|
||||
Warning.Log(message, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d406d8b892f54ccaa5b0ef4de59944a
|
||||
labels:
|
||||
- InverseKinematics
|
||||
- IK
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 9998
|
||||
icon: {fileID: 2800000, guid: 2631a18e2dd7844718dea7db8ecf6c03, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// BipedIK solver collection.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class BipedIKSolvers {
|
||||
/// <summary>
|
||||
/// The left foot
|
||||
/// </summary>
|
||||
public IKSolverLimb leftFoot = new IKSolverLimb(AvatarIKGoal.LeftFoot);
|
||||
/// <summary>
|
||||
/// The right foot.
|
||||
/// </summary>
|
||||
public IKSolverLimb rightFoot = new IKSolverLimb(AvatarIKGoal.RightFoot);
|
||||
/// <summary>
|
||||
/// The left hand.
|
||||
/// </summary>
|
||||
public IKSolverLimb leftHand = new IKSolverLimb(AvatarIKGoal.LeftHand);
|
||||
/// <summary>
|
||||
/// The right hand.
|
||||
/// </summary>
|
||||
public IKSolverLimb rightHand = new IKSolverLimb(AvatarIKGoal.RightHand);
|
||||
/// <summary>
|
||||
/// The spine.
|
||||
/// </summary>
|
||||
public IKSolverFABRIK spine = new IKSolverFABRIK();
|
||||
/// <summary>
|
||||
/// The Look At %IK.
|
||||
/// </summary>
|
||||
public IKSolverLookAt lookAt = new IKSolverLookAt();
|
||||
/// <summary>
|
||||
/// The Aim %IK. Rotates the spine to aim a transform's forward towards the target.
|
||||
/// </summary>
|
||||
public IKSolverAim aim = new IKSolverAim();
|
||||
/// <summary>
|
||||
/// %Constraints for manipulating the character's pelvis.
|
||||
/// </summary>
|
||||
public Constraints pelvis = new Constraints();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array containing all the limbs.
|
||||
/// </summary>
|
||||
public IKSolverLimb[] limbs {
|
||||
get {
|
||||
if (_limbs == null || (_limbs != null && _limbs.Length != 4)) _limbs = new IKSolverLimb[4] { leftFoot, rightFoot, leftHand, rightHand };
|
||||
return _limbs;
|
||||
}
|
||||
}
|
||||
private IKSolverLimb[] _limbs;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array containing all %IK solvers.
|
||||
/// </summary>
|
||||
public IKSolver[] ikSolvers {
|
||||
get {
|
||||
if (_ikSolvers == null || (_ikSolvers != null && _ikSolvers.Length != 7)) _ikSolvers = new IKSolver[7] { leftFoot, rightFoot, leftHand, rightHand, spine, lookAt, aim };
|
||||
return _ikSolvers;
|
||||
}
|
||||
}
|
||||
private IKSolver[] _ikSolvers;
|
||||
|
||||
public void AssignReferences(BipedReferences references) {
|
||||
// Assigning limbs from references
|
||||
leftHand.SetChain(references.leftUpperArm, references.leftForearm, references.leftHand, references.root);
|
||||
rightHand.SetChain(references.rightUpperArm, references.rightForearm, references.rightHand, references.root);
|
||||
leftFoot.SetChain(references.leftThigh, references.leftCalf, references.leftFoot, references.root);
|
||||
rightFoot.SetChain(references.rightThigh, references.rightCalf, references.rightFoot, references.root);
|
||||
|
||||
// Assigning spine bones from references
|
||||
spine.SetChain(references.spine, references.root);
|
||||
|
||||
// Assigning lookAt bones from references
|
||||
lookAt.SetChain(references.spine, references.head, references.eyes, references.root);
|
||||
|
||||
// Assigning Aim bones from references
|
||||
aim.SetChain(references.spine, references.root);
|
||||
|
||||
leftFoot.goal = AvatarIKGoal.LeftFoot;
|
||||
rightFoot.goal = AvatarIKGoal.RightFoot;
|
||||
leftHand.goal = AvatarIKGoal.LeftHand;
|
||||
rightHand.goal = AvatarIKGoal.RightHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 552b6be99351d42019784667c84a7d5a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230c114522f924447be695b657911302
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// The base abstract class for all Transform constraints.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract class Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The transform to constrain.
|
||||
/// </summary>
|
||||
public Transform transform;
|
||||
/// <summary>
|
||||
/// %Constraint weight.
|
||||
/// </summary>
|
||||
public float weight;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Constraint"/> is valid.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if is valid; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool isValid {
|
||||
get {
|
||||
return transform != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the constraint.
|
||||
/// </summary>
|
||||
public abstract void UpdateConstraint();
|
||||
|
||||
#endregion Main Interface
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e377232abb249ed8b4ef7d7ae933e7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %Constraints to position in world space.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintPosition : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The target position.
|
||||
/// </summary>
|
||||
public Vector3 position;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Lerping to position
|
||||
transform.position = Vector3.Lerp(transform.position, position, weight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintPosition() {}
|
||||
public ConstraintPosition(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 071793b8887c44ddda2d9dc3a0525167
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the transform from its (animated) position.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintPositionOffset : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The position offset in world space.
|
||||
/// </summary>
|
||||
public Vector3 offset;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Initiating
|
||||
if (!initiated) {
|
||||
// Storing default values
|
||||
defaultLocalPosition = transform.localPosition;
|
||||
lastLocalPosition = transform.localPosition;
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Check if position has changed. If true, set default local position to current.
|
||||
if (positionChanged) defaultLocalPosition = transform.localPosition;
|
||||
|
||||
// Offsetting the position
|
||||
transform.localPosition = defaultLocalPosition;
|
||||
transform.position += offset * weight;
|
||||
|
||||
// Store the current local position to check if it has changed in the next update.
|
||||
lastLocalPosition = transform.localPosition;
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintPositionOffset() {}
|
||||
|
||||
public ConstraintPositionOffset(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
private Vector3 defaultLocalPosition, lastLocalPosition;
|
||||
private bool initiated;
|
||||
|
||||
/*
|
||||
* Check if position has been changed by animation or any other external script.
|
||||
* If not, consider the object to be static and offset only from the default rotation.
|
||||
* */
|
||||
private bool positionChanged {
|
||||
get {
|
||||
return transform.localPosition != lastLocalPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2d9a3e673645474bb6716a1c403e3b1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %Constraints to rotation in world space
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintRotation : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The target rotation.
|
||||
/// </summary>
|
||||
public Quaternion rotation;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Slerping to target rotation
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, weight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintRotation() {}
|
||||
public ConstraintRotation(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a47eb259ef1b9403599c08fb1e457fcc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the transform from its (animated) rotation
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintRotationOffset: Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The rotation offset in world space.
|
||||
/// </summary>
|
||||
public Quaternion offset;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Initiating
|
||||
if (!initiated) {
|
||||
// Storing default rotations.
|
||||
defaultLocalRotation = transform.localRotation;
|
||||
lastLocalRotation = transform.localRotation;
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Check if rotation has changed. If true, set default local rotation to current.
|
||||
if (rotationChanged) defaultLocalRotation = transform.localRotation;
|
||||
|
||||
// Offsetting the rotation
|
||||
transform.localRotation = defaultLocalRotation;
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, offset, weight);
|
||||
|
||||
// Store the current local rotation to check if it has changed in the next update.
|
||||
lastLocalRotation = transform.localRotation;
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintRotationOffset() {}
|
||||
public ConstraintRotationOffset(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
private Quaternion defaultRotation, defaultLocalRotation, lastLocalRotation, defaultTargetLocalRotation;
|
||||
private bool initiated;
|
||||
|
||||
/*
|
||||
* Check if rotation has been changed by animation or any other external script.
|
||||
* If not, consider the object to be static and offset only from the default rotation.
|
||||
* */
|
||||
private bool rotationChanged {
|
||||
get {
|
||||
return transform.localRotation != lastLocalRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 530e73d7a55ff47029c43502e289273f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,95 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Contains and manages a set of constraints.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Constraints {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The transform.
|
||||
/// </summary>
|
||||
public Transform transform;
|
||||
/// <summary>
|
||||
/// The target.
|
||||
/// </summary>
|
||||
public Transform target;
|
||||
/// <summary>
|
||||
/// The position offset.
|
||||
/// </summary>
|
||||
public Vector3 positionOffset;
|
||||
/// <summary>
|
||||
/// The position to lerp to by positionWeight
|
||||
/// </summary>
|
||||
public Vector3 position;
|
||||
/// <summary>
|
||||
/// The weight of lerping to position
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
public float positionWeight;
|
||||
/// <summary>
|
||||
/// The rotation offset.
|
||||
/// </summary>
|
||||
public Vector3 rotationOffset;
|
||||
/// <summary>
|
||||
/// The rotation to slerp to by rotationWeight
|
||||
/// </summary>
|
||||
public Vector3 rotation;
|
||||
/// <summary>
|
||||
/// The weight of slerping to rotation
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
public float rotationWeight;
|
||||
|
||||
private Vector3 defaultLocalPosition;
|
||||
private Quaternion defaultLocalRotation;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance is valid.
|
||||
/// </summary>
|
||||
public bool IsValid() {
|
||||
return transform != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiate to the specified transform.
|
||||
/// </summary>
|
||||
public void Initiate(Transform transform) {
|
||||
this.transform = transform;
|
||||
this.position = transform.position;
|
||||
this.rotation = transform.eulerAngles;
|
||||
defaultLocalPosition = transform.localPosition;
|
||||
defaultLocalRotation = transform.localRotation;
|
||||
}
|
||||
|
||||
public void FixTransforms()
|
||||
{
|
||||
transform.localPosition = defaultLocalPosition;
|
||||
transform.localRotation = defaultLocalRotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the constraints.
|
||||
/// </summary>
|
||||
public void Update() {
|
||||
if (!IsValid()) return;
|
||||
|
||||
// Position
|
||||
if (target != null) position = target.position;
|
||||
transform.position += positionOffset;
|
||||
if (positionWeight > 0f) transform.position = Vector3.Lerp(transform.position, position, positionWeight);
|
||||
|
||||
// Rotation
|
||||
if (target != null) rotation = target.eulerAngles;
|
||||
transform.rotation = Quaternion.Euler(rotationOffset) * transform.rotation;
|
||||
if (rotationWeight > 0f) transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotation), rotationWeight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11679c68b0e4448338c1e21138a3596a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ad7f440b73d8470b959b7c9fb12fcfb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/FinalIK Change Log.pdf
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/FinalIK Change Log.pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7b02201a6e3c416cad2e367877dacc7
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 365bd3269a5454635af24dc6962f7d1d
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/FinalIK User Manual.pdf
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/FinalIK User Manual.pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ef58c8cd22c3461180e62ac068acdc4
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d91317b400b4b9ab842fa07822acc2
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,387 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion;
|
||||
using System;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Contains a LimbIK solver and some additional logic to handle the finger.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Finger {
|
||||
|
||||
[System.Serializable]
|
||||
public enum DOF {
|
||||
One,
|
||||
Three
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Master Weight for the finger.
|
||||
/// </summary>
|
||||
[Tooltip("Master Weight for the finger.")]
|
||||
[Range(0f, 1f)] public float weight = 1f;
|
||||
/// <summary>
|
||||
/// The weight of rotating the finger tip and bending the finger to the target.
|
||||
/// </summary>
|
||||
[Tooltip("The weight of rotating the finger tip and bending the finger to the target.")]
|
||||
[Range(0f, 1f)]
|
||||
public float rotationWeight = 1f;
|
||||
|
||||
[Tooltip("Rotational degrees of freedom. When set to 'One' the fingers will be able to be rotated only around a single axis. When 3, all 3 axes are free to rotate around.")]
|
||||
/// <summary>
|
||||
/// Rotational degrees of freedom. When set to 'One' the fingers will be able to be rotated only around a single axis. When 3, all 3 axes are free to rotate around.
|
||||
/// </summary>
|
||||
public DOF rotationDOF;
|
||||
|
||||
[Tooltip("If enabled, keeps bone1 twist angle fixed relative to bone2.")]
|
||||
/// <summary>
|
||||
/// If enabled, keeps bone1 twist angle fixed relative to bone2.
|
||||
/// </summary>
|
||||
public bool fixBone1Twist;
|
||||
|
||||
/// <summary>
|
||||
/// The first bone of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The first bone of the finger.")]
|
||||
public Transform bone1;
|
||||
/// <summary>
|
||||
/// The second bone of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The second bone of the finger.")]
|
||||
public Transform bone2;
|
||||
/// <summary>
|
||||
/// The (optional) third bone of the finger. This can be ignored for thumbs.
|
||||
/// </summary>
|
||||
[Tooltip("The (optional) third bone of the finger. This can be ignored for thumbs.")]
|
||||
public Transform bone3;
|
||||
/// <summary>
|
||||
/// The fingertip object. If your character doesn't have tip bones, you can create an empty GameObject and parent it to the last bone in the finger. Place it to the tip of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The fingertip object. If your character doesn't have tip bones, you can create an empty GameObject and parent it to the last bone in the finger. Place it to the tip of the finger.")]
|
||||
public Transform tip;
|
||||
/// <summary>
|
||||
/// The IK target (optional, can use IKPosition and IKRotation directly).
|
||||
/// </summary>
|
||||
[Tooltip("The IK target (optional, can use IKPosition and IKRotation directly).")]
|
||||
public Transform target;
|
||||
|
||||
/// <summary>
|
||||
/// Has the finger properly initiated (in play mode only)?
|
||||
/// </summary>
|
||||
public bool initiated { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IK target position if target is not used.
|
||||
/// </summary>
|
||||
public Vector3 IKPosition {
|
||||
get {
|
||||
return solver.IKPosition;
|
||||
}
|
||||
set {
|
||||
solver.IKPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IK target rotation if target is not used.
|
||||
/// </summary>
|
||||
public Quaternion IKRotation {
|
||||
get {
|
||||
return solver.IKRotation;
|
||||
}
|
||||
set {
|
||||
solver.IKRotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is this finger setup valid?
|
||||
/// </summary>
|
||||
public bool IsValid(ref string errorMessage) {
|
||||
if (bone1 == null || bone2 == null || tip == null) {
|
||||
errorMessage = "One of the bones in the Finger Rig is null, can not initiate solvers.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IKSolverLimb solver;
|
||||
private Quaternion bone3RelativeToTarget;
|
||||
private Vector3 bone3DefaultLocalPosition;
|
||||
private Quaternion bone3DefaultLocalRotation;
|
||||
private Vector3 bone1Axis;
|
||||
private Vector3 tipAxis;
|
||||
private Vector3 bone1TwistAxis;
|
||||
private Vector3 defaultBendNormal;
|
||||
|
||||
// Initiates the LimbIK solver
|
||||
public void Initiate(Transform hand, int index) {
|
||||
initiated = false;
|
||||
|
||||
string errorMessage = string.Empty;
|
||||
if (!IsValid(ref errorMessage)) {
|
||||
Warning.Log(errorMessage, hand, false);
|
||||
return;
|
||||
}
|
||||
|
||||
solver = new IKSolverLimb();
|
||||
|
||||
solver.IKPositionWeight = weight;
|
||||
solver.bendModifier = IKSolverLimb.BendModifier.Target;
|
||||
solver.bendModifierWeight = 1f;
|
||||
defaultBendNormal = -Vector3.Cross(tip.position - bone1.position, bone2.position - bone1.position).normalized;
|
||||
solver.bendNormal = defaultBendNormal;
|
||||
|
||||
Vector3 axisWorld = Vector3.Cross(bone2.position - bone1.position, tip.position - bone1.position);
|
||||
bone1Axis = Quaternion.Inverse(bone1.rotation) * axisWorld;
|
||||
tipAxis = Quaternion.Inverse(tip.rotation) * axisWorld;
|
||||
|
||||
Vector3 normal = bone2.position - bone1.position;
|
||||
Vector3 tangent = -Vector3.Cross(tip.position - bone1.position, bone2.position - bone1.position);
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
bone1TwistAxis = Quaternion.Inverse(bone1.rotation) * tangent;
|
||||
|
||||
IKPosition = tip.position;
|
||||
IKRotation = tip.rotation;
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3RelativeToTarget = Quaternion.Inverse(IKRotation) * bone3.rotation;
|
||||
bone3DefaultLocalPosition = bone3.localPosition;
|
||||
bone3DefaultLocalRotation = bone3.localRotation;
|
||||
}
|
||||
|
||||
solver.SetChain(bone1, bone2, tip, hand);
|
||||
solver.Initiate(hand);
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Fix bones to their initial local position and rotation
|
||||
public void FixTransforms() {
|
||||
if (!initiated) return;
|
||||
if (weight <= 0f) return;
|
||||
|
||||
solver.FixTransforms();
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3.localPosition = bone3DefaultLocalPosition;
|
||||
bone3.localRotation = bone3DefaultLocalRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Stores the default localPosition/Rotation of the finger bones used by FixTransforms()
|
||||
public void StoreDefaultLocalState() {
|
||||
if (!initiated) return;
|
||||
|
||||
solver.StoreDefaultLocalState();
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3DefaultLocalPosition = bone3.localPosition;
|
||||
bone3DefaultLocalRotation = bone3.localRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the LimbIK solver and rotate the optional 3rd bone
|
||||
public void Update(float masterWeight) {
|
||||
if (!initiated) return;
|
||||
|
||||
float w = weight * masterWeight;
|
||||
if (w <= 0f) return;
|
||||
|
||||
solver.target = target;
|
||||
if (target != null) {
|
||||
IKPosition = target.position;
|
||||
IKRotation = target.rotation;
|
||||
}
|
||||
|
||||
if (rotationDOF == DOF.One) {
|
||||
Quaternion q = Quaternion.FromToRotation(IKRotation * tipAxis, bone1.rotation * bone1Axis);
|
||||
IKRotation = q * IKRotation;
|
||||
}
|
||||
|
||||
// Rotate the 3rd bone
|
||||
if (bone3 != null) {
|
||||
if (w * rotationWeight >= 1f) {
|
||||
bone3.rotation = IKRotation * bone3RelativeToTarget;
|
||||
} else {
|
||||
bone3.rotation = Quaternion.Lerp(bone3.rotation, IKRotation * bone3RelativeToTarget, w * rotationWeight);
|
||||
}
|
||||
}
|
||||
|
||||
solver.IKPositionWeight = w;
|
||||
solver.IKRotationWeight = rotationWeight;
|
||||
solver.Update();
|
||||
|
||||
if (fixBone1Twist)
|
||||
{
|
||||
Quaternion bone2Rotation = bone2.rotation;
|
||||
Quaternion space = Quaternion.LookRotation(bone1.rotation * bone1TwistAxis, bone2.position - bone1.position);
|
||||
Vector3 bone1Twist = Quaternion.Inverse(space) * solver.bendNormal;
|
||||
float angle = Mathf.Atan2(bone1Twist.x, bone1Twist.z) * Mathf.Rad2Deg;
|
||||
bone1.rotation = Quaternion.AngleAxis(angle, bone2.position - bone1.position) * bone1.rotation;
|
||||
bone2.rotation = bone2Rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles IK for a number of Fingers with 3-4 joints.
|
||||
/// </summary>
|
||||
public class FingerRig : SolverManager {
|
||||
|
||||
/// <summary>
|
||||
/// The master weight for all fingers.
|
||||
/// </summary>
|
||||
[Tooltip("The master weight for all fingers.")]
|
||||
[Range(0f, 1f)]
|
||||
public float weight = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The array of Fingers.
|
||||
/// </summary>
|
||||
public Finger[] fingers = new Finger[0];
|
||||
|
||||
/// <summary>
|
||||
/// Has the rig properly initiated (in play mode only)?
|
||||
/// </summary>
|
||||
public bool initiated { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this rig valid?
|
||||
/// </summary>
|
||||
public bool IsValid(ref string errorMessage) {
|
||||
foreach (Finger finger in fingers) {
|
||||
if (!finger.IsValid(ref errorMessage)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to automatically fill in the Finger bones.
|
||||
/// </summary>
|
||||
[ContextMenu("Auto-detect")]
|
||||
public void AutoDetect() {
|
||||
fingers = new Finger[0];
|
||||
|
||||
for (int i = 0; i < transform.childCount; i++) {
|
||||
Transform[] potentialFinger = new Transform[0];
|
||||
AddChildrenRecursive(transform.GetChild(i), ref potentialFinger);
|
||||
|
||||
if (potentialFinger.Length == 3 || potentialFinger.Length == 4) {
|
||||
Finger finger = new Finger();
|
||||
finger.bone1 = potentialFinger[0];
|
||||
finger.bone2 = potentialFinger[1];
|
||||
if (potentialFinger.Length == 3) {
|
||||
finger.tip = potentialFinger[2];
|
||||
} else {
|
||||
finger.bone3 = potentialFinger[2];
|
||||
finger.tip = potentialFinger[3];
|
||||
}
|
||||
|
||||
finger.weight = 1f;
|
||||
|
||||
Array.Resize(ref fingers, fingers.Length + 1);
|
||||
fingers[fingers.Length - 1] = finger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a finger in run-time.
|
||||
/// </summary>
|
||||
public void AddFinger(Transform bone1, Transform bone2, Transform bone3, Transform tip, Transform target = null) {
|
||||
Finger finger = new Finger();
|
||||
finger.bone1 = bone1;
|
||||
finger.bone2 = bone2;
|
||||
finger.bone3 = bone3;
|
||||
finger.tip = tip;
|
||||
finger.target = target;
|
||||
|
||||
Array.Resize(ref fingers, fingers.Length + 1);
|
||||
fingers[fingers.Length - 1] = finger;
|
||||
|
||||
initiated = false;
|
||||
finger.Initiate(transform, fingers.Length - 1);
|
||||
if (fingers[fingers.Length - 1].initiated) initiated = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a finger in runtime.
|
||||
/// </summary>
|
||||
public void RemoveFinger(int index) {
|
||||
if (index < 0f || index >= fingers.Length) {
|
||||
Warning.Log("RemoveFinger index out of bounds.", transform);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fingers.Length == 1) {
|
||||
fingers = new Finger[0];
|
||||
return;
|
||||
}
|
||||
|
||||
Finger[] newFingers = new Finger[fingers.Length - 1];
|
||||
int added = 0;
|
||||
|
||||
for (int i = 0; i < fingers.Length; i++) {
|
||||
if (i != index) {
|
||||
newFingers[added] = fingers[i];
|
||||
added ++;
|
||||
}
|
||||
}
|
||||
|
||||
fingers = newFingers;
|
||||
}
|
||||
|
||||
// Adds child Transforms of the 'parent' to the 'array' recursively only if each Transform has a single child.
|
||||
private void AddChildrenRecursive(Transform parent, ref Transform[] array) {
|
||||
Array.Resize(ref array, array.Length + 1);
|
||||
array[array.Length - 1] = parent;
|
||||
|
||||
if (parent.childCount != 1) return;
|
||||
|
||||
AddChildrenRecursive(parent.GetChild(0), ref array);
|
||||
}
|
||||
|
||||
protected override void InitiateSolver() {
|
||||
initiated = true;
|
||||
|
||||
for (int i = 0; i < fingers.Length; i++) {
|
||||
fingers[i].Initiate(transform, i);
|
||||
if (!fingers[i].initiated) initiated = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFingerSolvers() {
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.Update(weight);
|
||||
}
|
||||
}
|
||||
|
||||
public void FixFingerTransforms() {
|
||||
if (weight <= 0f) return;
|
||||
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.FixTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreDefaultLocalState() {
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.StoreDefaultLocalState();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateSolver() {
|
||||
UpdateFingerSolvers();
|
||||
}
|
||||
|
||||
protected override void FixTransforms() {
|
||||
if (weight <= 0f) return;
|
||||
|
||||
FixFingerTransforms();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee545149746b44547897f32030465e57
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 10000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bdc8112837ae4a76b936df3038e4b2c
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/AimIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/AimIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14a4d69b319a04b75bb03f351a174cec
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/BipedIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/BipedIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2631a18e2dd7844718dea7db8ecf6c03
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/CCDIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/CCDIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79450243724744b44820e5468e418048
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/Chain Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/Chain Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e394bb73c6c534de1a49e2eff63b4f6d
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/EndEffector Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/EndEffector Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ee227cd5021b40b2a18d383ba9dadff
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FABRIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FABRIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ccc9218a62cd44dda0ddb5fa15c62cc
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FABRIKRoot Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FABRIKRoot Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55f7720fb239042f08656d4ab294f5c5
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FullBodyBipedIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/FullBodyBipedIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89e0c79ada10847639ab1754e12413a7
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderBipedIK.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderBipedIK.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0b08042695f548e79a4e5c84112fe52
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderFBBIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderFBBIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36056811931e14f20adcc2767d6262e7
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderIK.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderIK.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c84c5721b6d74a15ab63fe46effb886
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderQuadruped.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/GrounderQuadruped.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c92822fd107844dccaf6c30c024e5806
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionObject Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionObject Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e5cf919254ee4d6bb9ccd7dc1b4bebd
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionSystem Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionSystem Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e7cd1ffcb3304ceba342d37416ceb2c
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionTarget Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionTarget Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 706b88054f06c4e83ad5f34217bedea3
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionTrigger Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/InteractionTrigger Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a1323dcf174944a69736d167afe96e0
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/LimbIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/LimbIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e747b4712fd43444ab8213b7ff4c089b
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/LookAtIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/LookAtIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc3f34dec09f54c4d8a48bf1a653b179
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/Mapping Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/Mapping Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e949b7451d544077b75cb3246f9f739
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/MidEffector Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/MidEffector Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c829e174cb3c74f869cd9949be8d8814
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitAngle Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitAngle Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e0729a4bf8e24db994fb1390c510a4e
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitHinge Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitHinge Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac7ab65192f5c4348bdd26925b0bb42d
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitPolygonal Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitPolygonal Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03a93cc74a1364909b1ddd071896ad75
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitSpline Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/RotationLimitSpline Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6c289ca5c243470198f39f6517123fd
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/TrigonometricIK Icon.png
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/Gizmos/TrigonometricIK Icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff34b0ecb22e7466fbd0a856b7a00621
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bed935aadc9ff4217bc309bf058d2fdb
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Dedicated abstrac base component for the Grounding solver.
|
||||
/// </summary>
|
||||
public abstract class Grounder: MonoBehaviour {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The master weight. Use this to fade in/out the grounding effect.
|
||||
/// </summary>
|
||||
[Tooltip("The master weight. Use this to fade in/out the grounding effect.")]
|
||||
[Range(0f, 1f)] public float weight = 1f;
|
||||
/// <summary>
|
||||
/// The %Grounding solver. Not to confuse with IK solvers.
|
||||
/// </summary>
|
||||
[Tooltip("The Grounding solver. Not to confuse with IK solvers.")]
|
||||
public Grounding solver = new Grounding();
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for Grounder events.
|
||||
/// </summary>
|
||||
public delegate void GrounderDelegate();
|
||||
/// <summary>
|
||||
/// Called before the Grounder updates its solver.
|
||||
/// </summary>
|
||||
public GrounderDelegate OnPreGrounder;
|
||||
/// <summary>
|
||||
/// Called after the Grounder has updated its solver and before the IK is applied.
|
||||
/// </summary>
|
||||
public GrounderDelegate OnPostGrounder;
|
||||
/// <summary>
|
||||
/// Called after the IK has updated.
|
||||
/// </summary>
|
||||
public GrounderDelegate OnPostIK;
|
||||
|
||||
/// <summary>
|
||||
/// Resets this Grounder so characters can be teleported instananeously.
|
||||
/// </summary>
|
||||
public abstract void ResetPosition();
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public bool initiated { get; protected set; }
|
||||
|
||||
// Gets the spine bend direction
|
||||
protected Vector3 GetSpineOffsetTarget() {
|
||||
Vector3 sum = Vector3.zero;
|
||||
for (int i = 0; i < solver.legs.Length; i++) {
|
||||
sum += GetLegSpineBendVector(solver.legs[i]);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Logs the warning if no other warning has beed logged in this session.
|
||||
protected void LogWarning(string message) {
|
||||
Warning.Log(message, transform);
|
||||
}
|
||||
|
||||
// Gets the bend direction for a foot
|
||||
private Vector3 GetLegSpineBendVector(Grounding.Leg leg) {
|
||||
Vector3 spineTangent = GetLegSpineTangent(leg);
|
||||
float dotF = (Vector3.Dot(solver.root.forward, spineTangent.normalized) + 1) * 0.5f; // Default behaviour, not bending spine when going downhill
|
||||
//float dotF = Mathf.Abs(Vector3.Dot(solver.root.forward, spineTangent.normalized)); // Bending spine backwards when going downhill
|
||||
//float dotF = Vector3.Dot(solver.root.forward, spineTangent.normalized); // Bending spine forward when going downhill
|
||||
float w = (leg.IKPosition - leg.transform.position).magnitude;
|
||||
return spineTangent * w * dotF;
|
||||
}
|
||||
|
||||
// Gets the direction from the root to the foot (ortho-normalized to root.up)
|
||||
private Vector3 GetLegSpineTangent(Grounding.Leg leg) {
|
||||
Vector3 tangent = leg.transform.position - solver.root.position;
|
||||
|
||||
if (!solver.rotateSolver || solver.root.up == Vector3.up) return new Vector3(tangent.x, 0f, tangent.z);
|
||||
|
||||
Vector3 normal = solver.root.up;
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
return tangent;
|
||||
}
|
||||
|
||||
// Open the User Manual url
|
||||
protected abstract void OpenUserManual();
|
||||
|
||||
// Open the Script Reference url
|
||||
protected abstract void OpenScriptReference();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20d3b31ccf0b543f5b659a1c3292d5c5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,196 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 391939450fd8044e3839af08f34c2af8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: c0b08042695f548e79a4e5c84112fe52, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,215 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Grounding for FBBIK characters.
|
||||
/// </summary>
|
||||
[HelpURL("https://www.youtube.com/watch?v=9MiZiaJorws&index=6&list=PLVxSIA1OaTOu8Nos3CalXbJ2DrKnntMv6")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder Full Body Biped")]
|
||||
public class GrounderFBBIK: Grounder {
|
||||
|
||||
// Open a video tutorial video
|
||||
[ContextMenu("TUTORIAL VIDEO")]
|
||||
void OpenTutorial() {
|
||||
Application.OpenURL("https://www.youtube.com/watch?v=9MiZiaJorws&index=6&list=PLVxSIA1OaTOu8Nos3CalXbJ2DrKnntMv6");
|
||||
}
|
||||
|
||||
// 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_f_b_b_i_k.html");
|
||||
}
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// Contains the bending weights for an effector.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class SpineEffector {
|
||||
/// <summary>
|
||||
/// The type of the effector.
|
||||
/// </summary>
|
||||
[Tooltip("The type of the effector.")]
|
||||
public FullBodyBipedEffector effectorType;
|
||||
/// <summary>
|
||||
/// The weight of horizontal bend offset towards the slope..
|
||||
/// </summary>
|
||||
[Tooltip("The weight of horizontal bend offset towards the slope.")]
|
||||
public float horizontalWeight = 1f;
|
||||
/// <summary>
|
||||
/// The vertical bend offset weight.
|
||||
/// </summary>
|
||||
[Tooltip("The vertical bend offset weight.")]
|
||||
public float verticalWeight;
|
||||
|
||||
public SpineEffector() {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RootMotion.FinalIK.GrounderFBBIK+SpineEffector"/> class.
|
||||
/// </summary>
|
||||
/// <param name="effectorType">Effector type.</param>
|
||||
/// <param name="horizontalWeight">Horizontal weight.</param>
|
||||
/// <param name="verticalWeight">Vertical weight.</param>
|
||||
public SpineEffector(FullBodyBipedEffector effectorType, float horizontalWeight, float verticalWeight) {
|
||||
this.effectorType = effectorType;
|
||||
this.horizontalWeight = horizontalWeight;
|
||||
this.verticalWeight = verticalWeight;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the FBBIK componet.
|
||||
/// </summary>
|
||||
[Tooltip("Reference to the FBBIK componet.")]
|
||||
public FullBodyBipedIK ik;
|
||||
/// <summary>
|
||||
/// The amount of spine bending towards upward slopes.
|
||||
/// </summary>
|
||||
[Tooltip("The amount of spine bending towards upward slopes.")]
|
||||
public float spineBend = 2f;
|
||||
/// <summary>
|
||||
/// The interpolation speed of spine bending.
|
||||
/// </summary>
|
||||
[Tooltip("The interpolation speed of spine bending.")]
|
||||
public float spineSpeed = 3f;
|
||||
/// <summary>
|
||||
/// The spine bending effectors.
|
||||
/// </summary>
|
||||
public SpineEffector[] spine = new SpineEffector[0];
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public override void ResetPosition() {
|
||||
solver.Reset();
|
||||
spineOffset = Vector3.zero;
|
||||
}
|
||||
|
||||
public void Reinitiate()
|
||||
{
|
||||
initiated = false;
|
||||
firstSolve = false;
|
||||
}
|
||||
|
||||
private Transform[] feet = new Transform[2];
|
||||
private Vector3 spineOffset;
|
||||
private bool firstSolve;
|
||||
|
||||
// Can we initiate the Grounding?
|
||||
private bool IsReadyToInitiate() {
|
||||
if (ik == null) return false;
|
||||
if (!ik.solver.initiated) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initiate once we have a FBBIK component
|
||||
void Update() {
|
||||
firstSolve = true;
|
||||
weight = Mathf.Clamp(weight, 0f, 1f);
|
||||
if (weight <= 0f) return;
|
||||
|
||||
if (initiated) return;
|
||||
if (!IsReadyToInitiate()) return;
|
||||
|
||||
Initiate();
|
||||
}
|
||||
|
||||
void FixedUpdate() {
|
||||
firstSolve = true;
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
firstSolve = true;
|
||||
}
|
||||
|
||||
private void Initiate () {
|
||||
// Set maintainRotationWeight to 1 for both limbs so their rotation will be maintained as animated
|
||||
ik.solver.leftLegMapping.maintainRotationWeight = 1f;
|
||||
ik.solver.rightLegMapping.maintainRotationWeight = 1f;
|
||||
|
||||
// Gathering both foot bones from the FBBIK
|
||||
feet = new Transform[2];
|
||||
feet[0] = ik.solver.leftFootEffector.bone;
|
||||
feet[1] = ik.solver.rightFootEffector.bone;
|
||||
|
||||
// Add to the FBBIK OnPreUpdate delegate to know when it solves
|
||||
ik.solver.OnPreUpdate += OnSolverUpdate;
|
||||
ik.solver.OnPostUpdate += OnPostSolverUpdate;
|
||||
|
||||
// Initiate Grounding
|
||||
solver.Initiate(ik.references.root, feet);
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Called before updating the main IK solver
|
||||
private void OnSolverUpdate() {
|
||||
if (!firstSolve) return;
|
||||
firstSolve = false;
|
||||
if (!enabled) return;
|
||||
if (weight <= 0f) return;
|
||||
|
||||
if (OnPreGrounder != null) OnPreGrounder();
|
||||
|
||||
solver.Update();
|
||||
|
||||
// Move the pelvis
|
||||
ik.references.pelvis.position += solver.pelvis.IKOffset * weight;
|
||||
|
||||
// Set effector positionOffsets for the feet
|
||||
SetLegIK(ik.solver.leftFootEffector, solver.legs[0]);
|
||||
SetLegIK(ik.solver.rightFootEffector, solver.legs[1]);
|
||||
|
||||
// Bending the spine
|
||||
if (spineBend != 0f) {
|
||||
spineSpeed = Mathf.Clamp(spineSpeed, 0f, spineSpeed);
|
||||
|
||||
Vector3 spineOffseTarget = GetSpineOffsetTarget() * weight;
|
||||
spineOffset = Vector3.Lerp(spineOffset, spineOffseTarget * spineBend, Time.deltaTime * spineSpeed);
|
||||
Vector3 verticalOffset = ik.references.root.up * spineOffset.magnitude;
|
||||
|
||||
for (int i = 0; i < spine.Length; i++) {
|
||||
ik.solver.GetEffector(spine[i].effectorType).positionOffset += (spineOffset * spine[i].horizontalWeight) + (verticalOffset * spine[i].verticalWeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (OnPostGrounder != null) OnPostGrounder();
|
||||
}
|
||||
|
||||
// Set the effector positionOffset for the foot
|
||||
private void SetLegIK(IKEffector effector, Grounding.Leg leg) {
|
||||
effector.positionOffset += (leg.IKPosition - effector.bone.position) * weight;
|
||||
|
||||
effector.bone.rotation = Quaternion.Slerp(Quaternion.identity, leg.rotationOffset, weight) * effector.bone.rotation;
|
||||
}
|
||||
|
||||
// Auto-assign ik
|
||||
void OnDrawGizmosSelected() {
|
||||
if (ik == null) ik = GetComponent<FullBodyBipedIK>();
|
||||
if (ik == null) ik = GetComponentInParent<FullBodyBipedIK>();
|
||||
if (ik == null) ik = GetComponentInChildren<FullBodyBipedIK>();
|
||||
}
|
||||
|
||||
private void OnPostSolverUpdate()
|
||||
{
|
||||
if (OnPostIK != null) OnPostIK();
|
||||
}
|
||||
|
||||
// Cleaning up the delegate
|
||||
void OnDestroy() {
|
||||
if (initiated && ik != null)
|
||||
{
|
||||
ik.solver.OnPreUpdate -= OnSolverUpdate;
|
||||
ik.solver.OnPostUpdate -= OnPostSolverUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c72e1df647af4c0098866e944a04b01
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 36056811931e14f20adcc2767d6262e7, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,280 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Grounding for LimbIK, CCD and/or FABRIK solvers.
|
||||
/// </summary>
|
||||
[HelpURL("http://www.root-motion.com/finalikdox/html/page9.html")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder IK")]
|
||||
public class GrounderIK: 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_i_k.html");
|
||||
}
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The leg %IK componets (can be any type of IK component).
|
||||
/// </summary>
|
||||
public IK[] legs;
|
||||
/// <summary>
|
||||
/// The pelvis transform. Common ancestor of all the legs.
|
||||
/// </summary>
|
||||
[Tooltip("The pelvis transform. Common ancestor of all the legs.")]
|
||||
public Transform pelvis;
|
||||
/// <summary>
|
||||
/// The root Transform of the character, with the rigidbody and the collider.
|
||||
/// </summary>
|
||||
[Tooltip("The root Transform of the character, with the rigidbody and the collider.")]
|
||||
public Transform characterRoot;
|
||||
/// <summary>
|
||||
/// The weight of rotating the character root to the ground normal (range: 0 - 1).
|
||||
/// </summary>
|
||||
[Tooltip("The weight of rotating the character root to the ground normal (range: 0 - 1).")]
|
||||
[Range(0f, 1f)]
|
||||
public float rootRotationWeight;
|
||||
/// <summary>
|
||||
/// The speed of rotating the character root to the ground normal (range: 0 - inf).
|
||||
/// </summary>
|
||||
[Tooltip("The speed of rotating the character root to the ground normal (range: 0 - inf).")]
|
||||
public float rootRotationSpeed = 5f;
|
||||
/// <summary>
|
||||
/// The maximum angle of root rotation (range: 0 - 90).
|
||||
/// </summary>
|
||||
[Tooltip("The maximum angle of root rotation (range: 0 - 90).")]
|
||||
public float maxRootRotationAngle = 45f;
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public override void ResetPosition() {
|
||||
for (int i = 0; i < legs.Length; i++) {
|
||||
legs[i].GetIKSolver().IKPosition = feet[i].transform.position;
|
||||
if (legs[i] is LimbIK)
|
||||
{
|
||||
var leg = legs[i] as LimbIK;
|
||||
leg.solver.IKRotation = solver.legs[i].transform.rotation;
|
||||
}
|
||||
footRotations[i] = feet[i].rotation;
|
||||
}
|
||||
|
||||
animatedPelvisLocalPosition = pelvis.localPosition;
|
||||
solvedPelvisLocalPosition = pelvis.localPosition;
|
||||
|
||||
solver.Reset();
|
||||
}
|
||||
|
||||
private Transform[] feet = new Transform[0];
|
||||
private Quaternion[] footRotations = new Quaternion[0];
|
||||
private Vector3 animatedPelvisLocalPosition, solvedPelvisLocalPosition;
|
||||
private int solvedFeet;
|
||||
private bool solved;
|
||||
private float lastWeight;
|
||||
private Rigidbody characterRootRigidbody;
|
||||
|
||||
// Can we initiate the Grounding?
|
||||
private bool IsReadyToInitiate() {
|
||||
if (pelvis == null) return false;
|
||||
|
||||
if (legs.Length == 0) return false;
|
||||
|
||||
foreach (IK leg in legs) {
|
||||
if (leg == null) return false;
|
||||
|
||||
if (leg is FullBodyBipedIK) {
|
||||
LogWarning("GrounderIK does not support FullBodyBipedIK, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead. If you want to use FullBodyBipedIK, use the GrounderFBBIK component.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leg is FABRIKRoot) {
|
||||
LogWarning("GrounderIK does not support FABRIKRoot, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leg is AimIK) {
|
||||
LogWarning("GrounderIK does not support AimIK, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Weigh out the IK solvers properly when the component is disabled
|
||||
void OnDisable() {
|
||||
if (!initiated) return;
|
||||
|
||||
for (int i = 0; i < legs.Length; i++) {
|
||||
if (legs[i] != null) legs[i].GetIKSolver().IKPositionWeight = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Initiate once we have all the required components
|
||||
void Update() {
|
||||
weight = Mathf.Clamp(weight, 0f, 1f);
|
||||
if (weight <= 0f) return;
|
||||
|
||||
solved = false;
|
||||
|
||||
if (initiated) {
|
||||
// Clamping values
|
||||
rootRotationWeight = Mathf.Clamp(rootRotationWeight, 0f, 1f);
|
||||
rootRotationSpeed = Mathf.Clamp(rootRotationSpeed, 0f, rootRotationSpeed);
|
||||
|
||||
// Root rotation
|
||||
if (characterRoot != null && rootRotationSpeed > 0f && rootRotationWeight > 0f && solver.isGrounded) {
|
||||
Vector3 normal = solver.GetLegsPlaneNormal();
|
||||
|
||||
// Root rotation weight
|
||||
if (rootRotationWeight < 1f) {
|
||||
normal = Vector3.Slerp(Vector3.up, normal, rootRotationWeight);
|
||||
}
|
||||
|
||||
// Root rotation limit
|
||||
Quaternion upRotation = Quaternion.FromToRotation(transform.up, Vector3.up) * characterRoot.rotation;
|
||||
Quaternion rotationTarget = Quaternion.RotateTowards(upRotation, Quaternion.FromToRotation(transform.up, normal) * characterRoot.rotation, maxRootRotationAngle);
|
||||
|
||||
// Rotate the root
|
||||
if (characterRootRigidbody == null) {
|
||||
characterRoot.rotation = Quaternion.Lerp(characterRoot.rotation, rotationTarget, Time.deltaTime * rootRotationSpeed);
|
||||
} else {
|
||||
characterRootRigidbody.MoveRotation(Quaternion.Lerp(characterRoot.rotation, rotationTarget, Time.deltaTime * rootRotationSpeed));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsReadyToInitiate()) return;
|
||||
|
||||
Initiate();
|
||||
}
|
||||
|
||||
private void Initiate() {
|
||||
// Building arrays
|
||||
feet = new Transform[legs.Length];
|
||||
footRotations = new Quaternion[legs.Length];
|
||||
|
||||
for (int i = 0; i < feet.Length; i++) footRotations[i] = Quaternion.identity;
|
||||
|
||||
// Gathering the last bones of the IK solvers as feet
|
||||
for (int i = 0; i < legs.Length; i++) {
|
||||
IKSolver.Point[] points = legs[i].GetIKSolver().GetPoints();
|
||||
|
||||
feet[i] = points[points.Length - 1].transform;
|
||||
|
||||
// Add to the update delegates of each ik solver
|
||||
legs[i].GetIKSolver().OnPreUpdate += OnSolverUpdate;
|
||||
legs[i].GetIKSolver().OnPostUpdate += OnPostSolverUpdate;
|
||||
}
|
||||
|
||||
// Store the default localPosition of the pelvis
|
||||
animatedPelvisLocalPosition = pelvis.localPosition;
|
||||
|
||||
// Initiate the Grounding
|
||||
solver.Initiate(transform, feet);
|
||||
|
||||
for (int i = 0; i < legs.Length; i++) {
|
||||
if (legs [i] is LegIK) {
|
||||
solver.legs[i].invertFootCenter = true;
|
||||
}
|
||||
}
|
||||
|
||||
characterRootRigidbody = characterRoot.GetComponent<Rigidbody>();
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Called before updating the first 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 another IK has already solved in this frame, do nothing
|
||||
if (solved) return;
|
||||
|
||||
if (OnPreGrounder != null) OnPreGrounder();
|
||||
|
||||
// If the pelvis local position has not changed since last solved state, consider it unanimated
|
||||
if (pelvis.localPosition != solvedPelvisLocalPosition) animatedPelvisLocalPosition = pelvis.localPosition;
|
||||
else pelvis.localPosition = animatedPelvisLocalPosition;
|
||||
|
||||
// Update the Grounding
|
||||
solver.Update();
|
||||
|
||||
// Update the IKPositions and IKPositonWeights of the legs
|
||||
for (int i = 0; i < legs.Length; i++) SetLegIK(i);
|
||||
|
||||
// Move the pelvis
|
||||
pelvis.position += solver.pelvis.IKOffset * weight;
|
||||
|
||||
solved = true;
|
||||
solvedFeet = 0;
|
||||
|
||||
if (OnPostGrounder != null) OnPostGrounder();
|
||||
}
|
||||
|
||||
// Set the IK position and weight for a limb
|
||||
private void SetLegIK(int index) {
|
||||
footRotations[index] = feet[index].rotation;
|
||||
|
||||
if (legs [index] is LegIK) {
|
||||
(legs[index].GetIKSolver() as IKSolverLeg).IKRotation = Quaternion.Slerp(Quaternion.identity, solver.legs[index].rotationOffset, weight) * footRotations[index];
|
||||
(legs[index].GetIKSolver() as IKSolverLeg).IKRotationWeight = 1f;
|
||||
}
|
||||
|
||||
legs[index].GetIKSolver().IKPosition = solver.legs[index].IKPosition;
|
||||
legs[index].GetIKSolver().IKPositionWeight = weight;
|
||||
}
|
||||
|
||||
// Rotating the feet after IK has finished
|
||||
private void OnPostSolverUpdate() {
|
||||
if (weight <= 0f) return;
|
||||
if (!enabled) return;
|
||||
|
||||
// Only do this after the last IK solver has finished
|
||||
solvedFeet ++;
|
||||
if (solvedFeet < feet.Length) return;
|
||||
solved = false;
|
||||
|
||||
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 = pelvis.localPosition;
|
||||
|
||||
if (OnPostIK != null) OnPostIK();
|
||||
}
|
||||
|
||||
// Cleaning up the delegates
|
||||
void OnDestroy() {
|
||||
if (initiated) {
|
||||
foreach (IK leg in legs) {
|
||||
if (leg != null) {
|
||||
leg.GetIKSolver().OnPreUpdate -= OnSolverUpdate;
|
||||
leg.GetIKSolver().OnPostUpdate -= OnPostSolverUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65ace204533ef4c24ac80f11ef8ee8ea
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7c84c5721b6d74a15ab63fe46effb886, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,449 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Grounding for LimbIK, CCD and/or FABRIK solvers.
|
||||
/// </summary>
|
||||
[HelpURL("http://www.root-motion.com/finalikdox/html/page9.html")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder Quadruped")]
|
||||
public class GrounderQuadruped: 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_quadruped.html");
|
||||
}
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The %Grounding solver for the forelegs.
|
||||
/// </summary>
|
||||
[Tooltip("The Grounding solver for the forelegs.")]
|
||||
public Grounding forelegSolver = new Grounding();
|
||||
/// <summary>
|
||||
/// The weight of rotating the character root to the ground angle (range: 0 - 1).
|
||||
/// </summary>
|
||||
[Tooltip("The weight of rotating the character root to the ground angle (range: 0 - 1).")]
|
||||
[Range(0f, 1f)]
|
||||
public float rootRotationWeight = 0.5f;
|
||||
/// <summary>
|
||||
/// The maximum angle of rotating the quadruped downwards (going downhill, range: -90 - 0).
|
||||
/// </summary>
|
||||
[Tooltip("The maximum angle of rotating the quadruped downwards (going downhill, range: -90 - 0).")]
|
||||
[Range(-90f, 0f)]
|
||||
public float minRootRotation = -25f;
|
||||
/// <summary>
|
||||
/// The maximum angle of rotating the quadruped upwards (going uphill, range: 0 - 90).
|
||||
/// </summary>
|
||||
[Tooltip("The maximum angle of rotating the quadruped upwards (going uphill, range: 0 - 90).")]
|
||||
[Range(0f, 90f)]
|
||||
public float maxRootRotation = 45f;
|
||||
/// <summary>
|
||||
/// The speed of interpolating the character root rotation (range: 0 - inf).
|
||||
/// </summary>
|
||||
[Tooltip("The speed of interpolating the character root rotation (range: 0 - inf).")]
|
||||
public float rootRotationSpeed = 5f;
|
||||
/// <summary>
|
||||
/// The maximum IK offset for the legs (range: 0 - inf).
|
||||
/// </summary>
|
||||
[Tooltip("The maximum IK offset for the legs (range: 0 - inf).")]
|
||||
public float maxLegOffset = 0.5f;
|
||||
/// <summary>
|
||||
/// The maximum IK offset for the forelegs (range: 0 - inf).
|
||||
/// </summary>
|
||||
[Tooltip("The maximum IK offset for the forelegs (range: 0 - inf).")]
|
||||
public float maxForeLegOffset = 0.5f;
|
||||
/// <summary>
|
||||
/// The weight of maintaining the head's rotation as it was before solving the Grounding (range: 0 - 1).
|
||||
/// </summary>
|
||||
[Tooltip("The weight of maintaining the head's rotation as it was before solving the Grounding (range: 0 - 1).")]
|
||||
[Range(0f, 1f)]
|
||||
public float maintainHeadRotationWeight = 0.5f;
|
||||
/// <summary>
|
||||
/// The root Transform of the character, with the rigidbody and the collider.
|
||||
/// </summary>
|
||||
[Tooltip("The root Transform of the character, with the rigidbody and the collider.")]
|
||||
public Transform characterRoot;
|
||||
/// <summary>
|
||||
/// The pelvis transform. Common ancestor of both legs and the spine.
|
||||
/// </summary>
|
||||
[Tooltip("The pelvis transform. Common ancestor of both legs and the spine.")]
|
||||
public Transform pelvis;
|
||||
/// <summary>
|
||||
/// The last bone in the spine that is the common parent for both forelegs.
|
||||
/// </summary>
|
||||
[Tooltip("The last bone in the spine that is the common parent for both forelegs.")]
|
||||
public Transform lastSpineBone;
|
||||
/// <summary>
|
||||
/// The head (optional, if you intend to maintain its rotation).
|
||||
/// </summary>
|
||||
[Tooltip("The head (optional, if you intend to maintain its rotation).")]
|
||||
public Transform head;
|
||||
/// <summary>
|
||||
/// %IK componets of the hindlegs. Can be any type of IK components.
|
||||
/// </summary>
|
||||
public IK[] legs;
|
||||
/// <summary>
|
||||
/// %IK components for the forelegs. Can be any type of IK components.
|
||||
/// </summary>
|
||||
public IK[] forelegs;
|
||||
/// <summary>
|
||||
/// When using GrounderQuadruped on a spherical object, update this vector to always point towards the center of that object.
|
||||
/// </summary>
|
||||
[HideInInspector] public Vector3 gravity = Vector3.down;
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public override void ResetPosition() {
|
||||
for (int i = 0; i < legs.Length; i++)
|
||||
{
|
||||
legs[i].GetIKSolver().IKPosition = feet[i].transform.position;
|
||||
if (legs[i] is LimbIK)
|
||||
{
|
||||
var leg = legs[i] as LimbIK;
|
||||
leg.solver.IKRotation = solver.legs[i].transform.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
solver.Reset();
|
||||
forelegSolver.Reset();
|
||||
}
|
||||
|
||||
// Contains all the required information about a foot
|
||||
public struct Foot {
|
||||
public IKSolver solver;
|
||||
public Transform transform;
|
||||
public Quaternion rotation;
|
||||
public Grounding.Leg leg;
|
||||
|
||||
// The custom constructor
|
||||
public Foot (IKSolver solver, Transform transform) {
|
||||
this.solver = solver;
|
||||
this.transform = transform;
|
||||
this.leg = null;
|
||||
rotation = transform.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
private Foot[] feet = new Foot[0];
|
||||
private Vector3 animatedPelvisLocalPosition;
|
||||
private Quaternion animatedPelvisLocalRotation;
|
||||
private Quaternion animatedHeadLocalRotation;
|
||||
private Vector3 solvedPelvisLocalPosition;
|
||||
private Quaternion solvedPelvisLocalRotation;
|
||||
private Quaternion solvedHeadLocalRotation;
|
||||
private int solvedFeet;
|
||||
private bool solved;
|
||||
private float angle;
|
||||
private Transform forefeetRoot;
|
||||
private Quaternion headRotation;
|
||||
private float lastWeight;
|
||||
private Rigidbody characterRootRigidbody;
|
||||
|
||||
// Can we initiate the Grounding?
|
||||
private bool IsReadyToInitiate() {
|
||||
if (pelvis == null) return false;
|
||||
if (lastSpineBone == null) return false;
|
||||
|
||||
if (legs.Length == 0) return false;
|
||||
if (forelegs.Length == 0) return false;
|
||||
|
||||
if (characterRoot == null) return false;
|
||||
|
||||
if (!IsReadyToInitiateLegs(legs)) return false;
|
||||
if (!IsReadyToInitiateLegs(forelegs)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are the leg IK components valid for initiation?
|
||||
private bool IsReadyToInitiateLegs(IK[] ikComponents) {
|
||||
foreach (IK leg in ikComponents) {
|
||||
if (leg == null) return false;
|
||||
|
||||
if (leg is FullBodyBipedIK) {
|
||||
LogWarning("GrounderIK does not support FullBodyBipedIK, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead. If you want to use FullBodyBipedIK, use the GrounderFBBIK component.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leg is FABRIKRoot) {
|
||||
LogWarning("GrounderIK does not support FABRIKRoot, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leg is AimIK) {
|
||||
LogWarning("GrounderIK does not support AimIK, use CCDIK, FABRIK, LimbIK or TrigonometricIK instead.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Weigh out the IK solvers properly when the component is disabled
|
||||
void OnDisable() {
|
||||
if (!initiated) return;
|
||||
|
||||
for (int i = 0; i < feet.Length; i++) {
|
||||
if (feet[i].solver != null) feet[i].solver.IKPositionWeight = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Initiate once we have all the required components
|
||||
void Update() {
|
||||
weight = Mathf.Clamp(weight, 0f, 1f);
|
||||
if (weight <= 0f) return;
|
||||
|
||||
solved = false;
|
||||
|
||||
if (initiated) return;
|
||||
if (!IsReadyToInitiate()) return;
|
||||
|
||||
Initiate();
|
||||
}
|
||||
|
||||
// Initiate this Grounder
|
||||
private void Initiate() {
|
||||
// Building the feet
|
||||
feet = new Foot[legs.Length + forelegs.Length];
|
||||
|
||||
// Gathering the last bones of the IK solvers as feet
|
||||
Transform[] footBones = InitiateFeet(legs, ref feet, 0);
|
||||
Transform[] forefootBones = InitiateFeet(forelegs, ref feet, legs.Length);
|
||||
|
||||
// Store the default localPosition and localRotation of the pelvis
|
||||
animatedPelvisLocalPosition = pelvis.localPosition;
|
||||
animatedPelvisLocalRotation = pelvis.localRotation;
|
||||
if (head != null) animatedHeadLocalRotation = head.localRotation;
|
||||
|
||||
forefeetRoot = new GameObject().transform;
|
||||
forefeetRoot.parent = transform;
|
||||
forefeetRoot.name = "Forefeet Root";
|
||||
|
||||
// Initiate the Grounding
|
||||
solver.Initiate(transform, footBones);
|
||||
forelegSolver.Initiate(forefeetRoot, forefootBones);
|
||||
|
||||
for (int i = 0; i < footBones.Length; i++) feet[i].leg = solver.legs[i];
|
||||
for (int i = 0; i < forefootBones.Length; i++) feet[i + legs.Length].leg = forelegSolver.legs[i];
|
||||
|
||||
characterRootRigidbody = characterRoot.GetComponent<Rigidbody>();
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Initiate the feet
|
||||
private Transform[] InitiateFeet(IK[] ikComponents, ref Foot[] f, int indexOffset) {
|
||||
Transform[] bones = new Transform[ikComponents.Length];
|
||||
|
||||
for (int i = 0; i < ikComponents.Length; i++) {
|
||||
IKSolver.Point[] points = ikComponents[i].GetIKSolver().GetPoints();
|
||||
|
||||
f[i + indexOffset] = new Foot(ikComponents[i].GetIKSolver(), points[points.Length - 1].transform);
|
||||
bones[i] = f[i + indexOffset].transform;
|
||||
|
||||
// Add to the update delegates of each ik solver
|
||||
f[i + indexOffset].solver.OnPreUpdate += OnSolverUpdate;
|
||||
f[i + indexOffset].solver.OnPostUpdate += OnPostSolverUpdate;
|
||||
}
|
||||
|
||||
return bones;
|
||||
}
|
||||
|
||||
void LateUpdate () {
|
||||
if (weight <= 0f) return;
|
||||
|
||||
// Clamping values
|
||||
rootRotationWeight = Mathf.Clamp(rootRotationWeight, 0f, 1f);
|
||||
minRootRotation = Mathf.Clamp(minRootRotation, -90f, maxRootRotation);
|
||||
maxRootRotation = Mathf.Clamp(maxRootRotation, minRootRotation, 90f);
|
||||
rootRotationSpeed = Mathf.Clamp(rootRotationSpeed, 0f, rootRotationSpeed);
|
||||
maxLegOffset = Mathf.Clamp(maxLegOffset, 0f, maxLegOffset);
|
||||
maxForeLegOffset = Mathf.Clamp(maxForeLegOffset, 0f, maxForeLegOffset);
|
||||
maintainHeadRotationWeight = Mathf.Clamp(maintainHeadRotationWeight, 0f, 1f);
|
||||
|
||||
// Rotate the character root
|
||||
RootRotation();
|
||||
}
|
||||
|
||||
// Rotate the character along with the terrain
|
||||
private void RootRotation() {
|
||||
if (rootRotationWeight <= 0f) return;
|
||||
if (rootRotationSpeed <= 0f) return;
|
||||
|
||||
solver.rotateSolver = true;
|
||||
forelegSolver.rotateSolver = true;
|
||||
|
||||
// Get the horizontal rotation of the character
|
||||
Vector3 tangent = characterRoot.forward;
|
||||
|
||||
Vector3 normal = -gravity;
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
Quaternion horizontalRotation = Quaternion.LookRotation(tangent, -gravity);
|
||||
|
||||
// Get the direction from root hit to forelegs root hit in the space of the horizontal character rotation
|
||||
Vector3 hitDirection = forelegSolver.rootHit.point - solver.rootHit.point;
|
||||
Vector3 hitDirectionLocal = Quaternion.Inverse(horizontalRotation) * hitDirection;
|
||||
|
||||
// Get the angle between the horizontal and hit directions
|
||||
float angleTarget = Mathf.Atan2(hitDirectionLocal.y, hitDirectionLocal.z) * Mathf.Rad2Deg;
|
||||
angleTarget = Mathf.Clamp(angleTarget * rootRotationWeight, minRootRotation, maxRootRotation);
|
||||
|
||||
// Interpolate the angle
|
||||
angle = Mathf.Lerp(angle, angleTarget, Time.deltaTime * rootRotationSpeed);
|
||||
|
||||
if (characterRootRigidbody == null) {
|
||||
characterRoot.rotation = Quaternion.Slerp(characterRoot.rotation, Quaternion.AngleAxis(-angle, characterRoot.right) * horizontalRotation, weight);
|
||||
} else {
|
||||
characterRootRigidbody.MoveRotation(Quaternion.Slerp(characterRoot.rotation, Quaternion.AngleAxis(-angle, characterRoot.right) * horizontalRotation, weight));
|
||||
}
|
||||
}
|
||||
|
||||
// Called before updating the first 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 another IK has already solved in this frame, do nothing
|
||||
if (solved) return;
|
||||
|
||||
if (OnPreGrounder != null) OnPreGrounder();
|
||||
|
||||
// If the bone transforms have not changed since last solved state, consider them unanimated
|
||||
if (pelvis.localPosition != solvedPelvisLocalPosition) animatedPelvisLocalPosition = pelvis.localPosition;
|
||||
else pelvis.localPosition = animatedPelvisLocalPosition;
|
||||
|
||||
if (pelvis.localRotation != solvedPelvisLocalRotation) animatedPelvisLocalRotation = pelvis.localRotation;
|
||||
else pelvis.localRotation = animatedPelvisLocalRotation;
|
||||
|
||||
if (head != null) {
|
||||
if (head.localRotation != solvedHeadLocalRotation) animatedHeadLocalRotation = head.localRotation;
|
||||
else head.localRotation = animatedHeadLocalRotation;
|
||||
}
|
||||
|
||||
for (int i = 0; i < feet.Length; i++) feet[i].rotation = feet[i].transform.rotation;
|
||||
|
||||
// Store the head rotation so it could be maintained later
|
||||
if (head != null) headRotation = head.rotation;
|
||||
|
||||
// Position the forefeet root to the center of forefeet
|
||||
UpdateForefeetRoot();
|
||||
|
||||
// Update the Grounding
|
||||
solver.Update();
|
||||
forelegSolver.Update();
|
||||
|
||||
// Move the pelvis
|
||||
pelvis.position += solver.pelvis.IKOffset * weight;
|
||||
|
||||
// Rotate the pelvis
|
||||
Vector3 spineDirection = lastSpineBone.position - pelvis.position;
|
||||
|
||||
Vector3 newSpinePosition =
|
||||
lastSpineBone.position +
|
||||
forelegSolver.root.up * Mathf.Clamp(forelegSolver.pelvis.heightOffset, Mathf.NegativeInfinity, 0f) -
|
||||
solver.root.up * solver.pelvis.heightOffset;
|
||||
|
||||
Vector3 newDirection = newSpinePosition - pelvis.position;
|
||||
|
||||
Quaternion f = Quaternion.FromToRotation(spineDirection, newDirection);
|
||||
pelvis.rotation = Quaternion.Slerp(Quaternion.identity, f, weight) * pelvis.rotation;
|
||||
|
||||
// Update the IKPositions and IKPositonWeights of the legs
|
||||
for (int i = 0; i < feet.Length; i++) SetFootIK(feet[i], (i < 2? maxLegOffset: maxForeLegOffset));
|
||||
|
||||
solved = true;
|
||||
solvedFeet = 0;
|
||||
|
||||
if (OnPostGrounder != null) OnPostGrounder();
|
||||
}
|
||||
|
||||
// Position the forefeet root to the center of forefeet
|
||||
private void UpdateForefeetRoot() {
|
||||
// Get the centroid
|
||||
Vector3 foreFeetCenter = Vector3.zero;
|
||||
|
||||
for (int i = 0; i < forelegSolver.legs.Length; i++) {
|
||||
foreFeetCenter += forelegSolver.legs[i].transform.position;
|
||||
}
|
||||
|
||||
foreFeetCenter /= (float)forelegs.Length;
|
||||
Vector3 dir = foreFeetCenter - transform.position;
|
||||
|
||||
// Ortho-normalize to this Transform's rotation
|
||||
Vector3 normal = transform.up;
|
||||
Vector3 tangent = dir;
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
|
||||
// Positioning the forefeet root
|
||||
forefeetRoot.position = transform.position + tangent.normalized * dir.magnitude;
|
||||
}
|
||||
|
||||
// Set the IK position and weight for a limb
|
||||
private void SetFootIK(Foot foot, float maxOffset) {
|
||||
Vector3 direction = foot.leg.IKPosition - foot.transform.position;
|
||||
|
||||
foot.solver.IKPosition = foot.transform.position + Vector3.ClampMagnitude(direction, maxOffset);
|
||||
foot.solver.IKPositionWeight = weight;
|
||||
}
|
||||
|
||||
// Rotating the feet after IK has finished
|
||||
private void OnPostSolverUpdate() {
|
||||
if (weight <= 0f) return;
|
||||
if (!enabled) return;
|
||||
|
||||
// Only do this after the last IK solver has finished
|
||||
solvedFeet ++;
|
||||
if (solvedFeet < feet.Length) return;
|
||||
|
||||
for (int i = 0; i < feet.Length; i++) {
|
||||
feet[i].transform.rotation = Quaternion.Slerp(Quaternion.identity, feet[i].leg.rotationOffset, weight) * feet[i].rotation;
|
||||
}
|
||||
|
||||
if (head != null) head.rotation = Quaternion.Lerp(head.rotation, headRotation, maintainHeadRotationWeight * weight);
|
||||
|
||||
// Store the solved transform's of the bones so we know if they are not animated
|
||||
solvedPelvisLocalPosition = pelvis.localPosition;
|
||||
solvedPelvisLocalRotation = pelvis.localRotation;
|
||||
if (head != null) solvedHeadLocalRotation = head.localRotation;
|
||||
|
||||
if (OnPostIK != null) OnPostIK();
|
||||
}
|
||||
|
||||
// Cleaning up the delegates
|
||||
void OnDestroy() {
|
||||
if (initiated) {
|
||||
DestroyLegs(legs);
|
||||
DestroyLegs(forelegs);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleaning up the delegates
|
||||
private void DestroyLegs(IK[] ikComponents) {
|
||||
foreach (IK leg in ikComponents) {
|
||||
if (leg != null) {
|
||||
leg.GetIKSolver().OnPreUpdate -= OnSolverUpdate;
|
||||
leg.GetIKSolver().OnPostUpdate -= OnPostSolverUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9823e47edf1dd40c29dfe0ba019f33a6
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: c92822fd107844dccaf6c30c024e5806, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,364 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Foot placement system.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public partial class Grounding {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The raycasting quality. Fastest is a single raycast per foot, Simple is three raycasts, Best is one raycast and a capsule cast per foot.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public enum Quality {
|
||||
Fastest,
|
||||
Simple,
|
||||
Best
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Layers to ground the character to. Make sure to exclude the layer of the character controller.
|
||||
/// </summary>
|
||||
[Tooltip("Layers to ground the character to. Make sure to exclude the layer of the character controller.")]
|
||||
public LayerMask layers;
|
||||
/// <summary>
|
||||
/// Max step height. Maximum vertical distance of Grounding from the root of the character.
|
||||
/// </summary>
|
||||
[Tooltip("Max step height. Maximum vertical distance of Grounding from the root of the character.")]
|
||||
public float maxStep = 0.5f;
|
||||
/// <summary>
|
||||
/// The height offset of the root.
|
||||
/// </summary>
|
||||
[Tooltip("The height offset of the root.")]
|
||||
public float heightOffset;
|
||||
/// <summary>
|
||||
/// The speed of moving the feet up/down.
|
||||
/// </summary>
|
||||
[Tooltip("The speed of moving the feet up/down.")]
|
||||
public float footSpeed = 2.5f;
|
||||
/// <summary>
|
||||
/// CapsuleCast radius. Should match approximately with the size of the feet.
|
||||
/// </summary>
|
||||
[Tooltip("CapsuleCast radius. Should match approximately with the size of the feet.")]
|
||||
public float footRadius = 0.15f;
|
||||
/// <summary>
|
||||
/// Offset of the foot center along character forward axis.
|
||||
/// </summary>
|
||||
[Tooltip("Offset of the foot center along character forward axis.")]
|
||||
[HideInInspector] public float footCenterOffset; // TODO make visible in inspector if Grounder Visualization is finished.
|
||||
/// <summary>
|
||||
/// Amount of velocity based prediction of the foot positions.
|
||||
/// </summary>
|
||||
[Tooltip("Amount of velocity based prediction of the foot positions.")]
|
||||
public float prediction = 0.05f;
|
||||
/// <summary>
|
||||
/// Weight of rotating the feet to the ground normal offset.
|
||||
/// </summary>
|
||||
[Tooltip("Weight of rotating the feet to the ground normal offset.")]
|
||||
[Range(0f, 1f)]
|
||||
public float footRotationWeight = 1f;
|
||||
/// <summary>
|
||||
/// Speed of slerping the feet to their grounded rotations.
|
||||
/// </summary>
|
||||
[Tooltip("Speed of slerping the feet to their grounded rotations.")]
|
||||
public float footRotationSpeed = 7f;
|
||||
/// <summary>
|
||||
/// Max Foot Rotation Angle, Max angular offset from the foot's rotation (Reasonable range: 0-90 degrees).
|
||||
/// </summary>
|
||||
[Tooltip("Max Foot Rotation Angle. Max angular offset from the foot's rotation.")]
|
||||
[Range(0f, 90f)]
|
||||
public float maxFootRotationAngle = 45f;
|
||||
/// <summary>
|
||||
/// If true, solver will rotate with the character root so the character can be grounded for example to spherical planets.
|
||||
/// For performance reasons leave this off unless needed.
|
||||
/// </summary>
|
||||
[Tooltip("If true, solver will rotate with the character root so the character can be grounded for example to spherical planets. For performance reasons leave this off unless needed.")]
|
||||
public bool rotateSolver;
|
||||
/// <summary>
|
||||
/// The speed of moving the character up/down.
|
||||
/// </summary>
|
||||
[Tooltip("The speed of moving the character up/down.")]
|
||||
public float pelvisSpeed = 5f;
|
||||
/// <summary>
|
||||
/// Used for smoothing out vertical pelvis movement (range 0 - 1).
|
||||
/// </summary>
|
||||
[Tooltip("Used for smoothing out vertical pelvis movement (range 0 - 1).")]
|
||||
[Range(0f, 1f)]
|
||||
public float pelvisDamper;
|
||||
/// <summary>
|
||||
/// The weight of lowering the pelvis to the lowest foot.
|
||||
/// </summary>
|
||||
[Tooltip("The weight of lowering the pelvis to the lowest foot.")]
|
||||
public float lowerPelvisWeight = 1f;
|
||||
/// <summary>
|
||||
/// The weight of lifting the pelvis to the highest foot. This is useful when you don't want the feet to go too high relative to the body when crouching.
|
||||
/// </summary>
|
||||
[Tooltip("The weight of lifting the pelvis to the highest foot. This is useful when you don't want the feet to go too high relative to the body when crouching.")]
|
||||
public float liftPelvisWeight;
|
||||
/// <summary>
|
||||
/// The radius of the spherecast from the root that determines whether the character root is grounded.
|
||||
/// </summary>
|
||||
[Tooltip("The radius of the spherecast from the root that determines whether the character root is grounded.")]
|
||||
public float rootSphereCastRadius = 0.1f;
|
||||
/// <summary>
|
||||
/// If false, keeps the foot that is over a ledge at the root level. If true, lowers the overstepping foot and body by the 'Max Step' value.
|
||||
/// </summary>
|
||||
[Tooltip("If false, keeps the foot that is over a ledge at the root level. If true, lowers the overstepping foot and body by the 'Max Step' value.")]
|
||||
public bool overstepFallsDown = true;
|
||||
/// <summary>
|
||||
/// The raycasting quality. Fastest is a single raycast per foot, Simple is three raycasts, Best is one raycast and a capsule cast per foot.
|
||||
/// </summary>
|
||||
[Tooltip("The raycasting quality. Fastest is a single raycast per foot, Simple is three raycasts, Best is one raycast and a capsule cast per foot.")]
|
||||
public Quality quality = Quality.Best;
|
||||
|
||||
/// <summary>
|
||||
/// The %Grounding legs.
|
||||
/// </summary>
|
||||
public Leg[] legs { get; private set; }
|
||||
/// <summary>
|
||||
/// The %Grounding pelvis.
|
||||
/// </summary>
|
||||
public Pelvis pelvis { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether any of the legs are grounded
|
||||
/// </summary>
|
||||
public bool isGrounded { get; private set; }
|
||||
/// <summary>
|
||||
/// The root Transform
|
||||
/// </summary>
|
||||
public Transform root { get; private set; }
|
||||
/// <summary>
|
||||
/// Ground height at the root position.
|
||||
/// </summary>
|
||||
public RaycastHit rootHit { get; private set; }
|
||||
/// <summary>
|
||||
/// Is the RaycastHit from the root grounded?
|
||||
/// </summary>
|
||||
public bool rootGrounded {
|
||||
get {
|
||||
return rootHit.distance < maxStep * 2f;
|
||||
}
|
||||
}
|
||||
|
||||
// For overriding ray/capsule/sphere casting functions
|
||||
public delegate bool OnRaycastDelegate(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);
|
||||
public OnRaycastDelegate Raycast = Physics.Raycast;
|
||||
|
||||
public delegate bool OnCapsuleCastDelegate(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);
|
||||
public OnCapsuleCastDelegate CapsuleCast = Physics.CapsuleCast;
|
||||
|
||||
public delegate bool OnSphereCastDelegate(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);
|
||||
public OnSphereCastDelegate SphereCast = Physics.SphereCast;
|
||||
|
||||
/// <summary>
|
||||
/// Raycasts or sphereCasts to find the root ground point. Distance of the Ray/Sphere cast is maxDistanceMlp x maxStep. Use this instead of rootHit if the Grounder is weighed out/disabled and not updated.
|
||||
/// </summary>
|
||||
public RaycastHit GetRootHit(float maxDistanceMlp = 10f) {
|
||||
RaycastHit h = new RaycastHit();
|
||||
Vector3 _up = up;
|
||||
|
||||
Vector3 legsCenter = Vector3.zero;
|
||||
foreach (Leg leg in legs) legsCenter += leg.transform.position;
|
||||
legsCenter /= (float)legs.Length;
|
||||
|
||||
h.point = legsCenter - _up * maxStep * 10f;
|
||||
float distMlp = maxDistanceMlp + 1;
|
||||
h.distance = maxStep * distMlp;
|
||||
|
||||
if (maxStep <= 0f) return h;
|
||||
|
||||
if (quality != Quality.Best) Raycast(legsCenter + _up * maxStep, -_up, out h, maxStep * distMlp, layers, QueryTriggerInteraction.Ignore);
|
||||
else SphereCast(legsCenter + _up * maxStep, rootSphereCastRadius, -up, out h, maxStep * distMlp, layers, QueryTriggerInteraction.Ignore);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Grounding"/> is valid.
|
||||
/// </summary>
|
||||
public bool IsValid(ref string errorMessage) {
|
||||
if (root == null) {
|
||||
errorMessage = "Root transform is null. Can't initiate Grounding.";
|
||||
return false;
|
||||
}
|
||||
if (legs == null) {
|
||||
errorMessage = "Grounding legs is null. Can't initiate Grounding.";
|
||||
return false;
|
||||
}
|
||||
if (pelvis == null) {
|
||||
errorMessage = "Grounding pelvis is null. Can't initiate Grounding.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (legs.Length == 0) {
|
||||
errorMessage = "Grounding has 0 legs. Can't initiate Grounding.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiate the %Grounding as an integrated solver by providing the root Transform, leg solvers, pelvis Transform and spine solver.
|
||||
/// </summary>
|
||||
public void Initiate(Transform root, Transform[] feet) {
|
||||
this.root = root;
|
||||
initiated = false;
|
||||
|
||||
rootHit = new RaycastHit();
|
||||
|
||||
// Constructing Legs
|
||||
if (legs == null) legs = new Leg[feet.Length];
|
||||
if (legs.Length != feet.Length) legs = new Leg[feet.Length];
|
||||
for (int i = 0; i < feet.Length; i++) if (legs[i] == null) legs[i] = new Leg();
|
||||
|
||||
// Constructing pelvis
|
||||
if (pelvis == null) pelvis = new Pelvis();
|
||||
|
||||
string errorMessage = string.Empty;
|
||||
if (!IsValid(ref errorMessage)) {
|
||||
Warning.Log(errorMessage, root, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initiate solvers only if application is playing
|
||||
if (Application.isPlaying) {
|
||||
for (int i = 0; i < feet.Length; i++) legs[i].Initiate(this, feet[i]);
|
||||
pelvis.Initiate(this);
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the Grounding.
|
||||
/// </summary>
|
||||
public void Update() {
|
||||
if (!initiated) return;
|
||||
|
||||
if (layers == 0) LogWarning("Grounding layers are set to nothing. Please add a ground layer.");
|
||||
|
||||
maxStep = Mathf.Clamp(maxStep, 0f, maxStep);
|
||||
footRadius = Mathf.Clamp(footRadius, 0.0001f, maxStep);
|
||||
pelvisDamper = Mathf.Clamp(pelvisDamper, 0f, 1f);
|
||||
rootSphereCastRadius = Mathf.Clamp(rootSphereCastRadius, 0.0001f, rootSphereCastRadius);
|
||||
maxFootRotationAngle = Mathf.Clamp(maxFootRotationAngle, 0f, 90f);
|
||||
prediction = Mathf.Clamp(prediction, 0f, prediction);
|
||||
footSpeed = Mathf.Clamp(footSpeed, 0f, footSpeed);
|
||||
|
||||
// Root hit
|
||||
rootHit = GetRootHit();
|
||||
|
||||
float lowestOffset = Mathf.NegativeInfinity;
|
||||
float highestOffset = Mathf.Infinity;
|
||||
isGrounded = false;
|
||||
|
||||
// Process legs
|
||||
foreach (Leg leg in legs) {
|
||||
leg.Process();
|
||||
|
||||
if (leg.IKOffset > lowestOffset) lowestOffset = leg.IKOffset;
|
||||
if (leg.IKOffset < highestOffset) highestOffset = leg.IKOffset;
|
||||
|
||||
if (leg.isGrounded) isGrounded = true;
|
||||
}
|
||||
|
||||
// Precess pelvis
|
||||
lowestOffset = Mathf.Max(lowestOffset, 0f);
|
||||
highestOffset = Mathf.Min(highestOffset, 0f);
|
||||
pelvis.Process(-lowestOffset * lowerPelvisWeight, -highestOffset * liftPelvisWeight, isGrounded);
|
||||
}
|
||||
|
||||
// Calculate the normal of the plane defined by leg positions, so we know how to rotate the body
|
||||
public Vector3 GetLegsPlaneNormal() {
|
||||
if (!initiated) return Vector3.up;
|
||||
|
||||
Vector3 _up = up;
|
||||
Vector3 normal = _up;
|
||||
|
||||
// Go through all the legs, rotate the normal by its offset
|
||||
for (int i = 0; i < legs.Length; i++) {
|
||||
// Direction from the root to the leg
|
||||
Vector3 legDirection = legs[i].IKPosition - root.position;
|
||||
|
||||
// Find the tangent
|
||||
Vector3 legNormal = _up;
|
||||
Vector3 legTangent = legDirection;
|
||||
Vector3.OrthoNormalize(ref legNormal, ref legTangent);
|
||||
|
||||
// Find the rotation offset from the tangent to the direction
|
||||
Quaternion fromTo = Quaternion.FromToRotation(legTangent, legDirection);
|
||||
|
||||
// Rotate the normal
|
||||
normal = fromTo * normal;
|
||||
}
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
// Set everything to 0
|
||||
public void Reset() {
|
||||
if (!Application.isPlaying) return;
|
||||
pelvis.Reset();
|
||||
foreach (Leg leg in legs) leg.Reset();
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
private bool initiated;
|
||||
|
||||
// Logs the warning if no other warning has beed logged in this session.
|
||||
public void LogWarning(string message) {
|
||||
Warning.Log(message, root);
|
||||
}
|
||||
|
||||
// The up vector in solver rotation space.
|
||||
public Vector3 up {
|
||||
get {
|
||||
return (useRootRotation? root.up: Vector3.up);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the vertical offset between two vectors in solver rotation space
|
||||
public float GetVerticalOffset(Vector3 p1, Vector3 p2) {
|
||||
if (useRootRotation) {
|
||||
Vector3 v = Quaternion.Inverse(root.rotation) * (p1 - p2);
|
||||
return v.y;
|
||||
}
|
||||
|
||||
return p1.y - p2.y;
|
||||
}
|
||||
|
||||
// Flattens a vector to ground plane in solver rotation space
|
||||
public Vector3 Flatten(Vector3 v) {
|
||||
if (useRootRotation) {
|
||||
Vector3 tangent = v;
|
||||
Vector3 normal = root.up;
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
return Vector3.Project(v, tangent);
|
||||
}
|
||||
|
||||
v.y = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Determines whether to use root rotation as solver rotation
|
||||
private bool useRootRotation {
|
||||
get {
|
||||
if (!rotateSolver) return false;
|
||||
if (root.up == Vector3.up) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetFootCenterOffset() {
|
||||
return root.forward * footRadius + root.forward * footCenterOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc6729d441e4044f482135cdc532367d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,345 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
public partial class Grounding {
|
||||
|
||||
/// <summary>
|
||||
/// The %Grounding %Leg.
|
||||
/// </summary>
|
||||
public class Leg {
|
||||
|
||||
/// <summary>
|
||||
/// Returns true distance from foot to ground is less that maxStep
|
||||
/// </summary>
|
||||
public bool isGrounded { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the current IK position of the foot.
|
||||
/// </summary>
|
||||
public Vector3 IKPosition { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the current rotation offset of the foot.
|
||||
/// </summary>
|
||||
public Quaternion rotationOffset = Quaternion.identity;
|
||||
/// <summary>
|
||||
/// Returns true, if the leg is valid and initiated
|
||||
/// </summary>
|
||||
public bool initiated { get; private set; }
|
||||
/// <summary>
|
||||
/// The height of foot from ground.
|
||||
/// </summary>
|
||||
public float heightFromGround { get; private set; }
|
||||
/// <summary>
|
||||
/// Velocity of the foot
|
||||
/// </summary>
|
||||
public Vector3 velocity { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the foot Transform.
|
||||
/// </summary>
|
||||
public Transform transform { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the current IK offset.
|
||||
/// </summary>
|
||||
public float IKOffset { get; private set; }
|
||||
|
||||
public bool invertFootCenter;
|
||||
|
||||
public RaycastHit heelHit { get; private set; }
|
||||
public RaycastHit capsuleHit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RaycastHit last used by the Grounder to get ground height at foot position.
|
||||
/// </summary>
|
||||
public RaycastHit GetHitPoint {
|
||||
get
|
||||
{
|
||||
if (grounding.quality == Quality.Best) return capsuleHit;
|
||||
return heelHit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the animated position of the foot.
|
||||
/// </summary>
|
||||
public void SetFootPosition(Vector3 position)
|
||||
{
|
||||
doOverrideFootPosition = true;
|
||||
overrideFootPosition = position;
|
||||
}
|
||||
|
||||
private Grounding grounding;
|
||||
private float lastTime, deltaTime;
|
||||
private Vector3 lastPosition;
|
||||
private Quaternion toHitNormal, r;
|
||||
private Vector3 up = Vector3.up;
|
||||
private bool doOverrideFootPosition;
|
||||
private Vector3 overrideFootPosition;
|
||||
private Vector3 transformPosition;
|
||||
|
||||
// Initiates the Leg
|
||||
public void Initiate(Grounding grounding, Transform transform) {
|
||||
initiated = false;
|
||||
this.grounding = grounding;
|
||||
this.transform = transform;
|
||||
up = Vector3.up;
|
||||
IKPosition = transform.position;
|
||||
rotationOffset = Quaternion.identity;
|
||||
|
||||
initiated = true;
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
// Should be called each time the leg is (re)activated
|
||||
public void OnEnable() {
|
||||
if (!initiated) return;
|
||||
|
||||
lastPosition = transform.position;
|
||||
lastTime = Time.deltaTime;
|
||||
}
|
||||
|
||||
// Set everything to 0
|
||||
public void Reset() {
|
||||
lastPosition = transform.position;
|
||||
lastTime = Time.deltaTime;
|
||||
IKOffset = 0f;
|
||||
IKPosition = transform.position;
|
||||
rotationOffset = Quaternion.identity;
|
||||
}
|
||||
|
||||
// Raycasting, processing the leg's position
|
||||
public void Process() {
|
||||
if (!initiated) return;
|
||||
if (grounding.maxStep <= 0) return;
|
||||
|
||||
transformPosition = doOverrideFootPosition ? overrideFootPosition : transform.position;
|
||||
doOverrideFootPosition = false;
|
||||
|
||||
deltaTime = Time.time - lastTime;
|
||||
lastTime = Time.time;
|
||||
if (deltaTime == 0f) return;
|
||||
|
||||
up = grounding.up;
|
||||
heightFromGround = Mathf.Infinity;
|
||||
|
||||
// Calculating velocity
|
||||
velocity = (transformPosition - lastPosition) / deltaTime;
|
||||
//velocity = grounding.Flatten(velocity);
|
||||
lastPosition = transformPosition;
|
||||
|
||||
Vector3 prediction = velocity * grounding.prediction;
|
||||
|
||||
if (grounding.footRadius <= 0) grounding.quality = Grounding.Quality.Fastest;
|
||||
|
||||
isGrounded = false;
|
||||
|
||||
// Raycasting
|
||||
switch (grounding.quality)
|
||||
{
|
||||
|
||||
// The fastest, single raycast
|
||||
case Grounding.Quality.Fastest:
|
||||
|
||||
RaycastHit predictedHit = GetRaycastHit(prediction);
|
||||
SetFootToPoint(predictedHit.normal, predictedHit.point);
|
||||
if (predictedHit.collider != null) isGrounded = true;
|
||||
break;
|
||||
|
||||
// Medium, 3 raycasts
|
||||
case Grounding.Quality.Simple:
|
||||
|
||||
heelHit = GetRaycastHit(Vector3.zero);
|
||||
Vector3 f = grounding.GetFootCenterOffset();
|
||||
if (invertFootCenter) f = -f;
|
||||
RaycastHit toeHit = GetRaycastHit(f + prediction);
|
||||
RaycastHit sideHit = GetRaycastHit(grounding.root.right * grounding.footRadius * 0.5f);
|
||||
|
||||
if (heelHit.collider != null || toeHit.collider != null || sideHit.collider != null) isGrounded = true;
|
||||
|
||||
Vector3 planeNormal = Vector3.Cross(toeHit.point - heelHit.point, sideHit.point - heelHit.point).normalized;
|
||||
if (Vector3.Dot(planeNormal, up) < 0) planeNormal = -planeNormal;
|
||||
|
||||
SetFootToPlane(planeNormal, heelHit.point, heelHit.point);
|
||||
break;
|
||||
|
||||
// The slowest, raycast and a capsule cast
|
||||
case Grounding.Quality.Best:
|
||||
heelHit = GetRaycastHit(invertFootCenter ? -grounding.GetFootCenterOffset() : Vector3.zero);
|
||||
capsuleHit = GetCapsuleHit(prediction);
|
||||
|
||||
if (heelHit.collider != null || capsuleHit.collider != null) isGrounded = true;
|
||||
|
||||
SetFootToPlane(capsuleHit.normal, capsuleHit.point, heelHit.point);
|
||||
break;
|
||||
}
|
||||
|
||||
float offsetTarget = stepHeightFromGround;
|
||||
if (!grounding.rootGrounded) offsetTarget = 0f;
|
||||
|
||||
IKOffset = Interp.LerpValue(IKOffset, offsetTarget, grounding.footSpeed, grounding.footSpeed);
|
||||
IKOffset = Mathf.Lerp(IKOffset, offsetTarget, deltaTime * grounding.footSpeed);
|
||||
|
||||
float legHeight = grounding.GetVerticalOffset(transformPosition, grounding.root.position);
|
||||
float currentMaxOffset = Mathf.Clamp(grounding.maxStep - legHeight, 0f, grounding.maxStep);
|
||||
|
||||
IKOffset = Mathf.Clamp(IKOffset, -currentMaxOffset, IKOffset);
|
||||
|
||||
RotateFoot();
|
||||
|
||||
// Update IK values
|
||||
IKPosition = transformPosition - up * IKOffset;
|
||||
|
||||
float rW = grounding.footRotationWeight;
|
||||
rotationOffset = rW >= 1? r: Quaternion.Slerp(Quaternion.identity, r, rW);
|
||||
}
|
||||
|
||||
// Gets the height from ground clamped between min and max step height
|
||||
public float stepHeightFromGround {
|
||||
get {
|
||||
return Mathf.Clamp(heightFromGround, -grounding.maxStep, grounding.maxStep);
|
||||
}
|
||||
}
|
||||
|
||||
// Get predicted Capsule hit from the middle of the foot
|
||||
private RaycastHit GetCapsuleHit(Vector3 offsetFromHeel)
|
||||
{
|
||||
RaycastHit hit = new RaycastHit();
|
||||
Vector3 f = grounding.GetFootCenterOffset();
|
||||
if (invertFootCenter) f = -f;
|
||||
Vector3 origin = transformPosition + f;
|
||||
|
||||
if (grounding.overstepFallsDown)
|
||||
{
|
||||
hit.point = origin - up * grounding.maxStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit.point = new Vector3(origin.x, grounding.root.position.y, origin.z);
|
||||
}
|
||||
hit.normal = up;
|
||||
|
||||
// Start point of the capsule
|
||||
Vector3 capsuleStart = origin + grounding.maxStep * up;
|
||||
// End point of the capsule depending on the foot's velocity.
|
||||
Vector3 capsuleEnd = capsuleStart + offsetFromHeel;
|
||||
|
||||
if (grounding.CapsuleCast(capsuleStart, capsuleEnd, grounding.footRadius, -up, out hit, grounding.maxStep * 2, grounding.layers, QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
// Safeguarding from a CapsuleCast bug in Unity that might cause it to return NaN for hit.point when cast against large colliders.
|
||||
if (float.IsNaN(hit.point.x))
|
||||
{
|
||||
hit.point = origin - up * grounding.maxStep * 2f;
|
||||
hit.normal = up;
|
||||
}
|
||||
}
|
||||
|
||||
// Since Unity2017 Raycasts will return Vector3.zero when starting from inside a collider
|
||||
if (hit.point == Vector3.zero && hit.normal == Vector3.zero)
|
||||
{
|
||||
if (grounding.overstepFallsDown)
|
||||
{
|
||||
hit.point = origin - up * grounding.maxStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit.point = new Vector3(origin.x, grounding.root.position.y, origin.z);
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
// Get simple Raycast from the heel
|
||||
private RaycastHit GetRaycastHit(Vector3 offsetFromHeel)
|
||||
{
|
||||
RaycastHit hit = new RaycastHit();
|
||||
Vector3 origin = transformPosition + offsetFromHeel;
|
||||
|
||||
if (grounding.overstepFallsDown)
|
||||
{
|
||||
hit.point = origin - up * grounding.maxStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit.point = new Vector3(origin.x, grounding.root.position.y, origin.z);
|
||||
}
|
||||
hit.normal = up;
|
||||
|
||||
if (grounding.maxStep <= 0f) return hit;
|
||||
|
||||
grounding.Raycast(origin + grounding.maxStep * up, -up, out hit, grounding.maxStep * 2, grounding.layers, QueryTriggerInteraction.Ignore);
|
||||
|
||||
// Since Unity2017 Raycasts will return Vector3.zero when starting from inside a collider
|
||||
if (hit.point == Vector3.zero && hit.normal == Vector3.zero)
|
||||
{
|
||||
if (grounding.overstepFallsDown)
|
||||
{
|
||||
hit.point = origin - up * grounding.maxStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit.point = new Vector3(origin.x, grounding.root.position.y, origin.z);
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
// Rotates ground normal with respect to maxFootRotationAngle
|
||||
private Vector3 RotateNormal(Vector3 normal) {
|
||||
if (grounding.quality == Grounding.Quality.Best) return normal;
|
||||
return Vector3.RotateTowards(up, normal, grounding.maxFootRotationAngle * Mathf.Deg2Rad, deltaTime);
|
||||
}
|
||||
|
||||
// Set foot height from ground relative to a point
|
||||
private void SetFootToPoint(Vector3 normal, Vector3 point) {
|
||||
toHitNormal = Quaternion.FromToRotation(up, RotateNormal(normal));
|
||||
|
||||
heightFromGround = GetHeightFromGround(point);
|
||||
}
|
||||
|
||||
// Set foot height from ground relative to a plane
|
||||
private void SetFootToPlane(Vector3 planeNormal, Vector3 planePoint, Vector3 heelHitPoint) {
|
||||
planeNormal = RotateNormal(planeNormal);
|
||||
toHitNormal = Quaternion.FromToRotation(up, planeNormal);
|
||||
|
||||
Vector3 pointOnPlane = V3Tools.LineToPlane(transformPosition + up * grounding.maxStep, -up, planeNormal, planePoint);
|
||||
|
||||
// Get the height offset of the point on the plane
|
||||
heightFromGround = GetHeightFromGround(pointOnPlane);
|
||||
|
||||
// Making sure the heel doesn't penetrate the ground
|
||||
float heelHeight = GetHeightFromGround(heelHitPoint);
|
||||
heightFromGround = Mathf.Clamp(heightFromGround, -Mathf.Infinity, heelHeight);
|
||||
}
|
||||
|
||||
// Calculate height offset of a point
|
||||
private float GetHeightFromGround(Vector3 hitPoint) {
|
||||
return grounding.GetVerticalOffset(transformPosition, hitPoint) - rootYOffset;
|
||||
}
|
||||
|
||||
// Adding ground normal offset to the foot's rotation
|
||||
private void RotateFoot() {
|
||||
// Getting the full target rotation
|
||||
Quaternion rotationOffsetTarget = GetRotationOffsetTarget();
|
||||
|
||||
// Slerping the rotation offset
|
||||
r = Quaternion.Slerp(r, rotationOffsetTarget, deltaTime * grounding.footRotationSpeed);
|
||||
}
|
||||
|
||||
// Gets the target hit normal offset as a Quaternion
|
||||
private Quaternion GetRotationOffsetTarget() {
|
||||
if (grounding.maxFootRotationAngle <= 0f) return Quaternion.identity;
|
||||
if (grounding.maxFootRotationAngle >= 180f) return toHitNormal;
|
||||
return Quaternion.RotateTowards(Quaternion.identity, toHitNormal, grounding.maxFootRotationAngle);
|
||||
}
|
||||
|
||||
// The foot's height from ground in the animation
|
||||
private float rootYOffset {
|
||||
get {
|
||||
return grounding.GetVerticalOffset(transformPosition, grounding.root.position - up * grounding.heightOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0098ae58c812d4f599afc603a2d8b4b0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,82 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
public partial class Grounding {
|
||||
|
||||
/// <summary>
|
||||
/// The %Grounding %Pelvis.
|
||||
/// </summary>
|
||||
public class Pelvis {
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the pelvis as a Vector3.
|
||||
/// </summary>
|
||||
public Vector3 IKOffset { get; private set; }
|
||||
/// <summary>
|
||||
/// Scalar vertical offset of the pelvis.
|
||||
/// </summary>
|
||||
public float heightOffset { get; private set; }
|
||||
|
||||
private Grounding grounding;
|
||||
private Vector3 lastRootPosition;
|
||||
private float damperF;
|
||||
private bool initiated;
|
||||
private float lastTime;
|
||||
|
||||
// Initiating the pelvis
|
||||
public void Initiate(Grounding grounding) {
|
||||
this.grounding = grounding;
|
||||
|
||||
initiated = true;
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
// Set everything to 0
|
||||
public void Reset() {
|
||||
this.lastRootPosition = grounding.root.transform.position;
|
||||
lastTime = Time.deltaTime;
|
||||
IKOffset = Vector3.zero;
|
||||
heightOffset = 0f;
|
||||
}
|
||||
|
||||
// Should be called each time the pelvis is (re)activated
|
||||
public void OnEnable() {
|
||||
if (!initiated) return;
|
||||
this.lastRootPosition = grounding.root.transform.position;
|
||||
lastTime = Time.time;
|
||||
}
|
||||
|
||||
// Updates the pelvis position offset
|
||||
public void Process(float lowestOffset, float highestOffset, bool isGrounded) {
|
||||
if (!initiated) return;
|
||||
|
||||
float deltaTime = Time.time - lastTime;
|
||||
lastTime = Time.time;
|
||||
if (deltaTime <= 0f) return;
|
||||
|
||||
float offsetTarget = lowestOffset + highestOffset;
|
||||
if (!grounding.rootGrounded) offsetTarget = 0f;
|
||||
|
||||
// Interpolating the offset
|
||||
heightOffset = Mathf.Lerp(heightOffset, offsetTarget, deltaTime * grounding.pelvisSpeed);
|
||||
|
||||
// Damper
|
||||
Vector3 rootDelta = (grounding.root.position - lastRootPosition);
|
||||
lastRootPosition = grounding.root.position;
|
||||
|
||||
// Fading out damper when ungrounded
|
||||
damperF = Interp.LerpValue(damperF, isGrounded? 1f: 0f, 1f, 10f);
|
||||
|
||||
// Calculating the final damper
|
||||
heightOffset -= grounding.GetVerticalOffset(rootDelta, Vector3.zero) * grounding.pelvisDamper * damperF;
|
||||
|
||||
// Update IK value
|
||||
IKOffset = grounding.up * heightOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f32aae971577b4a689afe07820935737
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f581c9c6c8e7b49b48ff9a8be3b47df3
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Aim %IK solver component.
|
||||
/// </summary>
|
||||
[HelpURL("https://www.youtube.com/watch?v=wT8fViZpLmQ&index=3&list=PLVxSIA1OaTOu8Nos3CalXbJ2DrKnntMv6")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/IK/Aim IK")]
|
||||
public class AimIK : IK {
|
||||
|
||||
// Open the User Manual URL
|
||||
[ContextMenu("User Manual")]
|
||||
protected override void OpenUserManual() {
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/page1.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_aim_i_k.html");
|
||||
}
|
||||
|
||||
// Open a video tutorial about setting up the component
|
||||
[ContextMenu("TUTORIAL VIDEO")]
|
||||
void OpenSetupTutorial() {
|
||||
Application.OpenURL("https://www.youtube.com/watch?v=wT8fViZpLmQ");
|
||||
}
|
||||
|
||||
// Link to the Final IK Google Group
|
||||
[ContextMenu("Support Group")]
|
||||
void SupportGroup() {
|
||||
Application.OpenURL("https://groups.google.com/forum/#!forum/final-ik");
|
||||
}
|
||||
|
||||
// Link to the Final IK Asset Store thread in the Unity Community
|
||||
[ContextMenu("Asset Store Thread")]
|
||||
void ASThread() {
|
||||
Application.OpenURL("http://forum.unity3d.com/threads/final-ik-full-body-ik-aim-look-at-fabrik-ccd-ik-1-0-released.222685/");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Aim %IK solver.
|
||||
/// </summary>
|
||||
public IKSolverAim solver = new IKSolverAim();
|
||||
|
||||
public override IKSolver GetIKSolver() {
|
||||
return solver as IKSolver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5013856973b27429d937d256dc082f2e
|
||||
labels:
|
||||
- InverseKinematics
|
||||
- IK
|
||||
- Aim
|
||||
- AimingSystem
|
||||
timeCreated: 1511881277
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 9997
|
||||
icon: {fileID: 2800000, guid: 14a4d69b319a04b75bb03f351a174cec, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user