123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- using UnityEngine;
- using System.Collections;
- using System;
- namespace RootMotion.FinalIK {
- /// <summary>
- /// Full body biped IK effector types.
- /// </summary>
- [System.Serializable]
- public enum FullBodyBipedEffector {
- Body,
- LeftShoulder,
- RightShoulder,
- LeftThigh,
- RightThigh,
- LeftHand,
- RightHand,
- LeftFoot,
- RightFoot
- }
- /// <summary>
- /// Full body biped IK chain types.
- /// </summary>
- [System.Serializable]
- public enum FullBodyBipedChain {
- LeftArm,
- RightArm,
- LeftLeg,
- RightLeg
- }
- /// <summary>
- /// FBIK solver specialized to biped characters.
- /// </summary>
- [System.Serializable]
- public class IKSolverFullBodyBiped : IKSolverFullBody {
-
- #region Main Interface
-
- /// <summary>
- /// The central root node (body).
- /// </summary>
- public Transform rootNode;
- /// <summary>
- /// The stiffness of spine constraints.
- /// </summary>
- [Range(0f, 1f)]
- public float spineStiffness = 0.5f;
- /// <summary>
- /// Weight of hand effectors pulling the body vertically (relative to root rotation).
- /// </summary>
- [Range(-1f, 1f)]
- public float pullBodyVertical = 0.5f;
- /// <summary>
- /// Weight of hand effectors pulling the body horizontally (relative to root rotation).
- /// </summary>
- [Range(-1f, 1f)]
- public float pullBodyHorizontal = 0f;
-
- /// <summary>
- /// Gets the body effector.
- /// </summary>
- public IKEffector bodyEffector { get { return GetEffector(FullBodyBipedEffector.Body); }}
- /// <summary>
- /// Gets the left shoulder effector.
- /// </summary>
- public IKEffector leftShoulderEffector { get { return GetEffector(FullBodyBipedEffector.LeftShoulder); }}
- /// <summary>
- /// Gets the right shoulder effector.
- /// </summary>
- public IKEffector rightShoulderEffector { get { return GetEffector(FullBodyBipedEffector.RightShoulder); }}
- /// <summary>
- /// Gets the left thigh effector.
- /// </summary>
- public IKEffector leftThighEffector { get { return GetEffector(FullBodyBipedEffector.LeftThigh); }}
- /// <summary>
- /// Gets the right thigh effector.
- /// </summary>
- public IKEffector rightThighEffector { get { return GetEffector(FullBodyBipedEffector.RightThigh); }}
- /// <summary>
- /// Gets the left hand effector.
- /// </summary>
- public IKEffector leftHandEffector { get { return GetEffector(FullBodyBipedEffector.LeftHand); }}
- /// <summary>
- /// Gets the right hand effector.
- /// </summary>
- public IKEffector rightHandEffector { get { return GetEffector(FullBodyBipedEffector.RightHand); }}
- /// <summary>
- /// Gets the left foot effector.
- /// </summary>
- public IKEffector leftFootEffector { get { return GetEffector(FullBodyBipedEffector.LeftFoot); }}
- /// <summary>
- /// Gets the right foot effector.
- /// </summary>
- public IKEffector rightFootEffector { get { return GetEffector(FullBodyBipedEffector.RightFoot); }}
-
- /// <summary>
- /// Gets the left arm chain.
- /// </summary>
- public FBIKChain leftArmChain { get { return chain[1]; }}
- /// <summary>
- /// Gets the right arm chain.
- /// </summary>
- public FBIKChain rightArmChain { get { return chain[2]; }}
- /// <summary>
- /// Gets the left leg chain.
- /// </summary>
- public FBIKChain leftLegChain { get { return chain[3]; }}
- /// <summary>
- /// Gets the right leg chain.
- /// </summary>
- public FBIKChain rightLegChain { get { return chain[4]; }}
- /// <summary>
- /// Gets the left arm IK mapping.
- /// </summary>
- public IKMappingLimb leftArmMapping { get { return limbMappings[0]; }}
- /// <summary>
- /// Gets the right arm IK mapping.
- /// </summary>
- public IKMappingLimb rightArmMapping { get { return limbMappings[1]; }}
- /// <summary>
- /// Gets the left leg IK mapping.
- /// </summary>
- public IKMappingLimb leftLegMapping { get { return limbMappings[2]; }}
- /// <summary>
- /// Gets the right leg IK mapping.
- /// </summary>
- public IKMappingLimb rightLegMapping { get { return limbMappings[3]; }}
- /// <summary>
- /// Gets the head IK mapping.
- /// </summary>
- public IKMappingBone headMapping { get { return boneMappings[0]; }}
- /// <summary>
- /// Sets chain weights for the specified chain.
- /// </summary>
- public void SetChainWeights(FullBodyBipedChain c, float pull, float reach = 0f) {
- GetChain(c).pull = pull;
- GetChain(c).reach = reach;
- }
-
- /// <summary>
- /// Sets effector weights for the specified effector.
- /// </summary>
- public void SetEffectorWeights(FullBodyBipedEffector effector, float positionWeight, float rotationWeight) {
- GetEffector(effector).positionWeight = Mathf.Clamp(positionWeight, 0f, 1f);
- GetEffector(effector).rotationWeight = Mathf.Clamp(rotationWeight, 0f, 1f);
- }
-
- /// <summary>
- /// Gets the chain of a limb.
- /// </summary>
- public FBIKChain GetChain(FullBodyBipedChain c) {
- switch(c) {
- case FullBodyBipedChain.LeftArm: return chain[1];
- case FullBodyBipedChain.RightArm: return chain[2];
- case FullBodyBipedChain.LeftLeg: return chain[3];
- case FullBodyBipedChain.RightLeg: return chain[4];
- }
- return null;
- }
-
- /// <summary>
- /// Gets the chain of the specified effector.
- /// </summary>
- public FBIKChain GetChain(FullBodyBipedEffector effector) {
- switch(effector) {
- case FullBodyBipedEffector.Body: return chain[0];
- case FullBodyBipedEffector.LeftShoulder: return chain[1];
- case FullBodyBipedEffector.RightShoulder: return chain[2];
- case FullBodyBipedEffector.LeftThigh: return chain[3];
- case FullBodyBipedEffector.RightThigh: return chain[4];
- case FullBodyBipedEffector.LeftHand: return chain[1];
- case FullBodyBipedEffector.RightHand: return chain[2];
- case FullBodyBipedEffector.LeftFoot: return chain[3];
- case FullBodyBipedEffector.RightFoot: return chain[4];
- }
- return null;
- }
-
- /// <summary>
- /// Gets the effector of type.
- /// </summary>
- public IKEffector GetEffector(FullBodyBipedEffector effector) {
- switch(effector) {
- case FullBodyBipedEffector.Body: return effectors[0];
- case FullBodyBipedEffector.LeftShoulder: return effectors[1];
- case FullBodyBipedEffector.RightShoulder: return effectors[2];
- case FullBodyBipedEffector.LeftThigh: return effectors[3];
- case FullBodyBipedEffector.RightThigh: return effectors[4];
- case FullBodyBipedEffector.LeftHand: return effectors[5];
- case FullBodyBipedEffector.RightHand: return effectors[6];
- case FullBodyBipedEffector.LeftFoot: return effectors[7];
- case FullBodyBipedEffector.RightFoot: return effectors[8];
- }
- return null;
- }
- /// <summary>
- /// Gets the effector of type.
- /// </summary>
- public IKEffector GetEndEffector(FullBodyBipedChain c) {
- switch(c) {
- case FullBodyBipedChain.LeftArm: return effectors[5];
- case FullBodyBipedChain.RightArm: return effectors[6];
- case FullBodyBipedChain.LeftLeg: return effectors[7];
- case FullBodyBipedChain.RightLeg: return effectors[8];
- }
- return null;
- }
-
- /// <summary>
- /// Gets the limb mapping for the limb.
- /// </summary>
- public IKMappingLimb GetLimbMapping(FullBodyBipedChain chain) {
- switch(chain) {
- case FullBodyBipedChain.LeftArm: return limbMappings[0];
- case FullBodyBipedChain.RightArm: return limbMappings[1];
- case FullBodyBipedChain.LeftLeg: return limbMappings[2];
- case FullBodyBipedChain.RightLeg: return limbMappings[3];
- }
- return null;
- }
- /// <summary>
- /// Gets the limb mapping for the effector type.
- /// </summary>
- public IKMappingLimb GetLimbMapping(FullBodyBipedEffector effector) {
- switch(effector) {
- case FullBodyBipedEffector.LeftShoulder: return limbMappings[0];
- case FullBodyBipedEffector.RightShoulder: return limbMappings[1];
- case FullBodyBipedEffector.LeftThigh: return limbMappings[2];
- case FullBodyBipedEffector.RightThigh: return limbMappings[3];
- case FullBodyBipedEffector.LeftHand: return limbMappings[0];
- case FullBodyBipedEffector.RightHand: return limbMappings[1];
- case FullBodyBipedEffector.LeftFoot: return limbMappings[2];
- case FullBodyBipedEffector.RightFoot: return limbMappings[3];
- default: return null;
- }
- }
-
- /// <summary>
- /// Gets the spine mapping.
- /// </summary>
- public IKMappingSpine GetSpineMapping() {
- return spineMapping;
- }
-
- /// <summary>
- /// Gets the head mapping.
- /// </summary>
- public IKMappingBone GetHeadMapping() {
- return boneMappings[0];
- }
-
- /// <summary>
- /// Gets the bend constraint of a limb.
- /// </summary>
- public IKConstraintBend GetBendConstraint(FullBodyBipedChain limb) {
- switch(limb) {
- case FullBodyBipedChain.LeftArm: return chain[1].bendConstraint;
- case FullBodyBipedChain.RightArm: return chain[2].bendConstraint;
- case FullBodyBipedChain.LeftLeg: return chain[3].bendConstraint;
- case FullBodyBipedChain.RightLeg: return chain[4].bendConstraint;
- }
- return null;
- }
-
- public override bool IsValid(ref string message) {
- if (!base.IsValid(ref message)) return false;
-
- if (rootNode == null) {
- message = "Root Node bone is null. FBBIK will not initiate.";
- return false;
- }
-
- if (chain.Length != 5 ||
- chain[0].nodes.Length != 1 ||
- chain[1].nodes.Length != 3 ||
- chain[2].nodes.Length != 3 ||
- chain[3].nodes.Length != 3 ||
- chain[4].nodes.Length != 3 ||
- effectors.Length != 9 ||
- limbMappings.Length != 4
- ) {
- message = "Invalid FBBIK setup. Please right-click on the component header and select 'Reinitiate'.";
- return false;
- }
- return true;
- }
- /// <summary>
- /// Sets up the solver to BipedReferences and reinitiates (if in runtime).
- /// </summary>
- /// <param name="references">Biped references.</param>
- /// <param name="rootNode">Root node (optional). if null, will try to detect the root node bone automatically. </param>
- public void SetToReferences(BipedReferences references, Transform rootNode = null) {
- root = references.root;
- if (rootNode == null) rootNode = DetectRootNodeBone(references);
- this.rootNode = rootNode;
-
- // Root Node
- if (chain == null || chain.Length != 5) chain = new FBIKChain[5];
- for (int i = 0; i < chain.Length; i++) {
- if (chain[i] == null) {
- chain[i] = new FBIKChain();
- }
- }
- chain[0].pin = 0f;
- chain[0].SetNodes(rootNode);
- chain[0].children = new int[4] { 1, 2, 3, 4 };
-
- // Left Arm
- chain[1].SetNodes(references.leftUpperArm, references.leftForearm, references.leftHand);
-
- // Right Arm
- chain[2].SetNodes(references.rightUpperArm, references.rightForearm, references.rightHand);
-
- // Left Leg
- chain[3].SetNodes(references.leftThigh, references.leftCalf, references.leftFoot);
-
- // Right Leg
- chain[4].SetNodes(references.rightThigh, references.rightCalf, references.rightFoot);
-
- // Effectors
- if (effectors.Length != 9) effectors = new IKEffector[9] {
- new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector(), new IKEffector()
- };
-
- effectors[0].bone = rootNode;
- effectors[0].childBones = new Transform[2] { references.leftThigh, references.rightThigh };
-
- effectors[1].bone = references.leftUpperArm;
- effectors[2].bone = references.rightUpperArm;
- effectors[3].bone = references.leftThigh;
- effectors[4].bone = references.rightThigh;
- effectors[5].bone = references.leftHand;
- effectors[6].bone = references.rightHand;
- effectors[7].bone = references.leftFoot;
- effectors[8].bone = references.rightFoot;
-
- effectors[5].planeBone1 = references.leftUpperArm;
- effectors[5].planeBone2 = references.rightUpperArm;
- effectors[5].planeBone3 = rootNode;
- effectors[6].planeBone1 = references.rightUpperArm;
- effectors[6].planeBone2 = references.leftUpperArm;
- effectors[6].planeBone3 = rootNode;
- effectors[7].planeBone1 = references.leftThigh;
- effectors[7].planeBone2 = references.rightThigh;
- effectors[7].planeBone3 = rootNode;
- effectors[8].planeBone1 = references.rightThigh;
- effectors[8].planeBone2 = references.leftThigh;
- effectors[8].planeBone3 = rootNode;
-
- // Child Constraints
- chain[0].childConstraints = new FBIKChain.ChildConstraint[4] {
- new FBIKChain.ChildConstraint(references.leftUpperArm, references.rightThigh, 0f, 1f),
- new FBIKChain.ChildConstraint(references.rightUpperArm, references.leftThigh, 0f, 1f),
- new FBIKChain.ChildConstraint(references.leftUpperArm, references.rightUpperArm),
- new FBIKChain.ChildConstraint(references.leftThigh, references.rightThigh)
-
- };
-
- // IKMappingSpine
- Transform[] spineBones = new Transform[references.spine.Length + 1];
- spineBones[0] = references.pelvis;
- for (int i = 0; i < references.spine.Length; i++) {
- spineBones[i + 1] = references.spine[i];
- }
-
- if (spineMapping == null) {
- spineMapping = new IKMappingSpine();
- spineMapping.iterations = 3;
- }
- spineMapping.SetBones(spineBones, references.leftUpperArm, references.rightUpperArm, references.leftThigh, references.rightThigh);
-
- // IKMappingBone
- int boneMappingsCount = references.head != null? 1: 0;
-
- if (boneMappings.Length != boneMappingsCount) {
- boneMappings = new IKMappingBone[boneMappingsCount];
- for (int i = 0; i < boneMappings.Length; i++) {
- boneMappings[i] = new IKMappingBone();
- }
- if (boneMappingsCount == 1) boneMappings[0].maintainRotationWeight = 0f;
- }
-
- if (boneMappings.Length > 0) boneMappings[0].bone = references.head;
-
- // IKMappingLimb
- if (limbMappings.Length != 4) {
- limbMappings = new IKMappingLimb[4] {
- new IKMappingLimb(), new IKMappingLimb(), new IKMappingLimb(), new IKMappingLimb()
- };
-
- limbMappings[2].maintainRotationWeight = 1f;
- limbMappings[3].maintainRotationWeight = 1f;
- }
-
- limbMappings[0].SetBones(references.leftUpperArm, references.leftForearm, references.leftHand, GetLeftClavicle(references));
- limbMappings[1].SetBones(references.rightUpperArm, references.rightForearm, references.rightHand, GetRightClavicle(references));
- limbMappings[2].SetBones(references.leftThigh, references.leftCalf, references.leftFoot);
- limbMappings[3].SetBones(references.rightThigh, references.rightCalf, references.rightFoot);
- if (Application.isPlaying) Initiate(references.root);
- }
- /*
- * Tries to guess which bone should be the root node
- * */
- public static Transform DetectRootNodeBone(BipedReferences references) {
- if (!references.isFilled) return null;
- if (references.spine.Length < 1) return null;
- int spineLength = references.spine.Length;
- if (spineLength == 1) return references.spine[0];
-
- Vector3 hip = Vector3.Lerp(references.leftThigh.position, references.rightThigh.position, 0.5f);
- Vector3 neck = Vector3.Lerp(references.leftUpperArm.position, references.rightUpperArm.position, 0.5f);
- Vector3 toNeck = neck - hip;
- float toNeckMag = toNeck.magnitude;
-
- if (references.spine.Length < 2) return references.spine[0];
- int rootNodeBone = 0;
- for (int i = 1; i < spineLength; i++) {
- Vector3 hipToBone = references.spine[i].position - hip;
- Vector3 projection = Vector3.Project(hipToBone, toNeck);
-
- float dot = Vector3.Dot(projection.normalized, toNeck.normalized);
- if (dot > 0) {
- float mag = projection.magnitude / toNeckMag;
- if (mag < 0.5f) rootNodeBone = i;
- }
- }
- return references.spine[rootNodeBone];
- }
- /// <summary>
- /// Sets the bend directions of the limbs to the local axes specified by BipedLimbOrientations.
- /// </summary>
- public void SetLimbOrientations(BipedLimbOrientations o) {
- SetLimbOrientation(FullBodyBipedChain.LeftArm, o.leftArm);
- SetLimbOrientation(FullBodyBipedChain.RightArm, o.rightArm);
- SetLimbOrientation(FullBodyBipedChain.LeftLeg, o.leftLeg);
- SetLimbOrientation(FullBodyBipedChain.RightLeg, o.rightLeg);
- }
- #endregion Main Interface
- // Offset applied to the body effector by PullBody
- public Vector3 pullBodyOffset { get; private set; }
- /*
- * Sets the bend direction of a limb to the local axes specified by the LimbOrientation.
- * */
- private void SetLimbOrientation(FullBodyBipedChain chain, BipedLimbOrientations.LimbOrientation limbOrientation) {
- bool inverse = chain == FullBodyBipedChain.LeftArm || chain == FullBodyBipedChain.RightArm;
-
- if (inverse) {
- GetBendConstraint(chain).SetLimbOrientation(-limbOrientation.upperBoneForwardAxis, -limbOrientation.lowerBoneForwardAxis, -limbOrientation.lastBoneLeftAxis);
- GetLimbMapping(chain).SetLimbOrientation(-limbOrientation.upperBoneForwardAxis, -limbOrientation.lowerBoneForwardAxis);
- } else {
- GetBendConstraint(chain).SetLimbOrientation(limbOrientation.upperBoneForwardAxis, limbOrientation.lowerBoneForwardAxis, limbOrientation.lastBoneLeftAxis);
- GetLimbMapping(chain).SetLimbOrientation(limbOrientation.upperBoneForwardAxis, limbOrientation.lowerBoneForwardAxis);
- }
- }
- private static Transform GetLeftClavicle(BipedReferences references) {
- if (references.leftUpperArm == null) return null;
- if (!Contains(references.spine, references.leftUpperArm.parent)) return references.leftUpperArm.parent;
- return null;
- }
-
- private static Transform GetRightClavicle(BipedReferences references) {
- if (references.rightUpperArm == null) return null;
- if (!Contains(references.spine, references.rightUpperArm.parent)) return references.rightUpperArm.parent;
- return null;
- }
-
- private static bool Contains(Transform[] array, Transform transform) {
- foreach (Transform t in array) if (t == transform) return true;
- return false;
- }
- protected override void ReadPose() {
- // Set effectors to their targets
- for (int i = 0; i < effectors.Length; i++) effectors[i].SetToTarget();
- // Pulling the body with the hands
- PullBody();
-
- // Spine stiffness
- float s = Mathf.Clamp(1f - spineStiffness, 0f, 1f);
- chain[0].childConstraints[0].pushElasticity = s;
- chain[0].childConstraints[1].pushElasticity = s;
- base.ReadPose();
- }
- /*
- * Pulling the body with the hands
- * */
- private void PullBody() {
- if (iterations < 1) return;
- // Getting the body positionOffset
- if (pullBodyVertical != 0f || pullBodyHorizontal != 0f) {
- Vector3 offset = GetBodyOffset();
- pullBodyOffset = V3Tools.ExtractVertical(offset, root.up, pullBodyVertical) + V3Tools.ExtractHorizontal(offset, root.up, pullBodyHorizontal);
- bodyEffector.positionOffset += pullBodyOffset;
- }
- }
- /*
- * Get pull offset of the body effector.
- * */
- private Vector3 GetBodyOffset() {
- Vector3 offset = Vector3.zero + GetHandBodyPull(leftHandEffector, leftArmChain, Vector3.zero) * Mathf.Clamp(leftHandEffector.positionWeight, 0f, 1f);
- return offset + GetHandBodyPull(rightHandEffector, rightArmChain, offset) * Mathf.Clamp(rightHandEffector.positionWeight, 0f, 1f);
- }
- /*
- * Get pull offset of a hand
- * */
- private Vector3 GetHandBodyPull(IKEffector effector, FBIKChain arm, Vector3 offset) {
- // Get the vector from shoulder to hand effector
- Vector3 direction = effector.position - (arm.nodes[0].transform.position + offset);
- float armLength = arm.nodes[0].length + arm.nodes[1].length;
-
- // Find delta of effector distance and arm length
- float dirMag = direction.magnitude;
- if (dirMag < armLength) return Vector3.zero;
- float x = dirMag - armLength;
- return (direction / dirMag) * x;
- }
- private Vector3 offset;
- protected override void ApplyBendConstraints() {
- if (iterations > 0) {
- chain[1].bendConstraint.rotationOffset = leftHandEffector.planeRotationOffset;
- chain[2].bendConstraint.rotationOffset = rightHandEffector.planeRotationOffset;
- chain[3].bendConstraint.rotationOffset = leftFootEffector.planeRotationOffset;
- chain[4].bendConstraint.rotationOffset = rightFootEffector.planeRotationOffset;
- } else {
- offset = Vector3.Lerp(effectors[0].positionOffset, effectors[0].position - (effectors[0].bone.position + effectors[0].positionOffset), effectors[0].positionWeight);
- for (int i = 0; i < 5; i++) {
- effectors[i].GetNode(this).solverPosition += offset;
- }
- }
- base.ApplyBendConstraints();
- }
- protected override void WritePose() {
- if (iterations == 0) {
- spineMapping.spineBones[0].position += offset;
- }
- base.WritePose();
- }
- }
- }
|