public void ConfigureComponents() { BoneController lBoneController = mMotionController.GetOrAddComponent <BoneController>(); lBoneController.EditorBoneFilters = mBoneFilters; Animator lAnimator = mMotionController.GetComponent <Animator>(); lBoneController.RootTransform = lAnimator.GetBoneTransform(HumanBodyBones.Hips); if (SetBoneJoints) { if (IsHumanoidRig) { lBoneController.SetHumanoidBoneJoints(0); } else { lBoneController.SetBoneJoints(0); } } if (CreateBoneColliders) { if (IsHumanoidRig) { lBoneController.SetHumanoidBoneColliders(0); } else { lBoneController.SetBoneColliders(0); } } if (UseFootIK) { CreateFootToGroundMotor(lBoneController, true); CreateFootToGroundMotor(lBoneController, false); } if (UseHandIK) { // Not using right hand IK for anything yet //CreateLimbReachMotor(lBoneController, true); CreateLimbReachMotor(lBoneController, false); } }
/// <summary> /// Called when the inspector needs to draw /// </summary> public override void OnInspectorGUI() { // Pulls variables from runtime so we have the latest values. mSkeletonSO.Update(); // Force the inspector and scene to repain if needed if (BoneController.EditorForceRepaint) { Repaint(); SceneView.RepaintAll(); BoneController.EditorForceRepaint = false; } // Grab the position of the editor. Theis is a goofy hack, but works. EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); //Rect lArea = GUILayoutUtility.GetLastRect(); // Store the positions //float lEditorY = lArea.y; //float lEditorWidth = Screen.width - 20f; //// We want the BG aligned: Top Center. We'll cut off any piece that is too arge //Rect lBGCrop = new Rect(0, 0, mBackground.width, mBackground.height - 110); //Vector2 lBGPosition = new Vector2(lEditorWidth - (mBackground.width * 0.8f), lEditorY + 5f); //GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height)); //GUI.BeginGroup(new Rect(lBGPosition.x, lBGPosition.y, lBGCrop.width, lBGCrop.height)); //GUI.DrawTexture(new Rect(-lBGCrop.x, -lBGCrop.y, mBackground.width, mBackground.height), mBackground); //GUI.EndGroup(); //GUILayout.EndArea(); // Start putting in the properites GUILayout.Space(10); GUILayout.BeginHorizontal(); Transform lNewRootTransform = EditorGUILayout.ObjectField(new GUIContent("Root Transform", "Determines if this avatar will respond to input from the user."), mSkeleton.RootTransform, typeof(Transform), true) as Transform; if (mSkeleton.RootTransform != lNewRootTransform) { mIsDirty = true; mSkeleton.RootTransform = lNewRootTransform; // Force an update since we changed the bones mSkeleton.LateUpdate(); } if (GUILayout.Button(new GUIContent(), mBlueGearStyle, GUILayout.Width(16), GUILayout.Height(16))) { mShowSettings = !mShowSettings; } GUILayout.EndHorizontal(); if (mShowSettings) { EditorGUILayout.BeginVertical(GUI.skin.box); //bool lNewUsedStandardizedBoneForward = EditorGUILayout.Toggle(new GUIContent("Use standard bone forward", "Determines if we can used standard bone forwards"), mSkeleton.UseStandardizedBoneForward); //if (lNewUsedStandardizedBoneForward != mSkeleton.UseStandardizedBoneForward) //{ // mIsDirty = true; // mSkeleton.UseStandardizedBoneForward = lNewUsedStandardizedBoneForward; //} //Vector3 lNewBoneForward = EditorGUILayout.Vector3Field(new GUIContent("Bone Forward", "Forward direction bones were created in. Typically, this is (0, 1, 0)."), mSkeleton.BoneForward); //if (lNewBoneForward != mSkeleton.BoneForward) //{ // mIsDirty = true; // mSkeleton.BoneForward = lNewBoneForward; //} //Vector3 lNewBoneUp = EditorGUILayout.Vector3Field(new GUIContent("Bone Up", "Up direction bones were created in. Typically, this is (0, 0, -1)."), mSkeleton.BoneUp); //if (lNewBoneUp != mSkeleton.BoneUp) //{ // mIsDirty = true; // mSkeleton.BoneUp = lNewBoneUp; //} //Vector3 lToBoneForward = mSkeleton.ToBoneForward.eulerAngles; //Vector3 lNewToBoneForward = EditorGUILayout.Vector3Field(new GUIContent("To Bone Forward", "Rotation that is applied that takes a 'forward' facing quaterion and makes it face along the default bone forward."), lToBoneForward); //if (lNewToBoneForward != lToBoneForward) //{ // mIsDirty = true; // mSkeleton.ToBoneForward.eulerAngles = lNewToBoneForward; //} //GUILayout.Space(5); // Determine if we're to show the joint limits bool lNewShowSkeleton = EditorGUILayout.Toggle(new GUIContent("Draw bones", "Show or hide the skeleton."), mSkeleton.EditorShowBones); if (lNewShowSkeleton != mSkeleton.EditorShowBones) { mIsDirty = true; BoneController.EditorForceRepaint = true; mSkeleton.EditorShowBones = lNewShowSkeleton; } // Determine if we're to show the joint limits bool lNewShowBoneLimits = EditorGUILayout.Toggle(new GUIContent("Draw bone limits", "Show or hide the joint limits for the selected bone."), mSkeleton.EditorShowBoneLimits); if (lNewShowBoneLimits != mSkeleton.EditorShowBoneLimits) { mIsDirty = true; BoneController.EditorForceRepaint = true; mSkeleton.EditorShowBoneLimits = lNewShowBoneLimits; } // Determine if we're to show the joint limits bool lNewShowBoneColliders = EditorGUILayout.Toggle(new GUIContent("Draw bone colliders", "Show or hide the collider for the selected bone."), mSkeleton.EditorShowBoneColliders); if (lNewShowBoneColliders != mSkeleton.EditorShowBoneColliders) { mIsDirty = true; BoneController.EditorForceRepaint = true; mSkeleton.EditorShowBoneColliders = lNewShowBoneColliders; } // Determines if the GUI elements scale with the user position bool lNewAutoScaleHandles = EditorGUILayout.Toggle(new GUIContent("Auto scale handles", "Determines if we auto scale the joint handles."), mSkeleton.EditorAutoScaleHandles); if (lNewAutoScaleHandles != mSkeleton.EditorAutoScaleHandles) { mIsDirty = true; mSkeleton.EditorAutoScaleHandles = lNewAutoScaleHandles; } GUILayout.Space(10); GUILayout.BeginVertical("Bones", GUI.skin.window); EditorGUILayout.HelpBox("Matching bind pose puts the character back to it's original pose." + Environment.NewLine + Environment.NewLine + "Reloading bones removes the existing bones and loads the skeleton over. Reloading bones could effect motors that use the bones." + Environment.NewLine + Environment.NewLine + "Use Bone Import Filters to ignore bones as we load them. Seperate multiple string values with a pipe (|).", MessageType.None); EditorGUILayout.LabelField("Bone Import Filter"); string lNewEditorBoneFilters = GUILayout.TextArea(mSkeleton.EditorBoneFilters, GUILayout.Height(40)); if (lNewEditorBoneFilters != mSkeleton.EditorBoneFilters) { mIsDirty = true; mSkeleton.EditorBoneFilters = lNewEditorBoneFilters; } GUILayout.Space(5); if (GUILayout.Button(new GUIContent("Match Bind Pose", "Resets all the bone positions and rotations back to the bind pose."))) { mSkeleton.ResetBindPose(); } if (GUILayout.Button(new GUIContent("Reload Bones", "Reload all of the bones and thier children."))) { if (mSkeleton.RootTransform != null) { if (EditorUtility.DisplayDialog("Bone Controller", "Reloading the skeleton may require you to update bones and motors. Continue?", "Yes", "No")) { mSkeleton.RootTransform = mSkeleton.RootTransform; } } } GUILayout.EndVertical(); GUILayout.Space(10); GUILayout.BeginVertical("Joints", GUI.skin.window); EditorGUILayout.HelpBox("Automatically create joints using the specific style and level of detail. This will not change joints that already exist." + Environment.NewLine + Environment.NewLine + "Removing all joints clears all bones of all joint limits and types. This cannot be undone, but joints can be re-added.", MessageType.None); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent("Style", "Style of character to build joints for."), GUILayout.Width(40)); //mJointStyleName = EditorGUILayout.TextField(mJointStyleName, GUILayout.MinWidth(50)); mJointStyleNameIndex = EditorGUILayout.Popup("", mJointStyleNameIndex, mStyleNames, GUILayout.MinWidth(50)); EditorGUILayout.LabelField(new GUIContent("Detail", "Level of detail to build joints for."), GUILayout.Width(40)); mJointDetailLevelIndex = EditorGUILayout.Popup("", mJointDetailLevelIndex, mDetailLevels, GUILayout.Width(60)); EditorGUILayout.EndHorizontal(); if (GUILayout.Button(new GUIContent("Set Joints", "Automatically create joints and limits for your character."))) { mSkeleton.SetBoneJoints(mStyleNames[mJointStyleNameIndex], mJointDetailLevelIndex); mIsDirty = true; } if (GUILayout.Button(new GUIContent("Remove Joints", "Remove all existing joints and limits."))) { if (EditorUtility.DisplayDialog("Bone Controller", "Remove all joints from the skeleton?", "Yes", "No")) { mSkeleton.RemoveBoneJoints(mJointDetailLevelIndex); mIsDirty = true; } } GUILayout.EndVertical(); GUILayout.Space(10); GUILayout.BeginVertical("Colliders", GUI.skin.window); EditorGUILayout.HelpBox("Automatically create colliders using the specific style and level of detail. This will not change colliders that already exist." + Environment.NewLine + Environment.NewLine + "Removing all colliders clears all bones of the primary collider. This cannot be undone, but colliders can be re-added." + Environment.NewLine + Environment.NewLine + "By default we use 'psuedo-colliders' that have a performance improvement and limited interaction with other colliders." + Environment.NewLine + Environment.NewLine + "When using true colliders, capsule colliders have odd collision behavior when rotated. Forcing box colliders is safer.", MessageType.None); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent("Style", "Style of character to build colliders for."), GUILayout.Width(40)); //mColliderStyleName = EditorGUILayout.TextField(mColliderStyleName, GUILayout.MinWidth(50)); mColliderStyleNameIndex = EditorGUILayout.Popup("", mColliderStyleNameIndex, mStyleNames, GUILayout.MinWidth(50)); EditorGUILayout.LabelField(new GUIContent("Detail", "Level of detail to build colliders for."), GUILayout.Width(40)); mColliderDetailLevelIndex = EditorGUILayout.Popup("", mColliderDetailLevelIndex, mDetailLevels, GUILayout.Width(60)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent("Force True Colliders", "Forces the use of true colliders over pseudo colliders."), GUILayout.Width(120)); mSkeleton.EditorForceTrueColliders = EditorGUILayout.Toggle(mSkeleton.EditorForceTrueColliders, GUILayout.Width(15)); GUILayout.Space(20); EditorGUILayout.LabelField(new GUIContent("Force Box", "Forces the use of true box colliders over true capsule colliders."), GUILayout.Width(60)); mSkeleton.EditorForceTrueBoxColliders = EditorGUILayout.Toggle(mSkeleton.EditorForceTrueBoxColliders, GUILayout.Width(15)); EditorGUILayout.EndHorizontal(); if (GUILayout.Button(new GUIContent("Set Colliders", "Automatically create joints and limits for your character."))) { mSkeleton.SetBoneColliders(mStyleNames[mColliderStyleNameIndex], mColliderDetailLevelIndex); mIsDirty = true; } if (GUILayout.Button(new GUIContent("Remove Colliders", "Remove all existing colliders."))) { if (EditorUtility.DisplayDialog("Bone Controller", "Remove all primary colliders from the skeleton?", "Yes", "No")) { mSkeleton.RemoveBoneColliders(mColliderDetailLevelIndex); mIsDirty = true; } } GUILayout.EndVertical(); EditorGUILayout.EndVertical(); } // Show the Bones GUILayout.Space(10); EditorGUI.indentLevel++; bool lNewShowBones = EditorGUILayout.Foldout(mShowBones, new GUIContent("Show bones and limits")); { BoneController.EditorForceRepaint = true; mShowBones = lNewShowBones; } EditorGUI.indentLevel--; GUILayout.BeginVertical("IK Bones (" + mSkeleton.Bones.Count + ")", GUI.skin.window, GUILayout.Height(10)); if (mShowBones) { // Filter by name GUILayout.BeginVertical(); GUILayout.BeginHorizontal(GUI.skin.FindStyle("Toolbar")); mBoneSearchString = GUILayout.TextField(mBoneSearchString, GUI.skin.FindStyle("ToolbarSeachTextField"), GUILayout.ExpandWidth(true)); if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) { mBoneSearchString = ""; GUI.FocusControl(null); } GUILayout.EndHorizontal(); // Filter by selected bool lNewShowSelectedBones = EditorGUILayout.Toggle(new GUIContent("Only show selected bones", "Show only selected bones in the list."), mSkeleton.EditorShowSelectedBones); if (lNewShowSelectedBones != mSkeleton.EditorShowSelectedBones) { mIsDirty = true; mSkeleton.EditorShowSelectedBones = lNewShowSelectedBones; } GUILayout.EndVertical(); // Render the list bool lIsBoneListDirty = RenderBoneList(mBoneSearchString, mSkeleton.EditorShowSelectedBones); mIsDirty = mIsDirty || lIsBoneListDirty; } else { EditorGUILayout.LabelField("Click arrow above to show bone list..."); } GUILayout.EndVertical(); // Show the Motors GUILayout.Space(10); EditorGUI.indentLevel++; bool lNewShowMotors = EditorGUILayout.Foldout(mShowMotors, new GUIContent("Show bone motors")); if (lNewShowMotors != mShowMotors) { BoneController.EditorForceRepaint = true; mShowMotors = lNewShowMotors; } EditorGUI.indentLevel--; GUILayout.BeginVertical("IK Motors (" + mSkeleton.Motors.Count + ")", GUI.skin.window, GUILayout.Height(10)); if (mShowMotors) { bool lIsMotorListDirty = RenderMotorList(); mIsDirty = mIsDirty || lIsMotorListDirty; GUILayout.FlexibleSpace(); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); mSelectedMotorTypeIndex = EditorGUILayout.Popup(mSelectedMotorTypeIndex, mMotorNames.ToArray(), GUILayout.Width(150)); if (GUILayout.Button(new GUIContent("+", "Add Motor"), EditorStyles.miniButtonLeft, GUILayout.Width(20))) { mIsDirty = true; AddMotor(mMotorTypes[mSelectedMotorTypeIndex]); } if (GUILayout.Button(new GUIContent("-", "Delete Motor"), EditorStyles.miniButtonRight, GUILayout.Width(20))) { mIsDirty = true; RemoveMotor(mSelectedMotorIndex); // Clear any rotations and update. This will clear out any influence // from a motor we deleted mSkeleton.ResetBindPose(); // Force an update mSkeleton.LateUpdate(); } EditorGUILayout.EndHorizontal(); GUILayout.EndVertical(); // Show the layer motions GUILayout.Space(10); GUILayout.BeginVertical("IK Motor Properties", GUI.skin.window, GUILayout.Height(100)); bool lIsMotorDirty = RenderMotorProperties(mSelectedMotorIndex); mIsDirty = mIsDirty || lIsMotorDirty; } else { EditorGUILayout.LabelField("Click arrow above to show motor list..."); } GUILayout.EndVertical(); // Add some space at the bottom GUILayout.Space(10); // If there is a change... update. if (mIsDirty) { // Flag the object as needing to be saved EditorUtility.SetDirty(mSkeleton); #if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 EditorApplication.MarkSceneDirty(); #else if (!EditorApplication.isPlaying) { UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene()); } #endif // Pushes the values back to the runtime so it has the changes mSkeletonSO.ApplyModifiedProperties(); // Clear out the dirty flag mIsDirty = false; } }