/*
         * Draws the custom inspector for Constraints
         * */
        public static void AddInspector(SerializedProperty prop, SerializedContent[] content)
        {
            if (!prop.isExpanded) return;

            // Main properties
            for (int i = 0; i < 4; i++) AddClampedFloat(content[i]);

            EditorGUILayout.Space();
        }
        /*
         * Returns all solver SerializedProperties and wraps them into a SerializedContent with names and tooltips.
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[4] {
                new SerializedContent(prop.FindPropertyRelative("positionOffsetConstraint.weight"), new GUIContent("Pos Offset Weight", "The weight of pelvis position offset. You can set position offset by bipedIK.solvers.pelvis.positionOffsetConstraint.offset = value.")),
                new SerializedContent(prop.FindPropertyRelative("positionConstraint.weight"), new GUIContent("Pos Weight", "The weight of pelvis position. You can set pelvis position by bipedIK.solvers.pelvis.positionConstraint.position = value.")),
                new SerializedContent(prop.FindPropertyRelative("rotationOffsetConstraint.weight"), new GUIContent("Rot Offset Weight", "The weight of pelvis rotation offset. You can set rotation offset by bipedIK.solvers.pelvis.rotationOffsetConstraint.offset = value.")),
                new SerializedContent(prop.FindPropertyRelative("rotationConstraint.weight"), new GUIContent("Rot Weight", "The weight of pelvis rotation. You can set pelvis rotation by bipedIK.solvers.pelvis.rotationConstraint.rotation = value."))
            };

            return c;
        }
        /*
         * Returns all solver SeiralizedProperties
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[4] {
                new SerializedContent(prop.FindPropertyRelative("iterations"), new GUIContent("Iterations", "Solver iterations.")),
                new SerializedContent(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight.")),
                new SerializedContent(prop.FindPropertyRelative("rootPin"), new GUIContent("Root Pin", "Weight of keeping all FABRIK Trees pinned to the root position.")),
                new SerializedContent(prop.FindPropertyRelative("chains"), new GUIContent("Chains", "FABRIK chains."))
                };

            return c;
        }
        /*
         * Draws the custom inspector for IKSolverHeuristic
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool editWeights, SerializedContent[] content)
        {
            AddClampedFloat(content[0]);
            AddClampedFloat(content[1], 0f, Mathf.Infinity);
            AddClampedInt(content[2], 1, int.MaxValue);
            AddContent(content[3]);

            EditorGUILayout.Space();
            weights = editWeights;
            if (editHierarchy || editWeights) AddArray(content[4], editHierarchy, false, null, OnAddToArrayBone, DrawArrayElementLabelBone);
            EditorGUILayout.Space();
        }
        /*
         * Returns all solver SeiralizedProperties
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[5] {
                new SerializedContent(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending.")),
                new SerializedContent(prop.FindPropertyRelative("iterations"), new GUIContent("Iterations", "Solver iterations per frame.")),
                new SerializedContent(prop.FindPropertyRelative("effectors"), new GUIContent("Effectors", string.Empty)),
                new SerializedContent(prop.FindPropertyRelative("bendConstraints"), new GUIContent("Bend Constraints", string.Empty)),
                new SerializedContent(prop.FindPropertyRelative("chain"), new GUIContent("Chain", string.Empty)),
            };

            return c;
        }
        /*
         * Returns all solver SeiralizedProperties
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[5] {
                new SerializedContent(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending.")),
                new SerializedContent(prop.FindPropertyRelative("tolerance"), new GUIContent("Tolerance", "Minimum offset from last reached position. Will stop solving if offset is less than tolerance. If tolerance is zero, will iterate until maxIterations.")),
                new SerializedContent(prop.FindPropertyRelative("maxIterations"), new GUIContent("Max Iterations", "Max solver iterations per frame.")),
                new SerializedContent(prop.FindPropertyRelative("useRotationLimits"), new GUIContent("Use Rotation Limits", "If true, rotation limits (if excisting) will be applied on each iteration.")),
                new SerializedContent(prop.FindPropertyRelative("bones"), new GUIContent("Bones", string.Empty))
                };

            return c;
        }
        /// <summary>
        /// Draws the custom inspector for IKSolverAim
        /// </summary>
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, SerializedContent[] content)
        {
            AddContent(content[content.Length - 4]);
            AddContent(content[content.Length - 3], true);

            EditorGUILayout.Space();

            AddClampedFloat(content[content.Length - 2]);
            AddClampedInt(content[content.Length - 1], 0, 3);

            IKSolverHeuristicInspector.AddInspector(prop, editHierarchy, true, content);
        }
        /*
         * Draws the custom inspector for IKSolverFABRIKRoot
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, SerializedContent[] content)
        {
            AddClampedInt(content[0], 0, int.MaxValue);
            AddClampedFloat(content[1]);
            AddClampedFloat(content[2]);

            EditorGUILayout.Space();

            EditorGUI.indentLevel = 0;
            AddContent(content[3], true);

            EditorGUILayout.Space();
        }
        /*
         * Draws the custom inspector for IKSolverFABRIKRoot
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, SerializedContent[] content)
        {
            AddClampedInt(content[0], 0, int.MaxValue);
            AddClampedFloat(content[1]);
            AddClampedFloat(content[2]);

            EditorGUILayout.Space();

            EditorGUI.indentLevel = 0;
            AddArray(content[3], editHierarchy, false, DrawArrayElementChain, OnAddToArrayChain, DrawArrayElementLabelChain);

            EditorGUILayout.Space();
        }
        public void OnEnable()
        {
            if (serializedObject == null) return;

            // Store the MonoScript for changing script execution order
            if (!Application.isPlaying) {
                MonoScript monoScript = MonoScript.FromMonoBehaviour(script);

                // Changing the script execution order to make sure BipedIK always executes after any other script except FullBodyBipedIK
                int executionOrder = MonoImporter.GetExecutionOrder(monoScript);
                if (executionOrder != 9998) MonoImporter.SetExecutionOrder(monoScript, 9998);
            }

            references = serializedObject.FindProperty("references");
            solvers = serializedObject.FindProperty("solvers");
            solversProps = BipedIKSolversInspector.FindProperties(solvers);
            fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance."));

            // Caching Solver Contents
            leftFootContent = IKSolverLimbInspector.FindContent(solversProps[0]);
            rightFootContent = IKSolverLimbInspector.FindContent(solversProps[1]);
            leftHandContent = IKSolverLimbInspector.FindContent(solversProps[2]);
            rightHandContent = IKSolverLimbInspector.FindContent(solversProps[3]);
            spineContent = IKSolverHeuristicInspector.FindContent(solversProps[4]);
            aimContent = IKSolverAimInspector.FindContent(solversProps[5]);
            lookAtContent = IKSolverLookAtInspector.FindContent(solversProps[6]);
            pelvisContent = ConstraintsInspector.FindContent(solversProps[7]);

            solverContents = new SerializedContent[8][] {
                leftFootContent, rightFootContent, leftHandContent, rightHandContent, spineContent, aimContent, lookAtContent, pelvisContent
            };

            // Automatically detecting references
            if (!Application.isPlaying) {
                if (script.references.isEmpty) {
                    BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(false, true));

                    references.isExpanded = true;
                    solvers.isExpanded = false;
                    for (int i = 0; i < solversProps.Length; i++) solversProps[i].isExpanded = false;

                    // Setting default values and initiating
                    script.InitiateBipedIK();
                    script.SetToDefaults();
                    EditorUtility.SetDirty(script);
                } else script.InitiateBipedIK();

                Warning.logged = false;
                BipedReferences.CheckSetup(script.references);
            }
        }
        public static void DrawArrayElementEffector(SerializedProperty effector, bool editHierarchy)
        {
            if (!editHierarchy) return;

            if (effector.FindPropertyRelative("bones").arraySize > 1) {
                GUILayout.BeginHorizontal();
                GUILayout.Space(indent);
                AddClampedFloat(effector.FindPropertyRelative("falloff"), new GUIContent("Distance Falloff", string.Empty), 0f, Mathf.Infinity);
                GUILayout.EndHorizontal();
            }

            tempContent = new SerializedContent(effector.FindPropertyRelative("bones"), new GUIContent("Bones", string.Empty));
            AddArray(tempContent, editHierarchy, false, null, OnAddToArrayBone, DrawArrayElementLabelBone, false);

            if (effector.isExpanded) EditorGUILayout.Space();
        }
        /*
         * Draws the custom inspector for IKSolverLimb
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences, SerializedContent[] content)
        {
            // Draw the trigonometric IK inspector
            IKSolverTrigonometricInspector.AddInspector(prop, editHierarchy, showReferences, content);

            EditorGUILayout.Space();

            if (showReferences && editHierarchy) AddContent(content[content.Length - 1]);
            AddClampedFloat(content[content.Length - 2]);

            // Bend normal modifier.
            AddContent(content[content.Length - 3]);
            AddClampedFloat(content[content.Length - 4]);

            EditorGUILayout.Space();
        }
Example #13
0
		void OnEnable() {
			if (serializedObject == null) return;

			// Changing the script execution order
			if (!Application.isPlaying) {
				int executionOrder = 0;
				monoScript = MonoScript.FromMonoBehaviour(GetMonoBehaviour(out executionOrder));
				int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
				if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
			}

			solver = serializedObject.FindProperty("solver");
			timeStep = new SerializedContent(serializedObject.FindProperty("timeStep"), new GUIContent("Time Step", "If zero, will update the solver in every LateUpdate(). Use this for chains that are animated. If > 0, will be used as updating frequency so that the solver will reach its target in the same time on all machines."));
			fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance. Not recommended for CCD and FABRIK solvers."));

			OnEnableVirtual();
		}
Example #14
0
        void OnEnable()
        {
            if (serializedObject == null) return;

            // Changing the script execution order
            if (!Application.isPlaying) {
                int executionOrder = 0;
                monoScript = MonoScript.FromMonoBehaviour(GetMonoBehaviour(out executionOrder));
                int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
                if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
            }

            solver = serializedObject.FindProperty("solver");
            timeStep = new SerializedContent(serializedObject.FindProperty("timeStep"), new GUIContent("Time Step", "If zero, will update the solver in every LateUpdate(). Use this for chains that are animated. If > 0, will be used as updating frequency so that the solver will reach its target in the same time on all machines."));

            content = FindContent();
            OnEnableVirtual();
        }
        /*
         * Draws the custom inspector for IKSolverTrigonometric
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences, SerializedContent[] content)
        {
            EditorGUI.indentLevel = 0;

            // Bone references
            if (showReferences) {
                EditorGUILayout.Space();
                for (int i = 0; i < 3; i++) {
                    AddObjectReference(content[i].prop, content[i].guiContent, editHierarchy, 100);
                }
                EditorGUILayout.Space();
            }

            AddClampedFloat(content[3]);
            AddClampedFloat(content[4]);

            if (showReferences) AddContent(content[5], true);
        }
        /*
         * Draws the custom inspector for BipedIK.Solvers
         * */
        public static void AddInspector(SerializedProperty prop, SerializedProperty[] props, SerializedContent[][] solverContents)
        {
            EditorGUILayout.PropertyField(prop);

            if (prop.isExpanded) {
                for (int i = 0; i < props.Length; i++) {
                    BeginProperty(props[i]);
                    if (props[i].isExpanded) {
                        if (i <= 3) IKSolverLimbInspector.AddInspector(props[i], false, false, solverContents[i]);
                        else if (i == 4) IKSolverHeuristicInspector.AddInspector(props[i], false, false, solverContents[4]);
                        else if (i == 5) IKSolverAimInspector.AddInspector(props[i], false, solverContents[5]);
                        else if (i == 6) IKSolverLookAtInspector.AddInspector(props[i], false, false, solverContents[6]);
                        else if (i == 7) ConstraintsInspector.AddInspector(props[i], solverContents[7]);
                    }
                    EndProperty(props[i]);
                }
            }
        }
		public void OnEnable() {
			if (serializedObject == null) return;

			// Store the MonoScript for changing script execution order
			if (!Application.isPlaying) {
				MonoScript monoScript = MonoScript.FromMonoBehaviour(script);

				// Changing the script execution order to make sure BipedIK always executes after any other script except FullBodyBipedIK
				int executionOrder = MonoImporter.GetExecutionOrder(monoScript);
				if (executionOrder != 9998) MonoImporter.SetExecutionOrder(monoScript, 9998);
			}

			references = serializedObject.FindProperty("references");
			solvers = serializedObject.FindProperty("solvers");
			solversProps = BipedIKSolversInspector.FindProperties(solvers);
			fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance."));
			
			// Automatically detecting references
			if (!Application.isPlaying) {
				if (script.references.isEmpty) {
					BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(false, true));
					
					references.isExpanded = true;
					solvers.isExpanded = false;
					for (int i = 0; i < solversProps.Length; i++) solversProps[i].isExpanded = false;
					
					// Setting default values and initiating
					script.InitiateBipedIK();
					script.SetToDefaults();
					EditorUtility.SetDirty(script);
				} else script.InitiateBipedIK();
				
				Warning.logged = false;

				string message = string.Empty;
				if (Application.isPlaying) {
					if (BipedReferences.SetupError(script.references, ref message) || BipedReferences.SetupWarning(script.references, ref message)) {
						Warning.Log(message, script.references.root, false);
					}
				}
			}
		}
        /*
         * Draws the custom inspector for IKSolverLookAt
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences, SerializedContent[] content)
        {
            // Main properties
            for (int i = 0; i < 7; i++) AddClampedFloat(content[i]);
            AddClampedInt(content[7], 0, 3);

            // Spine Weight curve
            AddContent(content[11]);

            // References
            if (showReferences) {
                EditorGUILayout.Space();
                AddContent(content[8]);

                EditorGUILayout.Space();
                AddArray(content[9], editHierarchy, false, null, null, DrawArrayElementLabelBone);

                EditorGUILayout.Space();
                AddArray(content[10], editHierarchy, false, null, null, DrawArrayElementLabelBone);
            }

            EditorGUILayout.Space();
        }
 public static void AddContent(SerializedContent content, bool addChildren = false, params GUILayoutOption[] options)
 {
     EditorGUILayout.PropertyField(content.prop, content.guiContent, addChildren, options);
 }
 private static void DrawArrayElementChain(SerializedProperty chain, bool editHierarchy)
 {
     tempContent = new SerializedContent(chain.FindPropertyRelative("children"), new GUIContent("Children", string.Empty));
     IKSolverInspector.AddArray(tempContent, editHierarchy, false, DrawArrayElementChain, null, DrawArrayElementLabelChain, string.Empty, false);
 }
 public static void AddClampedInt(SerializedContent content, int min = int.MinValue, int max = int.MaxValue, params GUILayoutOption[] options)
 {
     AddClampedInt(content.prop, content.guiContent, min, max, options);
 }
Example #22
0
 private static void DrawArrayElementChain(SerializedProperty chain, bool editHierarchy)
 {
     tempContent = new SerializedContent(chain.FindPropertyRelative("children"), new GUIContent("Children", string.Empty));
     IKSolverInspector.AddArray(tempContent, editHierarchy, false, DrawArrayElementChain, null, DrawArrayElementLabelChain, string.Empty, false);
 }
 /*
  * Draws the custom inspector for IKSolverFullBody
  * */
 public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool editWeights, SerializedContent[] content)
 {
     AddClampedFloat(content[0]);
     AddClampedInt(content[1], 1, int.MaxValue);
 }
        /*
         * Draws the custom inspector for IKSolverFullBodybiped
         * */
        public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool editWeights, SerializedContent[] content)
        {
            IKSolverFullBodyInspector.AddInspector(prop, editHierarchy, editWeights, content);

            // Spine Iteration
            AddClampedInt(content[content.Length - 3].prop.FindPropertyRelative("iterations"), new GUIContent("Spine Mapping Iterations", "Iterations of FABRIK solver mapping the spine to the FBIK nodes."), 1, 10);

            // Spine Stiffness
            AddClampedFloat(content[content.Length - 6]);

            // Pull Body
            AddClampedFloat(content[content.Length - 1], -1f, 1f);
            AddClampedFloat(content[content.Length - 7], -1f, 1f);

            // Chain
            EditorGUILayout.Space();
            EditorGUI.indentLevel = 0;

            EditorGUILayout.PropertyField(content[4].prop, new GUIContent("Chain", "The node chain."));
            if (content[4].prop.isExpanded) {
                AddPulls(content[4].prop);
                EditorGUILayout.Space();
            }

            // Effectors
            EditorGUI.indentLevel = 0;

            EditorGUILayout.PropertyField(content[2].prop, new GUIContent("Effectors", "Effectors for manipulating the node chain."));
            if (content[2].prop.isExpanded) {

                // Body
                AddEffector(content[2].prop.GetArrayElementAtIndex(0), new GUIContent("Body"), false);

                // Left Shoulder
                AddEffector(content[2].prop.GetArrayElementAtIndex(1),new GUIContent("L Shoulder"), false);

                // Right Shoulder
                AddEffector(content[2].prop.GetArrayElementAtIndex(2),new GUIContent("R Shoulder"), false);

                // Left Thigh
                AddEffector(content[2].prop.GetArrayElementAtIndex(3),new GUIContent("L Thigh"), false);

                // Right Thigh
                AddEffector(content[2].prop.GetArrayElementAtIndex(4),new GUIContent("R Thigh"), false);

                // Left Hand
                AddEffector(content[2].prop.GetArrayElementAtIndex(5), new GUIContent("L Hand"));

                // Right Hand
                AddEffector(content[2].prop.GetArrayElementAtIndex(6), new GUIContent("R Hand"));

                // Left Foot
                AddEffector(content[2].prop.GetArrayElementAtIndex(7), new GUIContent("L Foot"));

                // Right Foot
                AddEffector(content[2].prop.GetArrayElementAtIndex(8), new GUIContent("R Foot"));

                EditorGUILayout.Space();
            }

            EditorGUI.indentLevel = 0;

            // Mappings
            EditorGUILayout.PropertyField(content[content.Length - 3].prop, new GUIContent("Mapping", "Options for mapping bones to their solver positions."));
            if (content[content.Length - 3].prop.isExpanded) {
                AddSpineMapping(content[content.Length - 3].prop, new GUIContent("Spine"));

                AddMapping(content[content.Length - 2].prop.GetArrayElementAtIndex(0), new GUIContent("Left Hand"));
                AddMapping(content[content.Length - 2].prop.GetArrayElementAtIndex(1), new GUIContent("Right Hand"));
                AddMapping(content[content.Length - 2].prop.GetArrayElementAtIndex(2), new GUIContent("Left Foot"));
                AddMapping(content[content.Length - 2].prop.GetArrayElementAtIndex(3), new GUIContent("Right Foot"));

                AddMapping(content[content.Length - 4].prop.GetArrayElementAtIndex(0), new GUIContent("Head"));

            }
        }
 public static void AddReferences(bool editHierarchy, SerializedContent[] content)
 {
     // RootNode
     if (editHierarchy) {
         AddContent(content[content.Length - 5]);
     }
 }
Example #26
0
        public void OnEnable()
        {
            if (serializedObject == null)
            {
                return;
            }

            // Store the MonoScript for changing script execution order
            if (!Application.isPlaying)
            {
                MonoScript monoScript = MonoScript.FromMonoBehaviour(script);

                // Changing the script execution order to make sure BipedIK always executes after any other script except FullBodyBipedIK
                int executionOrder = MonoImporter.GetExecutionOrder(monoScript);
                if (executionOrder != 9998)
                {
                    MonoImporter.SetExecutionOrder(monoScript, 9998);
                }
            }

            references    = serializedObject.FindProperty("references");
            solvers       = serializedObject.FindProperty("solvers");
            solversProps  = BipedIKSolversInspector.FindProperties(solvers);
            fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance."));

            // Caching Solver Contents
            leftFootContent  = IKSolverLimbInspector.FindContent(solversProps[0]);
            rightFootContent = IKSolverLimbInspector.FindContent(solversProps[1]);
            leftHandContent  = IKSolverLimbInspector.FindContent(solversProps[2]);
            rightHandContent = IKSolverLimbInspector.FindContent(solversProps[3]);
            spineContent     = IKSolverHeuristicInspector.FindContent(solversProps[4]);
            aimContent       = IKSolverAimInspector.FindContent(solversProps[5]);
            lookAtContent    = IKSolverLookAtInspector.FindContent(solversProps[6]);
            pelvisContent    = ConstraintsInspector.FindContent(solversProps[7]);

            solverContents = new SerializedContent[8][] {
                leftFootContent, rightFootContent, leftHandContent, rightHandContent, spineContent, aimContent, lookAtContent, pelvisContent
            };

            // Automatically detecting references
            if (!Application.isPlaying)
            {
                if (script.references.isEmpty)
                {
                    BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(false, true));

                    references.isExpanded = true;
                    solvers.isExpanded    = false;
                    for (int i = 0; i < solversProps.Length; i++)
                    {
                        solversProps[i].isExpanded = false;
                    }

                    // Setting default values and initiating
                    script.InitiateBipedIK();
                    script.SetToDefaults();
                    EditorUtility.SetDirty(script);
                }
                else
                {
                    script.InitiateBipedIK();
                }

                Warning.logged = false;
                BipedReferences.CheckSetupError(script.references);
                BipedReferences.CheckSetupWarning(script.references);
            }
        }
        /*
         * Returns all solver SeiralizedProperties
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[12] {
                new SerializedContent(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending.")),
                new SerializedContent(prop.FindPropertyRelative("bodyWeight"), new GUIContent("Body Weight", "Weight of rotating spine to target.")),
                new SerializedContent(prop.FindPropertyRelative("headWeight"), new GUIContent("Head Weight", "Weight of rotating head to target.")),
                new SerializedContent(prop.FindPropertyRelative("eyesWeight"), new GUIContent("Eyes Weight", "Weight of rotating eyes to target.")),
                new SerializedContent(prop.FindPropertyRelative("clampWeight"), new GUIContent("Clamp Weight", "Clamping rotation of spine and head. 0 is free rotation, 1 is completely clamped to forward.")),
                new SerializedContent(prop.FindPropertyRelative("clampWeightHead"), new GUIContent("Clamp Weight Head", "Clamping rotation of the head. 0 is free rotation, 1 is completely clamped to forward.")),
                new SerializedContent(prop.FindPropertyRelative("clampWeightEyes"), new GUIContent("Clamp Weight Eyes", "Clamping rotation of the eyes. 0 is free rotation, 1 is completely clamped to forward.")),
                new SerializedContent(prop.FindPropertyRelative("clampSmoothing"), new GUIContent("Clamp Smoothing", "Number of sine smoothing iterations applied on clamping to make the clamping point smoother.")),
                new SerializedContent(prop.FindPropertyRelative("head.transform"), new GUIContent("Head", "The head bone.")),
                new SerializedContent(prop.FindPropertyRelative("spine"), new GUIContent("Spine", string.Empty)),
                new SerializedContent(prop.FindPropertyRelative("eyes"), new GUIContent("Eyes", string.Empty)),
                new SerializedContent(prop.FindPropertyRelative("spineWeightCurve"), new GUIContent("Spine Weight Curve", "Weight distribution between spine bones (first bone is evaluated at time 0.0, last bone is at 1.0)."))
            };

            return c;
        }
        /*
         * Returns all solver SeiralizedProperties
         * */
        public static SerializedContent[] FindContent(SerializedProperty prop)
        {
            SerializedContent[] c = new SerializedContent[6] {
                new SerializedContent(prop.FindPropertyRelative("bone1.transform"), new GUIContent("Bone 1", "The first bone in the hierarchy (thigh or upper arm).")),
                new SerializedContent(prop.FindPropertyRelative("bone2.transform"), new GUIContent("Bone 2", "The second bone in the hierarchy (calf or forearm).")),
                new SerializedContent(prop.FindPropertyRelative("bone3.transform"), new GUIContent("Bone 3", "The last bone in the hierarchy (foot or hand).")),
                new SerializedContent(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Position Weight", "Solver weight for smooth blending.")),
                new SerializedContent(prop.FindPropertyRelative("IKRotationWeight"), new GUIContent("Rotation Weight", "Weight of last bone's rotation to IKRotation.")),
                new SerializedContent(prop.FindPropertyRelative("bendNormal"), new GUIContent("Bend Normal", "Bend plane normal."))
            };

            return c;
        }
 public static void AddClampedFloat(SerializedContent content, float min = 0f, float max = 1f, params GUILayoutOption[] options)
 {
     AddClampedFloat(content.prop, content.guiContent, min, max, options);
 }