public override void OnInspectorGUI()
        {
            serializedObject.Update();

            ArticulationBody body       = (ArticulationBody)target;
            ArticulationBody parentBody = FindParentBody(body);

            EditorGUILayout.PropertyField(m_Mass);

            if (body.isRoot)
            {
                EditorGUILayout.PropertyField(m_Immovable);

                EditorGUILayout.HelpBox("This is the root body of the articulation.", MessageType.Info);
            }
            else
            {
                EditorGUILayout.PropertyField(m_ComputeParentAnchor);

                // Show anchor edit fields and set to joint if changed
                // The reason we have change checks here is because in AwakeFromLoad we won't overwrite anchors
                // If we were to do that, simulation would drift caused by anchors reset relative to current poses
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(m_AnchorPosition);
                QuaternionAsEulerAnglesPropertyField("Anchor Rotation", m_AnchorRotation, body.anchorRotation);
                if (EditorGUI.EndChangeCheck())
                {
                    body.anchorPosition = m_AnchorPosition.vector3Value;
                    body.anchorRotation = m_AnchorRotation.quaternionValue;

                    if (m_ComputeParentAnchor.boolValue)
                    {
                        // setting child anchors in this mode will also change the parent ones
                        // lets fetch them back otherwise ApplyModifiedProperties overwrites them
                        m_ParentAnchorPosition.vector3Value    = body.parentAnchorPosition;
                        m_ParentAnchorRotation.quaternionValue = body.parentAnchorRotation;
                    }
                }

                // parent anchors
                if (!m_ComputeParentAnchor.boolValue)
                {
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(m_ParentAnchorPosition);
                    QuaternionAsEulerAnglesPropertyField("Parent Anchor Rotation", m_ParentAnchorRotation, body.parentAnchorRotation);

                    if (EditorGUI.EndChangeCheck())
                    {
                        body.parentAnchorPosition = m_ParentAnchorPosition.vector3Value;
                        body.parentAnchorRotation = m_ParentAnchorRotation.quaternionValue;
                    }
                }

                if (GUILayout.Button("Snap anchor to closest contact"))
                {
                    Vector3 com = parentBody.centerOfMass;
                    Vector3 closestOnSurface = body.GetClosestPoint(com);
                    body.anchorPosition = body.transform.InverseTransformPoint(closestOnSurface);
                    body.anchorRotation = Quaternion.FromToRotation(Vector3.right, body.transform.InverseTransformDirection(com - closestOnSurface).normalized);
                }

                EditorGUILayout.PropertyField(m_ArticulationJointType);

                EditorGUILayout.PropertyField(m_LinearDamping);
                EditorGUILayout.PropertyField(m_AngularDamping);
                EditorGUILayout.PropertyField(m_JointFriction);

                switch (body.jointType)
                {
                case ArticulationJointType.FixedJoint:
                    break;

                case ArticulationJointType.PrismaticJoint:
                    // toggles
                    PrismaticJointAxisLockProperty(m_LinearX);
                    PrismaticJointAxisLockProperty(m_LinearY);
                    PrismaticJointAxisLockProperty(m_LinearZ);

                    EditorGUILayout.Space();
                    if (body.linearLockX != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_XDrive);
                    }

                    if (body.linearLockY != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_YDrive);
                    }

                    if (body.linearLockZ != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_ZDrive);
                    }

                    break;

                case ArticulationJointType.RevoluteJoint:
                    EditorGUILayout.PropertyField(m_Twist);

                    EditorGUILayout.Space();
                    StructPropertyGUILayout.GenericStruct(m_XDrive);

                    break;

                case ArticulationJointType.SphericalJoint:
                    EditorGUILayout.PropertyField(m_SwingY);
                    EditorGUILayout.PropertyField(m_SwingZ);
                    EditorGUILayout.PropertyField(m_Twist);

                    EditorGUILayout.Space();

                    if (body.swingYLock != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_YDrive);
                    }

                    if (body.swingZLock != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_ZDrive);
                    }

                    if (body.twistLock != ArticulationDofLock.LockedMotion)
                    {
                        StructPropertyGUILayout.GenericStruct(m_XDrive);
                    }

                    break;
                }
            }

            serializedObject.ApplyModifiedProperties();
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            ArticulationBody body       = (ArticulationBody)target;
            ArticulationBody parentBody = FindParentBody(body);

            EditorGUILayout.PropertyField(m_Mass);

            if (body.isRoot)
            {
                EditorGUILayout.PropertyField(m_Immovable);
                EditorGUILayout.PropertyField(m_UseGravity);

                EditorGUILayout.HelpBox("This is the root body of the articulation.", MessageType.Info);
            }
            else
            {
                EditorGUILayout.PropertyField(m_UseGravity);
                EditorGUILayout.PropertyField(m_ComputeParentAnchor);

                // Render anchor handle display button only if editor scene view has Move, Rotate or Transform tool mode selected
                if (IsEditToolModeForAnchorDisplay())
                {
                    if (m_DisplayParentAnchor)
                    {
                        m_DisplayParentAnchor = !GUILayout.Button("Show anchor handle");
                    }
                    else
                    {
                        m_DisplayParentAnchor = GUILayout.Button("Show parent anchor handle");
                    }
                }

                // Show anchor edit fields and set to joint if changed
                // The reason we have change checks here is because in AwakeFromLoad we won't overwrite anchors
                // If we were to do that, simulation would drift caused by anchors reset relative to current poses
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(m_AnchorPosition);
                QuaternionAsEulerAnglesPropertyField("Anchor Rotation", m_AnchorRotation, body.anchorRotation);
                if (EditorGUI.EndChangeCheck())
                {
                    body.anchorPosition = m_AnchorPosition.vector3Value;
                    body.anchorRotation = m_AnchorRotation.quaternionValue;

                    if (m_ComputeParentAnchor.boolValue)
                    {
                        // setting child anchors in this mode will also change the parent ones
                        // lets fetch them back otherwise ApplyModifiedProperties overwrites them
                        m_ParentAnchorPosition.vector3Value    = body.parentAnchorPosition;
                        m_ParentAnchorRotation.quaternionValue = body.parentAnchorRotation;
                    }
                }

                // parent anchors
                if (!m_ComputeParentAnchor.boolValue)
                {
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(m_ParentAnchorPosition);
                    QuaternionAsEulerAnglesPropertyField("Parent Anchor Rotation", m_ParentAnchorRotation,
                                                         body.parentAnchorRotation);

                    if (EditorGUI.EndChangeCheck())
                    {
                        body.parentAnchorPosition = m_ParentAnchorPosition.vector3Value;
                        body.parentAnchorRotation = m_ParentAnchorRotation.quaternionValue;
                    }
                }

                if (GUILayout.Button("Snap anchor to closest contact"))
                {
                    Undo.RecordObject(body, "Changing anchor position/rotation to match closest contact.");
                    Vector3 com = parentBody.centerOfMass;
                    Vector3 closestOnSurface = body.GetClosestPoint(com);
                    body.anchorPosition = body.transform.InverseTransformPoint(closestOnSurface);
                    body.anchorRotation = Quaternion.FromToRotation(Vector3.right,
                                                                    body.transform.InverseTransformDirection(com - closestOnSurface).normalized);
                }

                EditorGUILayout.PropertyField(m_ArticulationJointType);

                EditorGUILayout.PropertyField(m_LinearDamping);
                EditorGUILayout.PropertyField(m_AngularDamping);
                EditorGUILayout.PropertyField(m_JointFriction);

                switch (body.jointType)
                {
                case ArticulationJointType.FixedJoint:
                    break;

                case ArticulationJointType.PrismaticJoint:
                    // work out joint settings
                    LinearDof           linearDof      = LinearDof.X; // x by default
                    ArticulationDofLock dofLockSetting = ArticulationDofLock.FreeMotion;

                    if (body.linearLockX != ArticulationDofLock.LockedMotion)
                    {
                        linearDof      = LinearDof.X;
                        dofLockSetting = body.linearLockX;
                    }
                    else if (body.linearLockY != ArticulationDofLock.LockedMotion)
                    {
                        linearDof      = LinearDof.Y;
                        dofLockSetting = body.linearLockY;
                    }
                    else if (body.linearLockZ != ArticulationDofLock.LockedMotion)
                    {
                        linearDof      = LinearDof.Z;
                        dofLockSetting = body.linearLockZ;
                    }

                    int dofCount = 0;

                    if (body.linearLockX != ArticulationDofLock.LockedMotion)
                    {
                        dofCount++;
                    }
                    if (body.linearLockY != ArticulationDofLock.LockedMotion)
                    {
                        dofCount++;
                    }
                    if (body.linearLockZ != ArticulationDofLock.LockedMotion)
                    {
                        dofCount++;
                    }

                    bool overrideDof = (dofCount != 1);

                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.Space();
                    linearDof = (LinearDof)EditorGUILayout.EnumPopup("Axis", linearDof);
                    NonLockedMotion motion = (dofLockSetting == ArticulationDofLock.FreeMotion) ? NonLockedMotion.Free : NonLockedMotion.Limited;
                    motion = (NonLockedMotion)EditorGUILayout.EnumPopup("Motion", motion);
                    if (EditorGUI.EndChangeCheck() || overrideDof)
                    {
                        m_LinearX.enumValueIndex = (linearDof == LinearDof.X) ? (int)motion : 0;
                        m_LinearY.enumValueIndex = (linearDof == LinearDof.Y) ? (int)motion : 0;
                        m_LinearZ.enumValueIndex = (linearDof == LinearDof.Z) ? (int)motion : 0;
                    }

                    EditorGUILayout.Space();

                    DoDriveInspector(m_YDrive, (ArticulationDofLock)m_LinearY.enumValueIndex);
                    DoDriveInspector(m_ZDrive, (ArticulationDofLock)m_LinearZ.enumValueIndex);
                    DoDriveInspector(m_XDrive, (ArticulationDofLock)m_LinearX.enumValueIndex);

                    break;

                case ArticulationJointType.RevoluteJoint:
                    ArticulationDofLock serialisedDofLock = (ArticulationDofLock)m_Twist.enumValueIndex;

                    NonLockedMotion revoluteMotion = serialisedDofLock == ArticulationDofLock.LimitedMotion
                            ? NonLockedMotion.Limited
                            : NonLockedMotion.Free;

                    EditorGUILayout.Space();
                    motion = (NonLockedMotion)EditorGUILayout.EnumPopup("Motion", revoluteMotion);

                    ArticulationDofLock newDofLock = (ArticulationDofLock)motion;

                    if (newDofLock != serialisedDofLock)
                    {
                        m_Twist.enumValueIndex = (int)newDofLock;
                    }

                    EditorGUILayout.Space();
                    DoDriveInspector(m_XDrive, newDofLock);

                    break;

                case ArticulationJointType.SphericalJoint:
                    EditorGUILayout.Space();
                    // here we just need to make sure we disable getting into an invalid configuration
                    SphericalJointMotionSetting(m_SwingY);
                    SphericalJointMotionSetting(m_SwingZ);
                    SphericalJointMotionSetting(m_Twist);

                    EditorGUILayout.Space();

                    DoDriveInspector(m_YDrive, body.swingYLock);
                    DoDriveInspector(m_ZDrive, body.swingZLock);
                    DoDriveInspector(m_XDrive, body.twistLock);

                    break;
                }
            }
            serializedObject.ApplyModifiedProperties();
            ShowBodyInfoProperties();
        }