示例#1
0
        public static bool AutoDetectReferences(ref BipedReferences references, Transform root, BipedReferences.AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }
            references.root = root;
            Animator component = root.GetComponent <Animator>();

            if (component != null && component.isHuman)
            {
                BipedReferences.AssignHumanoidReferences(ref references, component, autoDetectParams);
                return(true);
            }
            BipedReferences.DetectReferencesByNaming(ref references, root, autoDetectParams);
            Warning.logged = false;
            if (!references.isFilled)
            {
                Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
                return(false);
            }
            string message = "";

            if (BipedReferences.SetupError(references, ref message))
            {
                Warning.Log(message, references.root, true);
                return(false);
            }
            if (BipedReferences.SetupWarning(references, ref message))
            {
                Warning.Log(message, references.root, true);
            }
            return(true);
        }
示例#2
0
        /// <summary>
        /// Automatically detects biped bones. Returns true if a valid biped has been referenced.
        /// </summary>
        public static bool AutoDetectReferences(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }
            references.root = root;

            // Try with naming and hierarchy first
            DetectReferencesByNaming(ref references, root, autoDetectParams);

            if (references.isValid && CheckSetupError(references, false) && CheckSetupWarning(references, false))
            {
                return(true);
            }

            // If that failed try the Animator
            AssignHumanoidReferences(ref references, root.GetComponent <Animator>(), autoDetectParams);

            bool isValid = references.isValid;

            if (!isValid)
            {
                Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
            }

            return(isValid);
        }
示例#3
0
        // Check if eyes are properly set up
        private static bool CheckEyesError(BipedReferences references, bool log)
        {
            if (references.eyes.Length == 0)
            {
                return(true);
            }

            for (int i = 0; i < references.eyes.Length; i++)
            {
                if (references.eyes[i] == null)
                {
                    if (log)
                    {
                        Warning.Log("BipedReferences eye bone at index " + i + " is null.", references.root, true);
                    }
                    return(false);
                }
            }

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);

            if (duplicate != null)
            {
                if (log)
                {
                    Warning.Log(duplicate.name + " is represented multiple times in BipedReferences eyes.", references.eyes[0], true);
                }
                return(false);
            }

            return(true);
        }
示例#4
0
        // Check if eyes are properly set up
        private static bool EyesError(BipedReferences references, ref string errorMessage)
        {
            // No eyes might be a valid setup
            if (references.eyes.Length == 0)
            {
                return(false);
            }

            for (int i = 0; i < references.eyes.Length; i++)
            {
                if (references.eyes[i] == null)
                {
                    errorMessage = "BipedReferences eye bone at index " + i + " is null.";
                    return(true);
                }
            }

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);

            if (duplicate != null)
            {
                errorMessage = duplicate.name + " is represented multiple times in BipedReferences eyes.";
                return(true);
            }

            return(false);
        }
示例#5
0
        /// <summary>
        /// Checks the setup for definite problems.
        /// </summary>
        public static bool SetupError(BipedReferences references, ref string errorMessage)
        {
            if (!references.isFilled)
            {
                errorMessage = "BipedReferences contains one or more missing Transforms.";
                return(true);
            }

            if (LimbError(references.leftThigh, references.leftCalf, references.leftFoot, ref errorMessage))
            {
                return(true);
            }
            if (LimbError(references.rightThigh, references.rightCalf, references.rightFoot, ref errorMessage))
            {
                return(true);
            }
            if (LimbError(references.leftUpperArm, references.leftForearm, references.leftHand, ref errorMessage))
            {
                return(true);
            }
            if (LimbError(references.rightUpperArm, references.rightForearm, references.rightHand, ref errorMessage))
            {
                return(true);
            }
            if (SpineError(references, ref errorMessage))
            {
                return(true);
            }
            if (EyesError(references, ref errorMessage))
            {
                return(true);
            }

            return(false);
        }
示例#6
0
        // Determines whether a bone is valid for being added into the spine
        private static bool AddBoneToSpine(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams)
        {
            if (bone == references.root)
            {
                return(false);
            }

            bool isLegsParent = bone == references.leftThigh.parent;

            if (isLegsParent && !autoDetectParams.legsParentInSpine)
            {
                return(false);
            }

            if (references.pelvis != null)
            {
                if (bone == references.pelvis)
                {
                    return(false);
                }
                if (Hierarchy.IsAncestor(references.pelvis, bone))
                {
                    return(false);
                }
            }

            return(true);
        }
        private static bool CheckSpineError(BipedReferences references, bool log)
        {
            if (references.spine.Length == 0)
            {
                return(true);
            }
            for (int i = 0; i < references.spine.Length; i++)
            {
                if (references.spine[i] == null)
                {
                    if (log)
                    {
                        Warning.Log("BipedReferences spine bone at index " + i + " is null.", references.root, true);
                    }
                    return(false);
                }
            }
            Transform transform = (Transform)Hierarchy.ContainsDuplicate(references.spine);

            if (transform != null)
            {
                if (log)
                {
                    Warning.Log(transform.name + " is represented multiple times in BipedReferences spine.", references.spine[0], true);
                }
                return(false);
            }
            if (!Hierarchy.HierarchyIsValid(references.spine))
            {
                if (log)
                {
                    Warning.Log("BipedReferences spine hierarchy is invalid. Bone transforms in the spine do not belong to the same ancestry. Please make sure the bones are parented to each other.", references.spine[0], true);
                }
                return(false);
            }
            for (int j = 0; j < references.spine.Length; j++)
            {
                bool flag = false;
                if (j == 0 && references.spine[j].position == references.pelvis.position)
                {
                    flag = true;
                }
                if (j != 0 && references.spine.Length > 1 && references.spine[j].position == references.spine[j - 1].position)
                {
                    flag = true;
                }
                if (flag)
                {
                    if (log)
                    {
                        Warning.Log("Biped's spine bone nr " + j + " position is the same as it's parent spine/pelvis bone's position. Please remove this bone from the spine.", references.spine[j], true);
                    }
                    return(false);
                }
            }
            return(true);
        }
示例#8
0
        /// <summary>
        /// Fills in BipedReferences using Animator.GetBoneTransform().
        /// </summary>
        public static void AssignHumanoidReferences(ref BipedReferences references, Animator animator, AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }

            if (animator == null || !animator.isHuman)
            {
                return;
            }

            references.spine = new Transform[0];
            references.eyes  = new Transform[0];

            references.head = animator.GetBoneTransform(HumanBodyBones.Head);

            references.leftThigh = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
            references.leftCalf  = animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg);
            references.leftFoot  = animator.GetBoneTransform(HumanBodyBones.LeftFoot);

            references.rightThigh = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg);
            references.rightCalf  = animator.GetBoneTransform(HumanBodyBones.RightLowerLeg);
            references.rightFoot  = animator.GetBoneTransform(HumanBodyBones.RightFoot);

            references.leftUpperArm = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
            references.leftForearm  = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
            references.leftHand     = animator.GetBoneTransform(HumanBodyBones.LeftHand);

            references.rightUpperArm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
            references.rightForearm  = animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
            references.rightHand     = animator.GetBoneTransform(HumanBodyBones.RightHand);

            references.pelvis = animator.GetBoneTransform(HumanBodyBones.Hips);

            AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Spine));
            AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Chest));

            // Make sure the neck bone is not above the arms
            if (references.leftUpperArm != null)
            {
                if (!IsNeckBone(animator.GetBoneTransform(HumanBodyBones.Neck), references.leftUpperArm))
                {
                    AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Neck));
                }
            }

            if (autoDetectParams.includeEyes)
            {
                AddBoneToHierarchy(ref references.eyes, animator.GetBoneTransform(HumanBodyBones.LeftEye));
                AddBoneToHierarchy(ref references.eyes, animator.GetBoneTransform(HumanBodyBones.RightEye));
            }
        }
 public static bool CheckSetupError(BipedReferences references, bool log)
 {
     if (!references.isValid)
     {
         if (log)
         {
             Warning.Log("BipedReferences contains one or more missing Transforms.", references.root, true);
         }
         return(false);
     }
     return(BipedReferences.CheckLimbError(references.leftThigh, references.leftCalf, references.leftFoot, log) && BipedReferences.CheckLimbError(references.rightThigh, references.rightCalf, references.rightFoot, log) && BipedReferences.CheckLimbError(references.leftUpperArm, references.leftForearm, references.leftHand, log) && BipedReferences.CheckLimbError(references.rightUpperArm, references.rightForearm, references.rightHand, log) && BipedReferences.CheckSpineError(references, log) && BipedReferences.CheckEyesError(references, log));
 }
示例#10
0
        // Check if spine is properly set up
        private static bool SpineError(BipedReferences references, ref string errorMessage)
        {
            // No spine might be a valid setup in some cases
            if (references.spine.Length == 0)
            {
                return(false);
            }

            for (int i = 0; i < references.spine.Length; i++)
            {
                if (references.spine[i] == null)
                {
                    errorMessage = "BipedReferences spine bone at index " + i + " is null.";
                    return(true);
                }
            }

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.spine);

            if (duplicate != null)
            {
                errorMessage = duplicate.name + " is represented multiple times in BipedReferences spine.";
                return(true);
            }

            if (!Hierarchy.HierarchyIsValid(references.spine))
            {
                errorMessage = "BipedReferences spine hierarchy is invalid. Bone transforms in the spine do not belong to the same ancestry. Please make sure the bones are parented to each other.";
                return(true);
            }

            for (int i = 0; i < references.spine.Length; i++)
            {
                bool matchesParentPosition = false;
                if (i == 0 && references.spine[i].position == references.pelvis.position)
                {
                    matchesParentPosition = true;
                }
                if (i != 0 && references.spine.Length > 1 && references.spine[i].position == references.spine[i - 1].position)
                {
                    matchesParentPosition = true;
                }

                if (matchesParentPosition)
                {
                    errorMessage = "Biped's spine bone nr " + i + " position is the same as it's parent spine/pelvis bone's position. Please remove this bone from the spine.";
                    return(true);
                }
            }

            return(false);
        }
示例#11
0
        private static bool FacingAxisWarning(BipedReferences references, ref string warningMessage)
        {
            Vector3 vector  = references.rightHand.position - references.leftHand.position;
            Vector3 vector2 = references.rightFoot.position - references.leftFoot.position;
            float   num     = Vector3.Dot(vector.normalized, references.root.right);
            float   num2    = Vector3.Dot(vector2.normalized, references.root.right);

            if (num < 0f || num2 < 0f)
            {
                warningMessage = "Biped does not seem to be facing it's forward axis. Please make sure that in the initial pose the character is facing towards the positive Z axis of the Biped root gameobject.";
                return(true);
            }
            return(false);
        }
示例#12
0
        private static bool RootHeightWarning(BipedReferences references, ref string warningMessage)
        {
            if (references.head == null)
            {
                return(false);
            }
            float verticalOffset = BipedReferences.GetVerticalOffset(references.head.position, references.leftFoot.position, references.root.rotation);

            if (BipedReferences.GetVerticalOffset(references.root.position, references.leftFoot.position, references.root.rotation) / verticalOffset > 0.2f)
            {
                warningMessage = "Biped's root Transform's position should be at ground level relative to the character (at the character's feet not at it's pelvis).";
                return(true);
            }
            return(false);
        }
示例#13
0
        // Determines whether a bone is valid for being added into the eyes array
        private static bool AddBoneToEyes(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams)
        {
            if (references.head != null)
            {
                if (!Hierarchy.IsAncestor(bone, references.head))
                {
                    return(false);
                }
            }

            if (bone.GetComponent <SkinnedMeshRenderer>() != null)
            {
                return(false);
            }

            return(true);
        }
示例#14
0
        // Check if the character is facing the correct axis
        private static bool FacingAxisWarning(BipedReferences references, ref string warningMessage)
        {
            Vector3 handsLeftToRight = references.rightHand.position - references.leftHand.position;
            Vector3 feetLeftToRight  = references.rightFoot.position - references.leftFoot.position;

            float dotHands = Vector3.Dot(handsLeftToRight.normalized, references.root.right);
            float dotFeet  = Vector3.Dot(feetLeftToRight.normalized, references.root.right);

            if (dotHands < 0 || dotFeet < 0)
            {
                warningMessage = "Biped does not seem to be facing it's forward axis. " +
                                 "Please make sure that in the initial pose the character is facing towards the positive Z axis of the Biped root gameobject.";
                return(true);
            }

            return(false);
        }
示例#15
0
        /// <summary>
        /// Checks the setup for possible problems.
        /// </summary>
        public static bool CheckSetup(BipedReferences references, bool log = true)
        {
            if (!references.isValid)
            {
                return(false);
            }

            if (!CheckLimb(references.leftThigh, references.leftCalf, references.leftFoot, log))
            {
                return(false);
            }
            if (!CheckLimb(references.rightThigh, references.rightCalf, references.rightFoot, log))
            {
                return(false);
            }
            if (!CheckLimb(references.leftUpperArm, references.leftForearm, references.leftHand, log))
            {
                return(false);
            }
            if (!CheckLimb(references.rightUpperArm, references.rightForearm, references.rightHand, log))
            {
                return(false);
            }

            if (!CheckSpine(references, log))
            {
                return(false);
            }
            if (!CheckEyes(references, log))
            {
                return(false);
            }

            if (!CheckRootHeight(references, log))
            {
                return(false);
            }
            if (!CheckFacingAxis(references, log))
            {
                return(false);
            }

            return(true);
        }
示例#16
0
        private static bool CheckRootHeightWarning(BipedReferences references, bool log)
        {
            if (references.head == null)
            {
                return(true);
            }
            float verticalOffset  = BipedReferences.GetVerticalOffset(references.head.position, references.leftFoot.position, references.root.rotation);
            float verticalOffset2 = BipedReferences.GetVerticalOffset(references.root.position, references.leftFoot.position, references.root.rotation);

            if (verticalOffset2 / verticalOffset > 0.2f)
            {
                if (log)
                {
                    Warning.Log("Biped's root Transform's position should be at ground level relative to the character (at the character's feet not at it's pelvis).", references.root, true);
                }
                return(false);
            }
            return(true);
        }
示例#17
0
        // Check if spine is properly set up
        private static bool CheckSpineError(BipedReferences references, bool log)
        {
            if (references.spine.Length == 0)
            {
                return(true);
            }

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.spine);

            if (duplicate != null)
            {
                if (log)
                {
                    Warning.Log(duplicate.name + " is represented multiple times in BipedReferences spine.", references.spine[0], true);
                }
                return(false);
            }

            if (!Hierarchy.HierarchyIsValid(references.spine))
            {
                if (log)
                {
                    Warning.Log("BipedReferences spine hierarchy is invalid. Bone transforms in the spine do not belong to the same ancestry. Please make sure the bones are parented to each other.", references.spine[0], true);
                }
                return(false);
            }

            for (int i = 0; i < references.spine.Length; i++)
            {
                bool matchesParentPositon = i == 0? references.spine[i].position == references.pelvis.position: references.spine[i].position == references.spine[i - 1].position;

                if (matchesParentPositon)
                {
                    if (log)
                    {
                        Warning.Log("Biped's spine bone nr " + i + " position is the same as it's parent spine/pelvis bone's position. Please remove this bone from the spine.", references.spine[i], true);
                    }
                    return(false);
                }
            }

            return(true);
        }
示例#18
0
        /// <summary>
        /// Automatically detects biped bones. Returns true if a valid biped has been referenced.
        /// </summary>
        public static bool AutoDetectReferences(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }
            references.root = root;

            // If that failed try the Animator
            var animator = root.GetComponent <Animator>();

            if (animator != null && animator.isHuman)
            {
                AssignHumanoidReferences(ref references, animator, autoDetectParams);
                return(true);                // Assume humanoids are always valid
            }

            // Try with naming and hierarchy first
            DetectReferencesByNaming(ref references, root, autoDetectParams);

            Warning.logged = false;

            if (!references.isFilled)
            {
                Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
                return(false);
            }

            string message = "";

            if (SetupError(references, ref message))
            {
                Warning.Log(message, references.root, true);
                return(false);
            }

            if (SetupWarning(references, ref message))
            {
                Warning.Log(message, references.root, true);
            }

            return(true);
        }
示例#19
0
        // Check if eyes are properly set up
        private static bool CheckEyesError(BipedReferences references, bool log)
        {
            if (references.eyes.Length == 0)
            {
                return(true);
            }

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);

            if (duplicate != null)
            {
                if (log)
                {
                    Warning.Log(duplicate.name + " is represented multiple times in BipedReferences eyes.", references.eyes[0], true);
                }
                return(false);
            }

            return(true);
        }
示例#20
0
        public static bool AutoDetectReferences(ref BipedReferences references, Transform root, BipedReferences.AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }
            references.root = root;
            BipedReferences.DetectReferencesByNaming(ref references, root, autoDetectParams);
            if (references.isValid && BipedReferences.CheckSetupError(references, false) && BipedReferences.CheckSetupWarning(references, false))
            {
                return(true);
            }
            BipedReferences.AssignHumanoidReferences(ref references, root.GetComponent <Animator>(), autoDetectParams);
            bool isValid = references.isValid;

            if (!isValid)
            {
                Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
            }
            return(isValid);
        }
示例#21
0
        /// <summary>
        /// Checks the setup for possible problems.
        /// </summary>
        public static bool CheckSetupWarning(BipedReferences references, bool log)
        {
            if (!CheckLimbWarning(references.leftThigh, references.leftCalf, references.leftFoot, log))
            {
                return(false);
            }
            if (!CheckLimbWarning(references.rightThigh, references.rightCalf, references.rightFoot, log))
            {
                return(false);
            }
            if (!CheckLimbWarning(references.leftUpperArm, references.leftForearm, references.leftHand, log))
            {
                return(false);
            }
            if (!CheckLimbWarning(references.rightUpperArm, references.rightForearm, references.rightHand, log))
            {
                return(false);
            }

            if (!CheckSpineWarning(references, log))
            {
                return(false);
            }
            if (!CheckEyesWarning(references, log))
            {
                return(false);
            }

            if (!CheckRootHeightWarning(references, log))
            {
                return(false);
            }
            if (!CheckFacingAxisWarning(references, log))
            {
                return(false);
            }

            return(true);
        }
示例#22
0
        /// <summary>
        /// Checks the setup for possible problems.
        /// </summary>
        public static bool SetupWarning(BipedReferences references, ref string warningMessage)
        {
            if (LimbWarning(references.leftThigh, references.leftCalf, references.leftFoot, ref warningMessage))
            {
                return(true);
            }
            if (LimbWarning(references.rightThigh, references.rightCalf, references.rightFoot, ref warningMessage))
            {
                return(true);
            }
            if (LimbWarning(references.leftUpperArm, references.leftForearm, references.leftHand, ref warningMessage))
            {
                return(true);
            }
            if (LimbWarning(references.rightUpperArm, references.rightForearm, references.rightHand, ref warningMessage))
            {
                return(true);
            }
            if (SpineWarning(references, ref warningMessage))
            {
                return(true);
            }
            if (EyesWarning(references, ref warningMessage))
            {
                return(true);
            }
            if (RootHeightWarning(references, ref warningMessage))
            {
                return(true);
            }
            if (FacingAxisWarning(references, ref warningMessage))
            {
                return(true);
            }

            return(false);
        }
示例#23
0
        private static bool EyesError(BipedReferences references, ref string errorMessage)
        {
            if (references.eyes.Length == 0)
            {
                return(false);
            }
            for (int i = 0; i < references.eyes.Length; i++)
            {
                if (references.eyes[i] == null)
                {
                    errorMessage = "BipedReferences eye bone at index " + i + " is null.";
                    return(true);
                }
            }
            UnityEngine.Object[] objects   = references.eyes;
            Transform            transform = (Transform)Hierarchy.ContainsDuplicate(objects);

            if (transform != null)
            {
                errorMessage = transform.name + " is represented multiple times in BipedReferences eyes.";
                return(true);
            }
            return(false);
        }
 private static bool LimbWarning(Transform bone1, Transform bone2, Transform bone3, ref string warningMessage) => default; // 0x00000001804BA9B0-0x00000001804BADD0
 private static bool SpineError(BipedReferences references, ref string errorMessage) => default;                           // 0x00000001804BB370-0x00000001804BB7F0
示例#25
0
 // Check if eyes are properly set up
 private static bool EyesWarning(BipedReferences references, ref string warningMessage)
 {
     // Maybe need to add something here in the future
     return(false);
 }
 private static bool SpineWarning(BipedReferences references, ref string warningMessage) => default;                       // 0x0000000180250A70-0x0000000180250A80
 private static bool EyesError(BipedReferences references, ref string errorMessage) => default;                            // 0x00000001804B97A0-0x00000001804B99A0
示例#27
0
		/// <summary>
		/// Automatically detects biped bones. Returns true if a valid biped has been referenced.
		/// </summary>
		public static bool AutoDetectReferences(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams) {
			if (references == null) references = new BipedReferences();
			references.root = root;

			// If that failed try the Animator
			var animator = root.GetComponent<Animator>();
			if (animator != null && animator.isHuman) {
				AssignHumanoidReferences(ref references, animator, autoDetectParams);
				return true; // Assume humanoids are always valid
			}

			// Try with naming and hierarchy first
			DetectReferencesByNaming(ref references, root, autoDetectParams);

			Warning.logged = false;

			if (!references.isFilled) {
				Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
				return false;
			}

			if (!CheckSetupError(references, true)) return false;

			CheckSetupWarning(references, true);
			
			return true;
		}
示例#28
0
        /// <summary>
        /// Detects the references based on naming and hierarchy.
        /// </summary>
        public static void DetectReferencesByNaming(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams)
        {
            if (references == null)
            {
                references = new BipedReferences();
            }

            Transform[] children = root.GetComponentsInChildren <Transform>();

            // Find limbs
            DetectLimb(BipedNaming.BoneType.Arm, BipedNaming.BoneSide.Left, ref references.leftUpperArm, ref references.leftForearm, ref references.leftHand, children);
            DetectLimb(BipedNaming.BoneType.Arm, BipedNaming.BoneSide.Right, ref references.rightUpperArm, ref references.rightForearm, ref references.rightHand, children);
            DetectLimb(BipedNaming.BoneType.Leg, BipedNaming.BoneSide.Left, ref references.leftThigh, ref references.leftCalf, ref references.leftFoot, children);
            DetectLimb(BipedNaming.BoneType.Leg, BipedNaming.BoneSide.Right, ref references.rightThigh, ref references.rightCalf, ref references.rightFoot, children);

            // Find head bone
            references.head = BipedNaming.GetBone(children, BipedNaming.BoneType.Head);

            // Find Pelvis
            references.pelvis = BipedNaming.GetNamingMatch(children, BipedNaming.pelvis);

            // If pelvis is not an ancestor of a leg, it is not a valid pelvis
            if (references.pelvis == null || !Hierarchy.IsAncestor(references.leftThigh, references.pelvis))
            {
                if (references.leftThigh != null)
                {
                    references.pelvis = references.leftThigh.parent;
                }
            }

            // Find spine and head bones
            if (references.leftUpperArm != null && references.rightUpperArm != null && references.pelvis != null && references.leftThigh != null)
            {
                Transform neck = Hierarchy.GetFirstCommonAncestor(references.leftUpperArm, references.rightUpperArm);

                if (neck != null)
                {
                    Transform[] inverseSpine = new Transform[1] {
                        neck
                    };
                    Hierarchy.AddAncestors(inverseSpine[0], references.pelvis, ref inverseSpine);

                    references.spine = new Transform[0];
                    for (int i = inverseSpine.Length - 1; i > -1; i--)
                    {
                        if (AddBoneToSpine(inverseSpine[i], ref references, autoDetectParams))
                        {
                            Array.Resize(ref references.spine, references.spine.Length + 1);
                            references.spine[references.spine.Length - 1] = inverseSpine[i];
                        }
                    }

                    // Head
                    if (references.head == null)
                    {
                        for (int i = 0; i < neck.childCount; i++)
                        {
                            Transform child = neck.GetChild(i);

                            if (!Hierarchy.ContainsChild(child, references.leftUpperArm) && !Hierarchy.ContainsChild(child, references.rightUpperArm))
                            {
                                references.head = child;
                                break;
                            }
                        }
                    }
                }
            }

            // Find eye bones
            Transform[] eyes = BipedNaming.GetBonesOfType(BipedNaming.BoneType.Eye, children);
            references.eyes = new Transform[0];

            if (autoDetectParams.includeEyes)
            {
                for (int i = 0; i < eyes.Length; i++)
                {
                    if (AddBoneToEyes(eyes[i], ref references, autoDetectParams))
                    {
                        Array.Resize(ref references.eyes, references.eyes.Length + 1);
                        references.eyes[references.eyes.Length - 1] = eyes[i];
                    }
                }
            }
        }
        public static BipedRagdollReferences FromBipedReferences(BipedReferences biped)
        {
            BipedRagdollReferences r = new BipedRagdollReferences();

            r.root = biped.root;

            r.hips = biped.pelvis;

            if (biped.spine != null && biped.spine.Length > 0) {
                r.spine = biped.spine[0];
                if (biped.spine.Length > 1) r.chest = biped.spine[biped.spine.Length - 1];
            }

            r.head = biped.head;

            r.leftUpperArm = biped.leftUpperArm;
            r.leftLowerArm = biped.leftForearm;
            r.leftHand = biped.leftHand;

            r.rightUpperArm = biped.rightUpperArm;
            r.rightLowerArm = biped.rightForearm;
            r.rightHand = biped.rightHand;

            r.leftUpperLeg = biped.leftThigh;
            r.leftLowerLeg = biped.leftCalf;
            r.leftFoot = biped.leftFoot;

            r.rightUpperLeg = biped.rightThigh;
            r.rightLowerLeg = biped.rightCalf;
            r.rightFoot = biped.rightFoot;

            return r;
        }
示例#30
0
		// Check if BipedIK transform position is at the character's feet
		private static bool CheckRootHeightWarning(BipedReferences references, bool log) {
			if (references.head == null) return true;
			
			float headHeight = GetVerticalOffset(references.head.position, references.leftFoot.position, references.root.rotation);
			float rootHeight = GetVerticalOffset(references.root.position, references.leftFoot.position, references.root.rotation);
			
			if (rootHeight / headHeight > 0.2f) {
				if (log) Warning.Log("Biped's root Transform's position should be at ground level relative to the character (at the character's feet not at it's pelvis).", references.root, true);
				return false;
			}
			
			return true;
		}
示例#31
0
		/// <summary>
		/// Automatically detects biped bones. Returns true if a valid biped has been referenced.
		/// </summary>
		public static bool AutoDetectReferences(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams) {
			if (references == null) references = new BipedReferences();
			references.root = root;
			
			// Try with naming and hierarchy first
			DetectReferencesByNaming(ref references, root, autoDetectParams);
			
			if (references.isValid && CheckSetupError(references, false) && CheckSetupWarning(references, false)) return true;
			
			// If that failed try the Animator
			AssignHumanoidReferences(ref references, root.GetComponent<Animator>(), autoDetectParams);
			
			bool isValid = references.isValid;
			
			if (!isValid) {
				Warning.Log("BipedReferences contains one or more missing Transforms.", root, true);
			}
			
			return isValid;
		}
示例#32
0
 // Check if eyes are properly set up
 private static bool CheckEyesWarning(BipedReferences references, bool log)
 {
     // Maybe need to add something here in the future
     return(true);
 }
        /*
         * Check if eyes are properly set up
         * */
        private static bool CheckEyes(BipedReferences references, bool log)
        {
            if (references.eyes.Length == 0) return true;

            Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);
            if (duplicate != null) {
                if (log) Warning.Log(duplicate.name + " is represented multiple times in BipedReferences eyes.", references.eyes[0], true);
                return false;
            }

            return true;
        }
        void OnEnable()
        {
            if (script == null) return;
            if (Application.isPlaying) return;

            // Autodetection
            if (script.references.IsEmpty(false)) {
                Animator animator = script.gameObject.GetComponent<Animator>();

                if (animator == null && script.references.root != null) {
                    animator = script.references.root.GetComponentInChildren<Animator>();
                    if (animator == null) animator = GetAnimatorInParents(script.references.root);
                }

                if (animator != null) {
                    script.references = BipedRagdollReferences.FromAvatar(animator);

                } else {
                    BipedReferences r = new BipedReferences();
                    BipedReferences.AutoDetectReferences(ref r, script.transform, BipedReferences.AutoDetectParams.Default);
                    if (r.isFilled) script.references = BipedRagdollReferences.FromBipedReferences(r);
                }

                if (!OnRoot()) {
                    Debug.LogWarning("BipedRagdollCreator must be added to the root of the character. Destroying the component.");
                    DestroyImmediate(script);
                    return;
                }

                if (script.references.IsValid()) {
                    script.options = BipedRagdollCreator.AutodetectOptions(script.references);
                    //BipedRagdollCreator.Create(script.references, script.options);

                    //if (animator != null) DestroyImmediate(animator);
                    //if (script.GetComponent<Animation>() != null) DestroyImmediate(script.GetComponent<Animation>());
                }
            }
        }
    private bool BipedIsValid(BipedReferences references, IKSolverFullBodyBiped solver, Transform context, bool log)
    {
        BipedReferences.CheckSetup(script.references);

        if (!references.isValid)
        {
            //if (log) Warning.Log("BipedReferences contains one or more missing Transforms.", context, true);
            return false;
        }
        if (references.spine.Length == 0)
        {
            //if (log) Warning.Log("Biped has no spine bones.", context, true);
            return false;
        }

        if (solver.rootNode == null)
        {
            //if (log) Warning.Log("Root Node bone is null.", context, true);
            return false;
        }

        Vector3 toRightShoulder = references.rightUpperArm.position - references.leftUpperArm.position;
        Vector3 shoulderToRootNode = solver.rootNode.position - references.leftUpperArm.position;
        float dot = Vector3.Dot(toRightShoulder.normalized, shoulderToRootNode.normalized);

        if (dot > 0.95f)
        {
            if (log) Warning.Log("The root node, the left upper arm and the right upper arm bones should ideally form a triangle that is as close to equilateral as possible. " +
                "Currently the root node bone seems to be very close to the line between the left upper arm and the right upper arm bones. This might cause unwanted behaviour like the spine turning upside down when pulled by a hand effector." +
                "Please set the root node bone to be one of the lower bones in the spine.", context, true);
        }

        Vector3 toRightThigh = references.rightThigh.position - references.leftThigh.position;
        Vector3 thighToRootNode = solver.rootNode.position - references.leftThigh.position;
        dot = Vector3.Dot(toRightThigh.normalized, thighToRootNode.normalized);

        if (dot > 0.95f && log)
        {
            Warning.Log("The root node, the left thigh and the right thigh bones should ideally form a triangle that is as close to equilateral as possible. " +
                "Currently the root node bone seems to be very close to the line between the left thigh and the right thigh bones. This might cause unwanted behaviour like the hip turning upside down when pulled by an effector." +
                "Please set the root node bone to be one of the higher bones in the spine.", context, true);
        }

        /*
        Vector3 shoulderCross = Vector3.Cross(toRightShoulder, shoulderToRootNode);
        Vector3 charCross = Vector3.Cross(references.rightHand.position - references.leftHand.position, references.rightFoot.position - references.leftHand.position);
			
        float shoulderInvertDot = Vector3.Dot(shoulderCross.normalized, charCross.normalized);
			
        if (shoulderInvertDot < 0 && log) {
            Warning.Log("The triangle formed by the root node, left upper arm and right upper arm bones seems to be flipped. The root node bone should be below the upper arm bones.", context, true);
        }
			
        Vector3 thighCross = Vector3.Cross(toRightThigh, thighToRootNode);
			
        float thighInvertDot = Vector3.Dot(thighCross.normalized, charCross.normalized);
			
        if (thighInvertDot > 0 && log) {
            Warning.Log("The triangle formed by the root node, left thigh and right thigh bones seems to be flipped. The root node bone should be above the thigh bones.", context, true);
        }
        */

        return true;
    }
示例#36
0
		// Check if eyes are properly set up
		private static bool CheckEyesError(BipedReferences references, bool log) {
			if (references.eyes.Length == 0) return true;

			for (int i = 0; i < references.eyes.Length; i++) {
				if (references.eyes[i] == null) {
					if (log) Warning.Log("BipedReferences eye bone at index " + i + " is null.", references.root, true);
					return false;
				}
			}
			
			Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);
			if (duplicate != null) {
				if (log) Warning.Log(duplicate.name + " is represented multiple times in BipedReferences eyes.", references.eyes[0], true);
				return false;
			}
			
			return true;
		}
示例#37
0
		/// <summary>
		/// Detects the references based on naming and hierarchy.
		/// </summary>
		public static void DetectReferencesByNaming(ref BipedReferences references, Transform root, AutoDetectParams autoDetectParams) {
			if (references == null) references = new BipedReferences();

			Transform[] children = root.GetComponentsInChildren<Transform>();
			
			// Find limbs
			DetectLimb(BipedNaming.BoneType.Arm, BipedNaming.BoneSide.Left, ref references.leftUpperArm, ref references.leftForearm, ref references.leftHand, children);
			DetectLimb(BipedNaming.BoneType.Arm, BipedNaming.BoneSide.Right, ref references.rightUpperArm, ref references.rightForearm, ref references.rightHand, children);
			DetectLimb(BipedNaming.BoneType.Leg, BipedNaming.BoneSide.Left, ref references.leftThigh, ref references.leftCalf, ref references.leftFoot, children);
			DetectLimb(BipedNaming.BoneType.Leg, BipedNaming.BoneSide.Right, ref references.rightThigh, ref references.rightCalf, ref references.rightFoot, children);
			
			// Find head bone
			references.head = BipedNaming.GetBone(children, BipedNaming.BoneType.Head);
			
			// Find Pelvis
			references.pelvis = BipedNaming.GetNamingMatch(children, BipedNaming.pelvis);
			
			// If pelvis is not an ancestor of a leg, it is not a valid pelvis
			if (references.pelvis == null || !Hierarchy.IsAncestor(references.leftThigh, references.pelvis)) {
				if (references.leftThigh != null) references.pelvis = references.leftThigh.parent;
			}
			
			// Find spine and head bones
			if (references.leftUpperArm != null && references.rightUpperArm != null && references.pelvis != null && references.leftThigh != null) {
				Transform neck = Hierarchy.GetFirstCommonAncestor(references.leftUpperArm, references.rightUpperArm);

				if (neck != null) {
					Transform[] inverseSpine = new Transform[1] { neck };
					Hierarchy.AddAncestors(inverseSpine[0], references.pelvis, ref inverseSpine);
					
					references.spine = new Transform[0];
					for (int i = inverseSpine.Length - 1; i > -1; i--) {
						if (AddBoneToSpine(inverseSpine[i], ref references, autoDetectParams)) {
							Array.Resize(ref references.spine, references.spine.Length + 1);
							references.spine[references.spine.Length - 1] = inverseSpine[i];
						}
					}
					
					// Head
					if (references.head == null) {
						for (int i = 0; i < neck.childCount; i++) {
							Transform child = neck.GetChild(i);
							
							if (!Hierarchy.ContainsChild(child, references.leftUpperArm) && !Hierarchy.ContainsChild(child, references.rightUpperArm)) {
								references.head = child;
								break;
							}
						}
					}
				}
			}
			
			// Find eye bones
			Transform[] eyes = BipedNaming.GetBonesOfType(BipedNaming.BoneType.Eye, children);
			references.eyes = new Transform[0];
			
			if (autoDetectParams.includeEyes) {
				for (int i = 0; i < eyes.Length; i++) {
					if (AddBoneToEyes(eyes[i], ref references, autoDetectParams)) {
						Array.Resize(ref references.eyes, references.eyes.Length + 1);
						references.eyes[references.eyes.Length - 1] = eyes[i];
					}
				}
			}
		}
示例#38
0
		// Check if eyes are properly set up
		private static bool CheckEyesWarning(BipedReferences references, bool log) {
			// Maybe need to add something here in the future
			return true;
		}
示例#39
0
		/// <summary>
		/// Fills in BipedReferences using Animator.GetBoneTransform().
		/// </summary>
		public static void AssignHumanoidReferences(ref BipedReferences references, Animator animator, AutoDetectParams autoDetectParams) {
			if (references == null) references = new BipedReferences();

			if (animator == null || !animator.isHuman) return;
			
			references.spine = new Transform[0];
			references.eyes = new Transform[0];
			
			references.head = animator.GetBoneTransform(HumanBodyBones.Head);
			
			references.leftThigh = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
			references.leftCalf = animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg);
			references.leftFoot = animator.GetBoneTransform(HumanBodyBones.LeftFoot);
			
			references.rightThigh = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg);
			references.rightCalf = animator.GetBoneTransform(HumanBodyBones.RightLowerLeg);
			references.rightFoot = animator.GetBoneTransform(HumanBodyBones.RightFoot);
			
			references.leftUpperArm = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
			references.leftForearm = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
			references.leftHand = animator.GetBoneTransform(HumanBodyBones.LeftHand);
			
			references.rightUpperArm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
			references.rightForearm = animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
			references.rightHand = animator.GetBoneTransform(HumanBodyBones.RightHand);
			
			references.pelvis = animator.GetBoneTransform(HumanBodyBones.Hips);
			
			AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Spine));
			AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Chest));
			
			// Make sure the neck bone is not above the arms
			if (references.leftUpperArm != null) {
				if (!IsNeckBone(animator.GetBoneTransform(HumanBodyBones.Neck), references.leftUpperArm)) AddBoneToHierarchy(ref references.spine, animator.GetBoneTransform(HumanBodyBones.Neck));
			}
			
			if (autoDetectParams.includeEyes) {
				AddBoneToHierarchy(ref references.eyes, animator.GetBoneTransform(HumanBodyBones.LeftEye));
				AddBoneToHierarchy(ref references.eyes, animator.GetBoneTransform(HumanBodyBones.RightEye));
			}
		}
示例#40
0
		// Check if the character is facing the correct axis
		private static bool CheckFacingAxisWarning(BipedReferences references, bool log) {
			Vector3 handsLeftToRight = references.rightHand.position - references.leftHand.position;
			Vector3 feetLeftToRight = references.rightFoot.position - references.leftFoot.position;
			
			float dotHands = Vector3.Dot(handsLeftToRight.normalized, references.root.right);
			float dotFeet = Vector3.Dot(feetLeftToRight.normalized, references.root.right);
			
			if (dotHands < 0 || dotFeet < 0) {
				if (log) Warning.Log(
					"Biped does not seem to be facing it's forward axis. " +
					"Please make sure that in the initial pose the character is facing towards the positive Z axis of the Biped root gameobject.", references.root, true);
				return false;
			}
			
			return true;
		}
示例#41
0
		/// <summary>
		/// Checks the setup for definite problems.
		/// </summary>
		public static bool CheckSetupError(BipedReferences references, bool log) {
			if (!references.isValid) {
				if (log) Warning.Log("BipedReferences contains one or more missing Transforms.", references.root, true);
				return false;
			}
			
			if (!CheckLimbError(references.leftThigh, references.leftCalf, references.leftFoot, log)) return false;
			if (!CheckLimbError(references.rightThigh, references.rightCalf, references.rightFoot, log)) return false;
			if (!CheckLimbError(references.leftUpperArm, references.leftForearm, references.leftHand, log)) return false;
			if (!CheckLimbError(references.rightUpperArm, references.rightForearm, references.rightHand, log)) return false;
			
			if (!CheckSpineError(references, log)) return false;
			if (!CheckEyesError(references, log)) return false;
			
			return true;
		}
        /// <summary>
        /// Checks the setup for possible problems.
        /// </summary>
        public static bool CheckSetup(BipedReferences references, bool log = true)
        {
            if (!references.isValid) {
                return false;
            }

            if (!CheckLimb(references.leftThigh, references.leftCalf, references.leftFoot, log)) return false;
            if (!CheckLimb(references.rightThigh, references.rightCalf, references.rightFoot, log)) return false;
            if (!CheckLimb(references.leftUpperArm, references.leftForearm, references.leftHand, log)) return false;
            if (!CheckLimb(references.rightUpperArm, references.rightForearm, references.rightHand, log)) return false;

            if (!CheckSpine(references, log)) return false;
            if (!CheckEyes(references, log)) return false;

            if (!CheckRootHeight(references, log)) return false;
            if (!CheckFacingAxis(references, log)) return false;

            return true;
        }
示例#43
0
		// Check if eyes are properly set up
		private static bool EyesWarning(BipedReferences references, ref string warningMessage) {
			// Maybe need to add something here in the future
			return false;
		}
 /// <summary>
 /// Sets the solver to new biped references.
 /// </summary>
 /// /// <param name="references">Biped references.</param>
 /// <param name="rootNode">Root node. if null, will try to detect the root node bone automatically. </param>
 public void SetReferences(BipedReferences references, Transform rootNode)
 {
     this.references = references;
     solver.SetToReferences(this.references, rootNode);
 }
示例#45
0
		/// <summary>
		/// Checks the setup for possible problems.
		/// </summary>
		public static bool SetupWarning(BipedReferences references, ref string warningMessage) {
			if (LimbWarning(references.leftThigh, references.leftCalf, references.leftFoot, ref warningMessage)) return true;
			if (LimbWarning(references.rightThigh, references.rightCalf, references.rightFoot, ref warningMessage)) return true;
			if (LimbWarning(references.leftUpperArm, references.leftForearm, references.leftHand, ref warningMessage)) return true;
			if (LimbWarning(references.rightUpperArm, references.rightForearm, references.rightHand, ref warningMessage)) return true;
			if (SpineWarning(references, ref warningMessage)) return true;
			if (EyesWarning(references, ref warningMessage)) return true;
			if (RootHeightWarning(references, ref warningMessage)) return true;
			if (FacingAxisWarning(references, ref warningMessage)) return true;
			
			return false;
		}
示例#46
0
		/// <summary>
		/// Checks the setup for possible problems.
		/// </summary>
		public static bool CheckSetupWarning(BipedReferences references, bool log) {
			if (!CheckLimbWarning(references.leftThigh, references.leftCalf, references.leftFoot, log)) return false;
			if (!CheckLimbWarning(references.rightThigh, references.rightCalf, references.rightFoot, log)) return false;
			if (!CheckLimbWarning(references.leftUpperArm, references.leftForearm, references.leftHand, log)) return false;
			if (!CheckLimbWarning(references.rightUpperArm, references.rightForearm, references.rightHand, log)) return false;
			
			if (!CheckSpineWarning(references, log)) return false;
			if (!CheckEyesWarning(references, log)) return false;
			
			if (!CheckRootHeightWarning(references, log)) return false;
			if (!CheckFacingAxisWarning(references, log)) return false;
			
			return true;
		}
 private static bool SpineError(BipedReferences references, ref string errorMessage) => default;                           // 0x00000001804BB370-0x00000001804BB7F0
 private static bool SpineWarning(BipedReferences references, ref string warningMessage) => default;                       // 0x0000000180250A70-0x0000000180250A80
示例#48
0
		// Check if eyes are properly set up
		private static bool EyesError(BipedReferences references, ref string errorMessage) {
			// No eyes might be a valid setup
			if (references.eyes.Length == 0) return false;

			for (int i = 0; i < references.eyes.Length; i++) {
				if (references.eyes[i] == null) {
					errorMessage = "BipedReferences eye bone at index " + i + " is null.";
					return true;
				}
			}
			
			Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.eyes);
			if (duplicate != null) {
				errorMessage = duplicate.name + " is represented multiple times in BipedReferences eyes.";
				return true;
			}
			
			return false;
		}
示例#49
0
		// Determines whether a bone is valid for being added into the eyes array
		private static bool AddBoneToEyes(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams) {
			if (references.head != null) {
				if (!Hierarchy.IsAncestor(bone, references.head)) return false;
			}
			
			if (bone.GetComponent<SkinnedMeshRenderer>() != null) return false;
			
			return true;
		}
示例#50
0
		/// <summary>
		/// Checks the setup for definite problems.
		/// </summary>
		public static bool SetupError(BipedReferences references, ref string errorMessage) {
			if (!references.isFilled) {
				errorMessage = "BipedReferences contains one or more missing Transforms.";
				return true;
			}
			
			if (LimbError(references.leftThigh, references.leftCalf, references.leftFoot, ref errorMessage)) return true;
			if (LimbError(references.rightThigh, references.rightCalf, references.rightFoot, ref errorMessage)) return true;
			if (LimbError(references.leftUpperArm, references.leftForearm, references.leftHand, ref errorMessage)) return true;
			if (LimbError(references.rightUpperArm, references.rightForearm, references.rightHand, ref errorMessage)) return true;
			if (SpineError(references, ref errorMessage)) return true;
			if (EyesError(references, ref errorMessage)) return true;
			
			return false;
		}
示例#51
0
		// Determines whether a bone is valid for being added into the spine
		private static bool AddBoneToSpine(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams) {
			if (bone == references.root) return false;
			
			bool isLegsParent = bone == references.leftThigh.parent;
			if (isLegsParent && !autoDetectParams.legsParentInSpine) return false;
			
			if (references.pelvis != null) {
				if (bone == references.pelvis) return false;
				if (Hierarchy.IsAncestor(references.pelvis, bone)) return false;
			}
			
			return true;
		}
示例#52
0
		// Check if spine is properly set up
		private static bool CheckSpineError(BipedReferences references, bool log) {
			if (references.spine.Length == 0) return true;

			for (int i = 0; i < references.spine.Length; i++) {
				if (references.spine[i] == null) {
					if (log) Warning.Log("BipedReferences spine bone at index " + i + " is null.", references.root, true);
					return false;
				}
			}

			Transform duplicate = (Transform)Hierarchy.ContainsDuplicate(references.spine);
			if (duplicate != null) {
				if (log) Warning.Log(duplicate.name + " is represented multiple times in BipedReferences spine.", references.spine[0], true);
				return false;
			}
			
			if (!Hierarchy.HierarchyIsValid(references.spine)) {
				if (log) Warning.Log("BipedReferences spine hierarchy is invalid. Bone transforms in the spine do not belong to the same ancestry. Please make sure the bones are parented to each other.", references.spine[0], true);
				return false;
			}
			
			for (int i = 0; i < references.spine.Length; i++) {
				bool matchesParentPosition = false;
				if (i == 0 && references.spine[i].position == references.pelvis.position) matchesParentPosition = true;
				if (i != 0 && references.spine.Length > 1 && references.spine[i].position == references.spine[i - 1].position) matchesParentPosition = true;

				if (matchesParentPosition) {
					if (log) Warning.Log("Biped's spine bone nr " + i + " position is the same as it's parent spine/pelvis bone's position. Please remove this bone from the spine.", references.spine[i], true);
					return false;
				}
			}
			
			return true;
		}
 private static bool AddBoneToEyes(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams) => default;  // 0x00000001804B79C0-0x00000001804B7AC0
 private static bool AddBoneToSpine(Transform bone, ref BipedReferences references, AutoDetectParams autoDetectParams) => default; // 0x00000001804B7BB0-0x00000001804B7D40