using UnityEngine; using System.Collections; using System.Collections.Generic; namespace RootMotion.FinalIK { /// /// A full-body IK solver designed specifically for a VR HMD and hand controllers. /// //[HelpURL("http://www.root-motion.com/finalikdox/html/page16.html")] [AddComponentMenu("Scripts/RootMotion.FinalIK/IK/VR IK")] public class VRIK : IK { /// /// VRIK-specific definition of a humanoid biped. /// [System.Serializable] public class References { public Transform root; // 0 [LargeHeader("Spine")] public Transform pelvis; // 1 public Transform spine; // 2 [Tooltip("Optional")] public Transform chest; // 3 Optional [Tooltip("Optional")] public Transform neck; // 4 Optional public Transform head; // 5 [LargeHeader("Left Arm")] [Tooltip("Optional")] public Transform leftShoulder; // 6 Optional [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform leftUpperArm; // 7 [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform leftForearm; // 8 [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform leftHand; // 9 [LargeHeader("Right Arm")] [Tooltip("Optional")] public Transform rightShoulder; // 10 Optional [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform rightUpperArm; // 11 [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform rightForearm; // 12 [Tooltip("VRIK also supports armless characters.If you do not wish to use arms, leave all arm references empty.")] public Transform rightHand; // 13 [LargeHeader("Left Leg")] [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform leftThigh; // 14 Optional [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform leftCalf; // 15 Optional [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform leftFoot; // 16 Optional [Tooltip("Optional")] public Transform leftToes; // 17 Optional [LargeHeader("Right Leg")] [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform rightThigh; // 18 Optional [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform rightCalf; // 19 Optional [Tooltip("VRIK also supports legless characters.If you do not wish to use legs, leave all leg references empty.")] public Transform rightFoot; // 20 Optional [Tooltip("Optional")] public Transform rightToes; // 21 Optional public References() { } public References(BipedReferences b) { root = b.root; pelvis = b.pelvis; spine = b.spine[0]; chest = b.spine.Length > 1? b.spine[1]: null; head = b.head; leftShoulder = b.leftUpperArm.parent; leftUpperArm = b.leftUpperArm; leftForearm = b.leftForearm; leftHand = b.leftHand; rightShoulder = b.rightUpperArm.parent; rightUpperArm = b.rightUpperArm; rightForearm = b.rightForearm; rightHand = b.rightHand; leftThigh = b.leftThigh; leftCalf = b.leftCalf; leftFoot = b.leftFoot; leftToes = b.leftFoot.GetChild(0); rightThigh = b.rightThigh; rightCalf = b.rightCalf; rightFoot = b.rightFoot; rightToes = b.rightFoot.GetChild(0); } /// /// Returns an array of all the Transforms in the definition. /// public Transform[] GetTransforms() { return new Transform[22] { root, pelvis, spine, chest, neck, head, leftShoulder, leftUpperArm, leftForearm, leftHand, rightShoulder, rightUpperArm, rightForearm, rightHand, leftThigh, leftCalf, leftFoot, leftToes, rightThigh, rightCalf, rightFoot, rightToes }; } /// /// Returns true if all required Transforms have been assigned (shoulder, toe and neck bones are optional). /// public bool isFilled { get { if ( root == null || pelvis == null || spine == null || head == null ) return false; bool noArmBones = leftUpperArm == null && leftForearm == null && leftHand == null && rightUpperArm == null && rightForearm == null && rightHand == null; bool atLeastOneArmBoneMissing = leftUpperArm == null || leftForearm == null || leftHand == null || rightUpperArm == null || rightForearm == null || rightHand == null; // If all leg bones are null, it is valid bool noLegBones = leftThigh == null && leftCalf == null && leftFoot == null && rightThigh == null && rightCalf == null && rightFoot == null; bool atLeastOneLegBoneMissing = leftThigh == null || leftCalf == null || leftFoot == null || rightThigh == null || rightCalf == null || rightFoot == null; if (atLeastOneLegBoneMissing && !noLegBones) return false; if (atLeastOneArmBoneMissing && !noArmBones) return false; // Shoulder, toe and neck bones are optional return true; } } /// /// Returns true if none of the Transforms have been assigned. /// public bool isEmpty { get { if ( root != null || pelvis != null || spine != null || chest != null || neck != null || head != null || leftShoulder != null || leftUpperArm != null || leftForearm != null || leftHand != null || rightShoulder != null || rightUpperArm != null || rightForearm != null || rightHand != null || leftThigh != null || leftCalf != null || leftFoot != null || leftToes != null || rightThigh != null || rightCalf != null || rightFoot != null || rightToes != null ) return false; return true; } } /// /// Auto-detects VRIK references. Works with a Humanoid Animator on the root gameobject only. /// public static bool AutoDetectReferences(Transform root, out References references) { references = new References(); var animator = root.GetComponentInChildren(); if (animator == null || !animator.isHuman) { Debug.LogWarning("VRIK needs a Humanoid Animator to auto-detect biped references. Please assign references manually."); return false; } references.root = root; references.pelvis = animator.GetBoneTransform(HumanBodyBones.Hips); references.spine = animator.GetBoneTransform(HumanBodyBones.Spine); references.chest = animator.GetBoneTransform(HumanBodyBones.Chest); references.neck = animator.GetBoneTransform(HumanBodyBones.Neck); references.head = animator.GetBoneTransform(HumanBodyBones.Head); references.leftShoulder = animator.GetBoneTransform(HumanBodyBones.LeftShoulder); references.leftUpperArm = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm); references.leftForearm = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm); references.leftHand = animator.GetBoneTransform(HumanBodyBones.LeftHand); references.rightShoulder = animator.GetBoneTransform(HumanBodyBones.RightShoulder); references.rightUpperArm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm); references.rightForearm = animator.GetBoneTransform(HumanBodyBones.RightLowerArm); references.rightHand = animator.GetBoneTransform(HumanBodyBones.RightHand); references.leftThigh = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg); references.leftCalf = animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg); references.leftFoot = animator.GetBoneTransform(HumanBodyBones.LeftFoot); references.leftToes = animator.GetBoneTransform(HumanBodyBones.LeftToes); references.rightThigh = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg); references.rightCalf = animator.GetBoneTransform(HumanBodyBones.RightLowerLeg); references.rightFoot = animator.GetBoneTransform(HumanBodyBones.RightFoot); references.rightToes = animator.GetBoneTransform(HumanBodyBones.RightToes); return true; } } // Open the User Manual URL [ContextMenu("User Manual")] protected override void OpenUserManual() { Application.OpenURL("http://www.root-motion.com/finalikdox/html/page16.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_v_r_i_k.html"); } // Open a video tutorial about setting up the component [ContextMenu("TUTORIAL VIDEO (STEAMVR SETUP)")] void OpenSetupTutorial() { Application.OpenURL("https://www.youtube.com/watch?v=6Pfx7lYQiIA&feature=youtu.be"); } /// /// Bone mapping. Right-click on the component header and select 'Auto-detect References' of fill in manually if not a Humanoid character. Chest, neck, shoulder and toe bones are optional. VRIK also supports legless characters. If you do not wish to use legs, leave all leg references empty. /// [ContextMenuItem("Auto-detect References", "AutoDetectReferences")] [Tooltip("Bone mapping. Right-click on the component header and select 'Auto-detect References' of fill in manually if not a Humanoid character. Chest, neck, shoulder and toe bones are optional. VRIK also supports legless characters. If you do not wish to use legs, leave all leg references empty.")] public References references = new References(); /// /// The solver. /// [Tooltip("The VRIK solver.")] public IKSolverVR solver = new IKSolverVR(); /// /// Auto-detects bone references for this VRIK. Works with a Humanoid Animator on the gameobject only. /// [ContextMenu("Auto-detect References")] public void AutoDetectReferences() { References.AutoDetectReferences(transform, out references); } /// /// Fills in arm wristToPalmAxis and palmToThumbAxis. /// [ContextMenu("Guess Hand Orientations")] public void GuessHandOrientations() { solver.GuessHandOrientations(references, false); } public override IKSolver GetIKSolver() { return solver as IKSolver; } protected override void InitiateSolver() { if (references.isEmpty) AutoDetectReferences(); if (references.isFilled) solver.SetToReferences(references); base.InitiateSolver(); } protected override void UpdateSolver() { if (references.root != null && references.root.localScale == Vector3.zero) { Debug.LogError("VRIK Root Transform's scale is zero, can not update VRIK. Make sure you have not calibrated the character to a zero scale.", transform); enabled = false; return; } base.UpdateSolver(); } } }