コード例 #1
0
        /*
         * Draws the scene view helpers for IKSolverFABRIKRoot
         * */
        public static void AddScene(IKSolverFABRIKRoot solver, Color color, bool modifiable, ref FABRIKChain selected)
        {
            // Protect from null reference errors
            if (Application.isPlaying && !solver.initiated)
            {
                return;
            }
            if (!Application.isPlaying)
            {
                string message = string.Empty;
                if (!solver.IsValid(ref message))
                {
                    return;
                }
            }
            Handles.color = color;

            // Selecting solvers
            if (Application.isPlaying)
            {
                SelectChain(solver.chains, ref selected, color);
            }

            AddSceneChain(solver.chains, color, selected);

            // Root pin
            Handles.color = new Color(Mathf.Lerp(1f, color.r, solver.rootPin), Mathf.Lerp(1f, color.g, solver.rootPin), Mathf.Lerp(1f, color.b, solver.rootPin), Mathf.Lerp(0.5f, 1f, solver.rootPin));
            if (solver.GetRoot() != null)
            {
                Handles.DrawLine(solver.chains[0].ik.solver.bones[0].transform.position, solver.GetRoot().position);
                Inspector.CubeCap(0, solver.GetRoot().position, Quaternion.identity, GetHandleSize(solver.GetRoot().position));
            }
        }
コード例 #2
0
		/*
		 * Draws the scene view helpers for IKSolverHeuristic
		 * */
		public static void AddScene(IKSolverHeuristic solver, Color color, bool modifiable) {
			// Protect from null reference errors
			if (Application.isPlaying && !solver.initiated) return;
			if (!Application.isPlaying && !solver.IsValid()) return;

			Handles.color = color;
			GUI.color = color;
			
			// Display the bones
			for (int i = 0; i < solver.bones.Length; i++) {
				IKSolver.Bone bone = solver.bones[i];

				if (i < solver.bones.Length - 1) Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position);
				Inspector.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, GetHandleSize(solver.bones[i].transform.position));
			}
			
			// Selecting joint and manipulating IKPosition
			if (Application.isPlaying && solver.IKPositionWeight > 0) {
				if (modifiable) {
					Inspector.CubeCap(0, solver.IKPosition, solver.GetRoot().rotation, GetHandleSize(solver.IKPosition));
						
					// Manipulating position
					if (solver.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
				}
				
				// Draw a transparent line from last bone to IKPosition
				Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight);
				Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.IKPosition);
			}
			
			Handles.color = Color.white;
			GUI.color = Color.white;
		}
コード例 #3
0
        public static void AddScene(IKEffector e, Color color, bool modifiable, float size)
        {
            if (!modifiable)
            {
                return;
            }

            // Draw effectors
            bool  rotate = e.isEndEffector;
            float weight = rotate? Mathf.Max(e.positionWeight, e.rotationWeight): e.positionWeight;

            if (e.bone != null && weight > 0)
            {
                //if (Application.isPlaying) {
                Handles.color = new Color(color.r, color.g, color.b, weight);

                Handles.DrawLine(e.position, e.bone.position);
                Inspector.SphereCap(0, e.bone.position, Quaternion.identity, size * 0.5f);

                // Manipulating position and rotation
                if (e.target == null)
                {
                    switch (Tools.current)
                    {
                    case Tool.Move:
                        e.position = Handles.PositionHandle(e.position, Quaternion.identity);
                        break;

                    case Tool.Rotate:
                        if (rotate)
                        {
                            e.rotation = Handles.RotationHandle(e.rotation, e.position);
                        }
                        break;
                    }
                }

                if (rotate)
                {
                    Inspector.CubeCap(0, e.position, e.rotation, size);
                }
                else
                {
                    Inspector.SphereCap(0, e.position, Quaternion.identity, size);
                }
                //}
            }
        }
コード例 #4
0
        /*
         * Draws the scene view helpers for Constraints
         * */
        public static void AddScene(Constraints constraints, Color color, bool modifiable)
        {
            if (!constraints.IsValid())
            {
                return;
            }

            Handles.color = color;
            GUI.color     = color;

            // Transform
            Inspector.SphereCap(0, constraints.transform.position, Quaternion.identity, GetHandleSize(constraints.transform.position));

            // Target
            Handles.color = new Color(color.r, color.g, color.b, color.a * constraints.positionWeight);
            Handles.DrawLine(constraints.transform.position, constraints.position);
            Handles.color = color;

            if (Application.isPlaying && modifiable && (constraints.positionWeight > 0 || constraints.rotationWeight > 0))
            {
                Inspector.CubeCap(0, constraints.position, Quaternion.Euler(constraints.rotation), GetHandleSize(constraints.transform.position));

                // Manipulating position and rotation
                switch (Tools.current)
                {
                case Tool.Move:
                    constraints.position = Handles.PositionHandle(constraints.position, Quaternion.Euler(constraints.rotation));
                    break;

                case Tool.Rotate:
                    constraints.rotation = Handles.RotationHandle(Quaternion.Euler(constraints.rotation), constraints.position).eulerAngles;
                    break;
                }
            }

            Handles.color = Color.white;
            GUI.color     = Color.white;
        }
コード例 #5
0
        /*
         * Draws the scene view helpers for IKSolverTrigonometric
         * */
        public static void AddScene(IKSolverLeg solver, Color color, bool modifiable)
        {
            if (Application.isPlaying && !solver.initiated)
            {
                return;
            }
            if (!Application.isPlaying && !solver.IsValid())
            {
                return;
            }

            //float length = Vector3.Distance(solver.bone1.transform.position, solver.bone2.transform.position) + Vector3.Distance(solver.bone2.transform.position, solver.bone3.transform.position);
            //float size = length * 0.05f;

            Handles.color = color;
            GUI.color     = color;

            // Chain lines
            Handles.DrawLine(solver.pelvis.transform.position, solver.thigh.transform.position);
            Handles.DrawLine(solver.thigh.transform.position, solver.calf.transform.position);
            Handles.DrawLine(solver.calf.transform.position, solver.foot.transform.position);
            Handles.DrawLine(solver.foot.transform.position, solver.toe.transform.position);

            // Joints
            Inspector.SphereCap(0, solver.pelvis.transform.position, Quaternion.identity, GetHandleSize(solver.pelvis.transform.position));
            Inspector.SphereCap(0, solver.thigh.transform.position, Quaternion.identity, GetHandleSize(solver.thigh.transform.position));
            Inspector.SphereCap(0, solver.calf.transform.position, Quaternion.identity, GetHandleSize(solver.calf.transform.position));
            Inspector.SphereCap(0, solver.foot.transform.position, Quaternion.identity, GetHandleSize(solver.foot.transform.position));
            Inspector.SphereCap(0, solver.toe.transform.position, Quaternion.identity, GetHandleSize(solver.toe.transform.position));

            if (Application.isPlaying && (solver.IKPositionWeight > 0 || solver.IKRotationWeight > 0))
            {
                if (modifiable)
                {
                    Inspector.CubeCap(0, solver.IKPosition, solver.IKRotation, GetHandleSize(solver.IKPosition));

                    // Manipulating position and rotation
                    switch (Tools.current)
                    {
                    case Tool.Move:
                        if (solver.leg.target == null)
                        {
                            solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
                        }
                        break;

                    case Tool.Rotate:
                        if (solver.leg.target == null)
                        {
                            solver.IKRotation = Handles.RotationHandle(solver.IKRotation, solver.IKPosition);
                        }
                        break;
                    }
                }

                // Target
                Handles.color = new Color(color.r, color.g, color.b, color.a * Mathf.Max(solver.IKPositionWeight, solver.IKRotationWeight));
                Handles.DrawLine(solver.toe.transform.position, solver.IKPosition);
            }

            Handles.color = Color.white;
            GUI.color     = Color.white;
        }
コード例 #6
0
        void OnSceneGUI()
        {
            if (!script.enabled)
            {
                return;
            }
            string message = string.Empty;

            if (!script.IsValid(ref message))
            {
                return;
            }
            if (Application.isPlaying && !script.initiated)
            {
                return;
            }

            Color color = Color.cyan;

            color.a = script.weight;

            Handles.color = color;
            GUI.color     = color;

            // Display the bones
            if (!Application.isPlaying)
            {
                for (int i = 0; i < script.fingers.Length; i++)
                {
                    Handles.DrawLine(script.fingers[i].bone1.position, script.fingers[i].bone2.position);
                    Inspector.SphereCap(0, script.fingers[i].bone1.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone1.position) * 0.5f);
                    Inspector.SphereCap(0, script.fingers[i].bone2.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone2.position) * 0.5f);

                    if (script.fingers[i].bone3 != null)
                    {
                        Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].bone3.position);
                        Handles.DrawLine(script.fingers[i].bone3.position, script.fingers[i].tip.position);
                        Inspector.SphereCap(0, script.fingers[i].bone3.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone3.position) * 0.5f);
                    }
                    else
                    {
                        Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].tip.position);
                    }

                    Inspector.SphereCap(0, script.fingers[i].tip.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].tip.position) * 0.5f);
                }
            }

            // Selecting solvers
            if (Application.isPlaying)
            {
                if (selected >= 0 && selected < script.fingers.Length)
                {
                    if (script.fingers[selected].weight > 0f)
                    {
                        color.a       = script.weight * script.fingers[selected].weight;
                        Handles.color = color;

                        float size = IKSolverInspector.GetHandleSize(script.fingers[selected].IKPosition);

                        Inspector.CubeCap(0, script.fingers[selected].IKPosition, script.fingers[selected].IKRotation, size);

                        if (script.fingers[selected].target == null)
                        {
                            switch (Tools.current)
                            {
                            case Tool.Move:
                                script.fingers[selected].IKPosition = Handles.PositionHandle(script.fingers[selected].IKPosition, Tools.pivotRotation == PivotRotation.Local? script.fingers[selected].IKRotation: Quaternion.identity);
                                break;

                            case Tool.Rotate:
                                script.fingers[selected].IKRotation = Handles.RotationHandle(script.fingers[selected].IKRotation, script.fingers[selected].IKPosition);
                                break;
                            }
                        }
                    }
                }

                for (int i = 0; i < script.fingers.Length; i++)
                {
                    color.a       = script.weight * script.fingers[i].weight;
                    Handles.color = color;
                    Handles.DrawLine(script.fingers[i].tip.position, script.fingers[i].IKPosition);

                    if (script.fingers[i].weight > 0 && selected != i && script.fingers[i].initiated)
                    {
                        float size = IKSolverInspector.GetHandleSize(script.fingers[i].IKPosition) * 0.5f;

                        if (Inspector.DotButton(script.fingers[i].IKPosition, Quaternion.identity, size, size))
                        {
                            selected = i;
                        }
                    }
                }
            }

            Handles.color = Color.white;
            GUI.color     = Color.white;
        }
コード例 #7
0
        void OnSceneGUI()
        {
            Rigidbody[] rigidbodies = script.transform.GetComponentsInChildren <Rigidbody>();
            if (rigidbodies.Length == 0)
            {
                return;
            }

            Collider[] colliders = script.transform.GetComponentsInChildren <Collider>();

            if (script.selectedRigidbody == null)
            {
                script.selectedRigidbody = rigidbodies[0];
            }
            if (script.selectedCollider == null && colliders.Length > 0)
            {
                script.selectedCollider = colliders[0];
            }

            Rigidbody symmetricRigidbody = script.symmetry && script.selectedRigidbody != null?SymmetryTools.GetSymmetric(script.selectedRigidbody, rigidbodies, script.transform) : null;

            Collider symmetricCollider = script.symmetry && script.selectedCollider != null?SymmetryTools.GetSymmetric(script.selectedCollider, colliders, script.transform) : null;

            Joint joint = script.selectedRigidbody != null?script.selectedRigidbody.GetComponent <Joint>() : null;

            Joint symmetricJoint = joint != null && symmetricRigidbody != null?symmetricRigidbody.GetComponent <Joint>() : null;

            // Selected
            Transform selected = script.mode == RootMotion.Dynamics.RagdollEditor.Mode.Colliders? (script.selectedCollider != null? script.selectedCollider.transform: null): (script.selectedRigidbody != null? script.selectedRigidbody.transform: null);

            if (selected != null)
            {
                Handles.BeginGUI();
                GUILayout.BeginVertical(new GUIContent("Ragdoll Editor", string.Empty), "Window", GUILayout.Width(200), GUILayout.Height(20));
                GUILayout.BeginHorizontal();
                GUILayout.Label(selected.name);
                if (GUILayout.Button("Select GameObject", EditorStyles.miniButton))
                {
                    Selection.activeGameObject = selected.gameObject;
                }
                GUILayout.EndHorizontal();

                GUILayout.Space(10);

                //GUILayout.BeginVertical("Box");

                GUILayout.BeginHorizontal();
                GUILayout.Label("Edit Mode", GUILayout.Width(86));
                script.mode = (RagdollEditor.Mode)EditorGUILayout.EnumPopup(string.Empty, script.mode, GUILayout.Width(100));
                GUILayout.EndHorizontal();


                GUILayout.BeginHorizontal();
                GUILayout.Label("Symmetry", GUILayout.Width(86));
                script.symmetry = GUILayout.Toggle(script.symmetry, string.Empty);
                GUILayout.EndHorizontal();

                GUILayout.Space(10);

                // COLLIDERS
                if (script.mode == RagdollEditor.Mode.Colliders && selected != null)
                {
                    if (script.selectedCollider is CapsuleCollider)
                    {
                        var capsule  = script.selectedCollider as CapsuleCollider;
                        var capsuleS = symmetricCollider != null?symmetricCollider.transform.GetComponent <CapsuleCollider>() : null;

                        if (GUILayout.Button("Convert To Box Collider"))
                        {
                            ColliderTools.ConvertToBoxCollider(capsule);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (capsuleS != null)
                            {
                                ColliderTools.ConvertToBoxCollider(capsuleS);
                            }
                            return;
                        }

                        if (GUILayout.Button("Convert To Sphere Collider"))
                        {
                            ColliderTools.ConvertToSphereCollider(capsule);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (capsuleS != null)
                            {
                                ColliderTools.ConvertToSphereCollider(capsuleS);
                            }
                            return;
                        }

                        string capsuleDir = capsule.direction == 0? "X": (capsule.direction == 1? "Y": "Z");

                        if (GUILayout.Button("Direction: " + capsuleDir))
                        {
                            if (capsuleS == null)
                            {
                                Undo.RecordObject(capsule, "Change Capsule Direction");
                            }
                            else
                            {
                                Undo.RecordObjects(new Object[2] {
                                    capsule, capsuleS
                                }, "Change Capsule Direction");
                            }

                            capsule.direction++;
                            if (capsule.direction > 2)
                            {
                                capsule.direction = 0;
                            }
                            if (capsuleS != null)
                            {
                                capsuleS.direction = capsule.direction;
                            }
                        }
                    }
                    else if (script.selectedCollider is BoxCollider)
                    {
                        var box  = script.selectedCollider as BoxCollider;
                        var boxS = symmetricCollider != null?symmetricCollider.transform.GetComponent <BoxCollider>() : null;

                        if (GUILayout.Button("Convert To Capsule Collider"))
                        {
                            ColliderTools.ConvertToCapsuleCollider(box);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (boxS != null)
                            {
                                ColliderTools.ConvertToCapsuleCollider(boxS);
                            }
                            return;
                        }

                        if (GUILayout.Button("Convert To Sphere Collider"))
                        {
                            ColliderTools.ConvertToSphereCollider(box);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (boxS != null)
                            {
                                ColliderTools.ConvertToSphereCollider(boxS);
                            }
                            return;
                        }

                        if (GUILayout.Button("Rotate Collider"))
                        {
                            if (boxS == null)
                            {
                                Undo.RecordObject(box, "Rotate Collider");
                            }
                            else
                            {
                                Undo.RecordObjects(new Object[2] {
                                    box, boxS
                                }, "Rotate Collider");
                            }

                            box.size = new Vector3(box.size.y, box.size.z, box.size.x);
                            if (boxS != null)
                            {
                                boxS.size = box.size;
                            }
                        }
                    }
                    else if (script.selectedCollider is SphereCollider)
                    {
                        var sphere  = script.selectedCollider as SphereCollider;
                        var sphereS = symmetricCollider != null?symmetricCollider.transform.GetComponent <SphereCollider>() : null;

                        if (GUILayout.Button("Convert To Capsule Collider"))
                        {
                            ColliderTools.ConvertToCapsuleCollider(sphere);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (sphereS != null)
                            {
                                ColliderTools.ConvertToCapsuleCollider(sphereS);
                            }
                            return;
                        }

                        if (GUILayout.Button("Convert To Box Collider"))
                        {
                            ColliderTools.ConvertToBoxCollider(sphere);
                            script.selectedCollider = selected.GetComponent <Collider>();
                            if (sphereS != null)
                            {
                                ColliderTools.ConvertToBoxCollider(sphereS);
                            }
                            return;
                        }
                    }
                }

                // JOINTS
                if (script.mode == RagdollEditor.Mode.Joints)
                {
                    if (joint != null && (joint is CharacterJoint || joint is ConfigurableJoint))
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("Connected Body");

                        var lastConnectedBody = joint.connectedBody;
                        var newConnectedBody  = (Rigidbody)EditorGUILayout.ObjectField(joint.connectedBody, typeof(Rigidbody), true);
                        if (newConnectedBody != lastConnectedBody)
                        {
                            Undo.RecordObject(joint, "Changing Joint ConnectedBody");
                            joint.connectedBody = newConnectedBody;
                        }

                        GUILayout.EndHorizontal();

                        if (joint is CharacterJoint)
                        {
                            var j  = joint as CharacterJoint;
                            var sJ = symmetricJoint != null && symmetricJoint is CharacterJoint? symmetricJoint as CharacterJoint: null;

                            if (GUILayout.Button("Convert to Configurable"))
                            {
                                JointConverter.CharacterToConfigurable(j);

                                if (sJ != null)
                                {
                                    JointConverter.CharacterToConfigurable(sJ);
                                }
                            }

                            if (GUILayout.Button("Switch Yellow/Green"))
                            {
                                JointTools.SwitchXY(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchXY(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Switch Yellow/Blue"))
                            {
                                JointTools.SwitchXZ(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchXZ(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Switch Green/Blue"))
                            {
                                JointTools.SwitchYZ(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchYZ(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Invert Yellow"))
                            {
                                JointTools.InvertAxis(ref joint);
                                if (sJ != null)
                                {
                                    JointTools.InvertAxis(ref symmetricJoint);
                                }
                            }
                        }

                        if (joint is ConfigurableJoint)
                        {
                            var j  = joint as ConfigurableJoint;
                            var sJ = symmetricJoint != null && symmetricJoint is ConfigurableJoint? symmetricJoint as ConfigurableJoint: null;

                            if (GUILayout.Button("Switch Yellow/Green"))
                            {
                                JointTools.SwitchXY(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchXY(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Switch Yellow/Blue"))
                            {
                                JointTools.SwitchXZ(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchXZ(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Switch Green/Blue"))
                            {
                                JointTools.SwitchYZ(ref j);
                                if (sJ != null)
                                {
                                    JointTools.SwitchYZ(ref sJ);
                                }
                            }

                            if (GUILayout.Button("Invert Yellow"))
                            {
                                JointTools.InvertAxis(ref joint);
                                if (sJ != null)
                                {
                                    JointTools.InvertAxis(ref symmetricJoint);
                                }
                            }
                        }
                    }
                }

                GUILayout.EndVertical();
                //GUILayout.EndArea();
                Handles.EndGUI();

                if (script.mode == RagdollEditor.Mode.Joints && joint != null)
                {
                    if (joint is CharacterJoint)
                    {
                        var j = joint as CharacterJoint;

                        SoftJointLimit lowTwistLimit  = j.lowTwistLimit;
                        SoftJointLimit highTwistLimit = j.highTwistLimit;
                        SoftJointLimit swing1Limit    = j.swing1Limit;
                        SoftJointLimit swing2Limit    = j.swing2Limit;

                        CharacterJointInspector.DrawJoint(j);

                        if (symmetricJoint != null && symmetricJoint is CharacterJoint)
                        {
                            var sJ = symmetricJoint as CharacterJoint;

                            CharacterJointInspector.DrawJoint(sJ, false, 0.5f);

                            // Low Twist
                            if (lowTwistLimit.limit != j.lowTwistLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");

                                Vector3 lowXAxisWorld       = JointTools.GetLowXAxisWorld(j);
                                Vector3 lowXAxisWorldS      = JointTools.GetLowXAxisWorld(sJ);
                                Vector3 lowXAxisWorldMirror = SymmetryTools.Mirror(lowXAxisWorld, script.transform);
                                bool    low = Vector3.Dot(lowXAxisWorldMirror, lowXAxisWorldS) < 0f;

                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Primary, sJ, script.transform);
                                float     delta      = j.lowTwistLimit.limit - lowTwistLimit.limit;

                                JointTools.ApplyXDeltaToJointLimit(ref sJ, delta, sJointAxis, low);
                            }

                            // High Twist
                            if (highTwistLimit.limit != j.highTwistLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");

                                Vector3 highXAxisWorld       = JointTools.GetHighXAxisWorld(j);
                                Vector3 highXAxisWorldS      = JointTools.GetHighXAxisWorld(sJ);
                                Vector3 highXAxisWorldMirror = SymmetryTools.Mirror(highXAxisWorld, script.transform);
                                bool    low = Vector3.Dot(highXAxisWorldMirror, highXAxisWorldS) > 0f;

                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Primary, sJ, script.transform);
                                float     delta      = j.highTwistLimit.limit - highTwistLimit.limit;

                                JointTools.ApplyXDeltaToJointLimit(ref sJ, -delta, sJointAxis, low);
                            }

                            // Swing 1
                            if (swing1Limit.limit != j.swing1Limit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");
                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Secondary, sJ, script.transform);
                                float     delta      = j.swing1Limit.limit - swing1Limit.limit;

                                JointTools.ApplyDeltaToJointLimit(ref sJ, delta, sJointAxis);
                            }

                            // Swing 2
                            if (swing2Limit.limit != j.swing2Limit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");
                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Tertiary, sJ, script.transform);
                                float     delta      = j.swing2Limit.limit - swing2Limit.limit;

                                JointTools.ApplyDeltaToJointLimit(ref sJ, delta, sJointAxis);
                            }
                        }
                    }
                    else if (joint is ConfigurableJoint)
                    {
                        var j = joint as ConfigurableJoint;

                        SoftJointLimit lowAngularXLimit  = j.lowAngularXLimit;
                        SoftJointLimit highAngularXLimit = j.highAngularXLimit;
                        SoftJointLimit angularYLimit     = j.angularYLimit;
                        SoftJointLimit angularZLimit     = j.angularZLimit;

                        ConfigurableJointInspector.DrawJoint(j);

                        if (symmetricJoint != null && symmetricJoint is ConfigurableJoint)
                        {
                            var sJ = symmetricJoint as ConfigurableJoint;

                            ConfigurableJointInspector.DrawJoint(sJ, false, 0.5f);

                            // Low X
                            if (lowAngularXLimit.limit != j.lowAngularXLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");

                                Vector3 lowXAxisWorld       = JointTools.GetLowXAxisWorld(j);
                                Vector3 lowXAxisWorldS      = JointTools.GetLowXAxisWorld(sJ);
                                Vector3 lowXAxisWorldMirror = SymmetryTools.Mirror(lowXAxisWorld, script.transform);
                                bool    low = Vector3.Dot(lowXAxisWorldMirror, lowXAxisWorldS) < 0f;

                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Primary, sJ, script.transform);
                                float     delta      = j.lowAngularXLimit.limit - lowAngularXLimit.limit;

                                JointTools.ApplyXDeltaToJointLimit(ref sJ, delta, sJointAxis, low);
                            }

                            // High X
                            if (highAngularXLimit.limit != j.highAngularXLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");

                                Vector3 highXAxisWorld       = JointTools.GetHighXAxisWorld(j);
                                Vector3 highXAxisWorldS      = JointTools.GetHighXAxisWorld(sJ);
                                Vector3 highXAxisWorldMirror = SymmetryTools.Mirror(highXAxisWorld, script.transform);
                                bool    low = Vector3.Dot(highXAxisWorldMirror, highXAxisWorldS) > 0f;

                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Primary, sJ, script.transform);
                                float     delta      = j.highAngularXLimit.limit - highAngularXLimit.limit;

                                JointTools.ApplyXDeltaToJointLimit(ref sJ, -delta, sJointAxis, low);
                            }

                            // Y
                            if (angularYLimit.limit != j.angularYLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");
                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Secondary, sJ, script.transform);
                                float     delta      = j.angularYLimit.limit - angularYLimit.limit;

                                JointTools.ApplyDeltaToJointLimit(ref sJ, delta, sJointAxis);
                            }

                            // Z
                            if (angularZLimit.limit != j.angularZLimit.limit)
                            {
                                Undo.RecordObject(sJ, "Change Joint Limits");
                                JointAxis sJointAxis = JointTools.GetSymmetricJointAxis(j, JointAxis.Tertiary, sJ, script.transform);
                                float     delta      = j.angularZLimit.limit - angularZLimit.limit;

                                JointTools.ApplyDeltaToJointLimit(ref sJ, delta, sJointAxis);
                            }
                        }
                    }
                }
            }

            if (!Application.isPlaying)
            {
                foreach (Collider c in colliders)
                {
                    c.enabled = script.mode == RagdollEditor.Mode.Colliders;
                }
            }

            // HANDLES
            Color color = new Color(0.2f, 0.9f, 0.5f);

            Handles.color = color;

            if (Event.current.type == EventType.MouseUp)
            {
                isDragging = false;
            }
            if (Event.current.type == EventType.MouseDown)
            {
                isDragging = false;
            }

            if (script.mode == RagdollEditor.Mode.Colliders)
            {
                // Select/move scale colliders
                for (int i = 0; i < colliders.Length; i++)
                {
                    if (colliders[i] == script.selectedCollider)
                    {
                        // Moving and scaling selected colliders
                        switch (Tools.current)
                        {
                        case Tool.Move:
                            Vector3 oldPosition = ColliderTools.GetColliderCenterWorld(colliders[i]);
                            Vector3 newPosition = Handles.PositionHandle(oldPosition, colliders[i].transform.rotation);
                            if (newPosition != oldPosition)
                            {
                                if (!isDragging)
                                {
                                    Undo.RecordObjects(SymmetryTools.GetColliderPair(colliders[i], symmetricCollider), "Move Colliders");

                                    isDragging = true;
                                }

                                ColliderTools.SetColliderCenterWorld(colliders[i], symmetricCollider, newPosition, script.transform);
                            }
                            break;

                        case Tool.Scale:
                            Vector3 position = ColliderTools.GetColliderCenterWorld(colliders[i]);
                            Vector3 oldSize  = ColliderTools.GetColliderSize(colliders[i]);
                            Vector3 oldSizeS = ColliderTools.GetColliderSize(symmetricCollider);
                            Vector3 newSize  = Handles.ScaleHandle(oldSize, position, colliders[i].transform.rotation, HandleUtility.GetHandleSize(position));
                            if (newSize != oldSize)
                            {
                                if (!isDragging)
                                {
                                    Undo.RecordObjects(SymmetryTools.GetColliderPair(colliders[i], symmetricCollider), "Scale Colliders");

                                    isDragging = true;
                                }

                                ColliderTools.SetColliderSize(colliders[i], symmetricCollider, newSize, oldSize, oldSizeS, script.transform);
                            }

                            Handles.color = color;
                            break;
                        }

                        // Dot on selected collider
                        if (Tools.current != Tool.Scale)
                        {
                            Handles.color = new Color(0.8f, 0.8f, 0.8f);
                            Vector3 center = ColliderTools.GetColliderCenterWorld(colliders[i]);
                            float   size   = GetHandleSize(center);
                            Inspector.CubeCap(0, center, colliders[i].transform.rotation, size);
                            Handles.color = color;
                        }
                    }
                    else
                    {
                        // Selecting colliders
                        Vector3 center = ColliderTools.GetColliderCenterWorld(colliders[i]);
                        float   size   = GetHandleSize(center);

                        if (Inspector.DotButton(center, Quaternion.identity, size * 0.5f, size * 0.5f))
                        {
                            Undo.RecordObject(script, "Change RagdollEditor Selection");

                            script.selectedCollider = colliders[i];
                        }
                    }
                }
            }
            else
            {
                // Select joints
                for (int i = 0; i < rigidbodies.Length; i++)
                {
                    if (rigidbodies[i] == script.selectedRigidbody)
                    {
                        // Dots on selected joints
                        Handles.color = new Color(0.8f, 0.8f, 0.8f);
                        Vector3 center = rigidbodies[i].transform.position;
                        float   size   = GetHandleSize(center);
                        Inspector.CubeCap(0, center, rigidbodies[i].transform.rotation, size);
                        Handles.color = color;
                    }
                    else
                    {
                        // Selecting joints
                        Vector3 center = rigidbodies[i].transform.position;
                        float   size   = GetHandleSize(center);

                        if (Inspector.DotButton(center, Quaternion.identity, size * 0.5f, size * 0.5f))
                        {
                            Undo.RecordObject(script, "Change RagdollEditor Selection");

                            script.selectedRigidbody = rigidbodies[i];
                        }
                    }
                }
            }

            Handles.color = Color.white;
        }