/// <summary> /// Destroys the instance of the skinned item /// </summary> /// <param name="rItem"></param> public void RemoveSkinnedItemInstance(SkinnedItem rItem) { if (rItem == null || rItem._GameObject == null) { return; } rItem.DestroyInstance(); }
/// <summary> /// Instanciate a child GameObject and use the parent bones in order to drive this child's skinned mesh. /// Since skinned meshes wrap specific bones, we don't need a parent bone to attach the child to. /// </summary> /// <param name="rItemPath">Path to the prefab we'll instanciate</param> /// <returns>MountItem containing the results of the instanciation</returns> public SkinnedItem AddSkinnedItem(string rItemPath) { if (rItemPath == null || rItemPath.Length == 0) { return null; } SkinnedItem lItem = new SkinnedItem(); lItem.ResourcePath = rItemPath; bool lCreated = AddSkinnedItem(lItem); if (!lCreated) { return null; } return lItem; }
/// <summary> /// Removes the skinned mesh from the list of items /// </summary> /// <param name="rItem"></param> public void RemoveSkinnedItem(SkinnedItem rItem) { if (rItem == null) { return; } rItem.DestroyInstance(); SkinnedItems.Remove(rItem); // Apply the body masks if needed ApplyBodyMasks(); }
/// <summary> /// Instanciate a child GameObject and use the parent bones in order to drive this child's skinned mesh. /// Since skinned meshes wrap specific bones, we don't need a parent bone to attach the child to. /// </summary> /// <param name="rItem">MountItem containing the location of the prefab and mask to instanciate</param> /// <returns>Boolean that determines if we added the skinned mesh</returns> public bool AddSkinnedItem(SkinnedItem rItem) { if (SkinnedItems.Contains(rItem)) { return false; } rItem.IsVisible = (rItem.ResourcePath.Length > 0); rItem.IsMaskVisible = (rItem.MaskPath.Length > 0); // Create the instance from the path if (rItem.ResourcePath.Length > 0) { rItem.CreateInstance(this); if (rItem.GameObject == null) { return false; } } // Add the mount item to the list if (_UseBodyMasks && rItem.MaskPath.Length > 0) { rItem.CreateMask(); } // Add the item to our list SkinnedItems.Add(rItem); // Apply the body masks if needed ApplyBodyMasks(); // Return success return true; }
/// <summary> /// Renders the properties of the motion so they can be changed here /// </summary> /// <param name="rLayerIndex">Layer the motion belongs to</param> /// <param name="rMotionIndex">Motions whose properites are to be listed</param> private bool DrawItemDetailItem(SkinnedItem rItem) { bool lIsDirty = false; EditorHelper.DrawSmallTitle(rItem.Name); // Warning about the resource not being found if (rItem._GameObject == null && rItem._ResourcePath.Length > 0 && Resources.Load(rItem._ResourcePath) == null) { EditorHelper.DrawInspectorDescription("Resource not found. If you want to instantiate the item at run-time, please ensure the file is in a 'Resources' folder.", MessageType.None); GUILayout.Space(5); } else { EditorGUILayout.LabelField("", GUILayout.Height(1f)); } // Friendly name string lNewName = EditorGUILayout.TextField(new GUIContent("Name", "Friendly name of the skinned item."), rItem.Name); if (lNewName != rItem.Name) { lIsDirty = true; rItem.Name = lNewName; } // Resource Path string lNewResourcePath = EditorGUILayout.TextField(new GUIContent("Resource Path", "Path to the prefab resource that is the item."), rItem.ResourcePath); if (lNewResourcePath != rItem.ResourcePath) { lIsDirty = true; rItem.ResourcePath = lNewResourcePath; } // Mask Path string lNewMaskPath = EditorGUILayout.TextField(new GUIContent("Mask Path", "Path to the texture resource that will mask the body."), rItem.MaskPath); if (lNewMaskPath != rItem.MaskPath) { lIsDirty = true; // Now we can set the mask rItem.MaskPath = lNewMaskPath; // If it was visible or if it is now, we need to apply the mask if (Application.isPlaying && mTarget.UseBodyMasks) { rItem.CreateMask(); mTarget.ApplyBodyMasks(); } } bool lNewInstanciateOnStart = EditorGUILayout.Toggle(new GUIContent("Instantiate On Start", "Determines if we create an instance of the object and mask when the game starts."), rItem.InstantiateOnStart); if (lNewInstanciateOnStart != rItem.InstantiateOnStart) { lIsDirty = true; rItem.InstantiateOnStart = lNewInstanciateOnStart; } bool lNewIsVisible = EditorGUILayout.Toggle(new GUIContent("Is Instance Visible", "Determines if the object itself is visible."), rItem.IsVisible); if (lNewIsVisible != rItem.IsVisible) { lIsDirty = true; rItem.IsVisible = lNewIsVisible; } bool lNewIsMaskVisible = EditorGUILayout.Toggle(new GUIContent("Is Mask Visible", "Determines if the body mask is visible."), rItem.IsMaskVisible); if (lNewIsMaskVisible != rItem.IsMaskVisible) { lIsDirty = true; // Now we can set the visability rItem.IsMaskVisible = lNewIsMaskVisible; // If it was visible or if it is now, we need to apply the mask if (Application.isPlaying && mTarget.UseBodyMasks) { mTarget.ApplyBodyMasks(); } } // Object EditorHelper.DrawLine(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Instance:", GUILayout.Width(60)); if (rItem.GameObject == null) { GUILayout.Label("<none>", GUILayout.MinWidth(100)); if (GUILayout.Button(new GUIContent("", "Create instance"), EditorHelper.BlueAddButton, GUILayout.Width(16), GUILayout.Height(16))) { rItem.CreateInstance(mTarget); if (mTarget.UseBodyMasks) { rItem.CreateMask(); mTarget.ApplyBodyMasks(); } } } else { GUILayout.Label(rItem.GameObject.name, GUILayout.MinWidth(100)); if (GUILayout.Button(new GUIContent("", "Select instance"), EditorHelper.BlueSelectButton, GUILayout.Width(16), GUILayout.Height(16))) { Selection.activeGameObject = rItem.GameObject; } if (GUILayout.Button(new GUIContent("", "Delete instance"), EditorHelper.RedXButton, GUILayout.Width(16), GUILayout.Height(16))) { mTarget.RemoveSkinnedItemInstance(rItem); } } GUILayout.Space(2); EditorGUILayout.EndHorizontal(); GUILayout.Space(5); return lIsDirty; }
/// <summary> /// Allows us to add to a list /// </summary> /// <param name="rList"></param> private void OnItemListItemAdd(ReorderableList rList) { // Create a skinned item SkinnedItem lItem = new SkinnedItem(); mTarget.AddSkinnedItem(lItem); // Set the visible values after we add it lItem.IsVisible = true; lItem.IsMaskVisible = true; // Make it the selected one mItemList.index = mTarget.SkinnedItems.Count - 1; OnItemListItemSelect(rList); mIsDirty = true; }
/// <summary> /// Renders the properties of the motion so they can be changed here /// </summary> /// <param name="rLayerIndex">Layer the motion belongs to</param> /// <param name="rMotionIndex">Motions whose properites are to be listed</param> private bool DrawItemDetailItem(SkinnedItem rItem) { bool lIsDirty = false; EditorHelper.DrawSmallTitle(rItem.Name); // Warning about the resource not being found if (rItem._GameObject == null && rItem._ResourcePath.Length > 0 && Resources.Load(rItem._ResourcePath) == null) { EditorHelper.DrawInspectorDescription("Resource not found. If you want to instantiate the item at run-time, please ensure the file is in a 'Resources' folder.", MessageType.None); GUILayout.Space(5); } else { EditorGUILayout.LabelField("", GUILayout.Height(1f)); } // Friendly name string lNewName = EditorGUILayout.TextField(new GUIContent("Name", "Friendly name of the skinned item."), rItem.Name); if (lNewName != rItem.Name) { lIsDirty = true; rItem.Name = lNewName; } // Resource Path EditorGUILayout.BeginHorizontal(); string lNewResourcePath = EditorGUILayout.TextField(new GUIContent("Resource Path", "Path to the prefab resource that is the item."), rItem.ResourcePath); if (lNewResourcePath != rItem.ResourcePath) { lIsDirty = true; rItem.ResourcePath = lNewResourcePath; } if (GUILayout.Button(new GUIContent("...", "Select resource"), EditorStyles.miniButton, GUILayout.Width(20))) { lNewResourcePath = EditorUtility.OpenFilePanel("Select the file", mLastPath, "fbx,prefab"); if (lNewResourcePath.Length != 0) { mLastPath = lNewResourcePath; int lStartResource = lNewResourcePath.IndexOf("Resources"); if (lStartResource >= 0) { lNewResourcePath = lNewResourcePath.Substring(lStartResource + 10); } lStartResource = lNewResourcePath.IndexOf("Assets"); if (lStartResource >= 0) { lNewResourcePath = lNewResourcePath.Substring(lStartResource + 7); } int lStartExtension = lNewResourcePath.LastIndexOf("."); if (lStartExtension > 0) { lNewResourcePath = lNewResourcePath.Substring(0, lStartExtension); } if (lNewResourcePath != rItem.ResourcePath) { lIsDirty = true; rItem.ResourcePath = lNewResourcePath; } } } EditorGUILayout.EndHorizontal(); // Mask Path EditorGUILayout.BeginHorizontal(); string lNewMaskPath = EditorGUILayout.TextField(new GUIContent("Mask Path", "Path to the texture resource that will mask the body."), rItem.MaskPath); if (lNewMaskPath != rItem.MaskPath) { lIsDirty = true; // Now we can set the mask rItem.MaskPath = lNewMaskPath; // If it was visible or if it is now, we need to apply the mask if (Application.isPlaying && mTarget.UseBodyMasks) { rItem.CreateMask(); mTarget.ApplyBodyMasks(); } } if (GUILayout.Button(new GUIContent("...", "Select mask"), EditorStyles.miniButton, GUILayout.Width(20))) { lNewMaskPath = EditorUtility.OpenFilePanel("Select the file", mLastPath, "png,jpg,psd"); if (lNewMaskPath.Length != 0) { mLastPath = lNewMaskPath; int lStartResource = lNewMaskPath.IndexOf("Resources"); if (lStartResource >= 0) { lNewMaskPath = lNewMaskPath.Substring(lStartResource + 10); } lStartResource = lNewMaskPath.IndexOf("Assets"); if (lStartResource >= 0) { lNewMaskPath = lNewMaskPath.Substring(lStartResource + 7); } int lStartExtension = lNewMaskPath.LastIndexOf("."); if (lStartExtension > 0) { lNewMaskPath = lNewMaskPath.Substring(0, lStartExtension); } if (lNewMaskPath != rItem.MaskPath) { lIsDirty = true; // Now we can set the mask rItem.MaskPath = lNewMaskPath; // If it was visible or if it is now, we need to apply the mask if (Application.isPlaying && mTarget.UseBodyMasks) { rItem.CreateMask(); mTarget.ApplyBodyMasks(); } } } } EditorGUILayout.EndHorizontal(); bool lNewInstanciateOnStart = EditorGUILayout.Toggle(new GUIContent("Instantiate On Start", "Determines if we create an instance of the object and mask when the game starts."), rItem.InstantiateOnStart); if (lNewInstanciateOnStart != rItem.InstantiateOnStart) { lIsDirty = true; rItem.InstantiateOnStart = lNewInstanciateOnStart; } bool lNewIsVisible = EditorGUILayout.Toggle(new GUIContent("Is Instance Visible", "Determines if the object itself is visible."), rItem.IsVisible); if (lNewIsVisible != rItem.IsVisible) { lIsDirty = true; rItem.IsVisible = lNewIsVisible; } bool lNewIsMaskVisible = EditorGUILayout.Toggle(new GUIContent("Is Mask Visible", "Determines if the body mask is visible."), rItem.IsMaskVisible); if (lNewIsMaskVisible != rItem.IsMaskVisible) { lIsDirty = true; // Now we can set the visability rItem.IsMaskVisible = lNewIsMaskVisible; // If it was visible or if it is now, we need to apply the mask if (Application.isPlaying && mTarget.UseBodyMasks) { mTarget.ApplyBodyMasks(); } } bool lNewUpdateWhenOffScreen = EditorGUILayout.Toggle(new GUIContent("Update Offscreen", "Useful if Unity hides the item at-runtime."), rItem.UpdateWhenOffScreen); if (lNewUpdateWhenOffScreen != rItem.UpdateWhenOffScreen) { lIsDirty = true; rItem.UpdateWhenOffScreen = lNewUpdateWhenOffScreen; } // Object EditorHelper.DrawLine(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Instance:", GUILayout.Width(60)); if (rItem.GameObject == null) { GUILayout.Label("<none>", GUILayout.MinWidth(100)); if (GUILayout.Button(new GUIContent("", "Create instance"), EditorHelper.BlueAddButton, GUILayout.Width(16), GUILayout.Height(16))) { rItem.CreateInstance(mTarget); if (mTarget.UseBodyMasks) { rItem.CreateMask(); mTarget.ApplyBodyMasks(); } } } else { GUILayout.Label(rItem.GameObject.name, GUILayout.MinWidth(100)); if (GUILayout.Button(new GUIContent("", "Select instance"), EditorHelper.BlueSelectButton, GUILayout.Width(16), GUILayout.Height(16))) { Selection.activeGameObject = rItem.GameObject; } if (GUILayout.Button(new GUIContent("", "Delete instance"), EditorHelper.RedXButton, GUILayout.Width(16), GUILayout.Height(16))) { mTarget.RemoveSkinnedItemInstance(rItem); } } GUILayout.Space(2); EditorGUILayout.EndHorizontal(); GUILayout.Space(5); return(lIsDirty); }
/// <summary> /// Called when the inspector needs to draw /// </summary> public override void OnInspectorGUI() { // Pulls variables from runtime so we have the latest values. mTargetSO.Update(); // Clean up the mount points to ensure everything stays in sync PreProcessPoints(); GUILayout.Space(5); EditorHelper.DrawInspectorTitle("ootii Mount List"); EditorHelper.DrawInspectorDescription("Manages multiple mount point and allows for others to connect. Also supports skinned meshes.", MessageType.None); GUILayout.Space(5); float lNewSnapDistance = EditorGUILayout.FloatField(new GUIContent("Snap Distance", "Snap distance for all mount points."), MountPoints.EditorSnapDistance); if (lNewSnapDistance != MountPoints.EditorSnapDistance) { MountPoints.EditorSnapDistance = lNewSnapDistance; } if (!IsAddMountPointEnabled(mTarget)) { GUILayout.Space(5); EditorGUILayout.HelpBox("Unity prevents mount points from being parented directly on the prefab. Instead, add them to a prefab instance and then press 'apply' to update the prefab.", MessageType.Warning); } // Show the points GUILayout.BeginVertical(EditorHelper.GroupBox); mPointList.DoLayoutList(); GUILayout.EndVertical(); if (mPointList.index >= 0) { EditorGUILayout.BeginVertical(EditorHelper.Box); MountPoint lPoint = mTarget.Points[mPointList.index]; bool lItemIsDirty = DrawPointDetailItem(lPoint); if (lItemIsDirty) { mIsDirty = true; } EditorGUILayout.EndVertical(); } GUILayout.Space(5); EditorHelper.DrawLine(); GUILayout.Space(5); SkinnedMeshRenderer lNewRenderer = EditorGUILayout.ObjectField(new GUIContent("Body Skin Renderer", "Skinned Mesh Renderer containing the bones and materials we'll use."), mTarget.Renderer, typeof(SkinnedMeshRenderer), true) as SkinnedMeshRenderer; if (lNewRenderer != mTarget.Renderer) { mIsDirty = true; mTarget.Renderer = lNewRenderer; } bool lNewUseBodyMasks = EditorGUILayout.Toggle(new GUIContent("Use Body Masks", "Processes mask textures to hide parts of the main body."), mTarget.UseBodyMasks); if (lNewUseBodyMasks != mTarget.UseBodyMasks) { mIsDirty = true; mTarget.UseBodyMasks = lNewUseBodyMasks; } if (mTarget.UseBodyMasks) { int lNewBodyMaskIndex = EditorGUILayout.IntField(new GUIContent(" Material Index", "Index of the material that is the skin texture to modify."), mTarget.MaterialIndex); if (lNewBodyMaskIndex != mTarget.MaterialIndex) { mIsDirty = true; mTarget.MaterialIndex = lNewBodyMaskIndex; } EditorHelper.DrawInspectorDescription("Ensure your actor's body material Rendering Mode is set to 'Cutout' or 'Transparency'.", MessageType.None); GUILayout.Space(5); } // Show the skinned items GUILayout.BeginVertical(EditorHelper.GroupBox); mItemList.DoLayoutList(); GUILayout.EndVertical(); if (mItemList.index >= 0) { if (mItemList.index < mTarget.SkinnedItems.Count) { EditorGUILayout.BeginVertical(EditorHelper.Box); SkinnedItem lItem = mTarget.SkinnedItems[mItemList.index]; bool lItemIsDirty = DrawItemDetailItem(lItem); if (lItemIsDirty) { mIsDirty = true; } EditorGUILayout.EndVertical(); } else { mItemList.index = -1; } } GUILayout.Space(5); // If there is a change... update. if (mIsDirty) { // Flag the object as needing to be saved EditorUtility.SetDirty(mTarget); #if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || 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 mTargetSO.ApplyModifiedProperties(); // Clear out the dirty flag mIsDirty = false; } }