using UnityEngine; using System.Linq; using System.Collections.Generic; using UnityEngine.ProBuilder; using UnityEngine.ProBuilder.MeshOperations; namespace UnityEditor.ProBuilder.Actions { sealed class ProBuilderize : MenuAction { bool m_Enabled; Pref m_Quads = new Pref("meshImporter.quads", true); Pref m_Smoothing = new Pref("meshImporter.smoothing", true); Pref m_SmoothingAngle = new Pref("meshImporter.smoothingAngle", 1f); public ProBuilderize() { MeshSelection.objectSelectionChanged += OnObjectSelectionChanged; OnObjectSelectionChanged(); // invoke once as we might already have a selection in Hierarchy } private void OnObjectSelectionChanged() { // can't just check if any MeshFilter is present because we need to know whether or not it's already a // probuilder mesh int meshCount = Selection.transforms.SelectMany(x => x.GetComponentsInChildren()).Count(); m_Enabled = meshCount > 0 && meshCount != MeshSelection.selectedObjectCount; } public override ToolbarGroup group { get { return ToolbarGroup.Object; } } public override Texture2D icon { get { return IconUtility.GetIcon("Toolbar/Object_ProBuilderize", IconSkin.Pro); } } public override TooltipContent tooltip { get { return s_Tooltip; } } GUIContent m_QuadsTooltip = new GUIContent("Import Quads", "Create ProBuilder mesh using quads where " + "possible instead of triangles."); GUIContent m_SmoothingTooltip = new GUIContent("Import Smoothing", "Import smoothing groups by " + "testing adjacent faces against an angle threshold."); GUIContent m_SmoothingThresholdTooltip = new GUIContent("Smoothing Threshold", "When importing " + "smoothing groups any adjacent faces with an adjoining angle difference of less than this value will be " + "grouped together in a smoothing group."); private static readonly TooltipContent s_Tooltip = new TooltipContent ( "ProBuilderize", @"Creates ProBuilder-modifiable objects from meshes." ); public override bool enabled { get { return base.enabled && m_Enabled; } } protected override MenuActionState optionsMenuState { get { return MenuActionState.VisibleAndEnabled; } } protected override void OnSettingsGUI() { GUILayout.Label("ProBuilderize Options", EditorStyles.boldLabel); EditorGUILayout.HelpBox("When Preserve Faces is enabled ProBuilder will try to group adjacent triangles into faces.", MessageType.Info); EditorGUI.BeginChangeCheck(); m_Quads.value = EditorGUILayout.Toggle(m_QuadsTooltip, m_Quads); m_Smoothing.value = EditorGUILayout.Toggle(m_SmoothingTooltip, m_Smoothing); GUI.enabled = m_Smoothing; EditorGUILayout.PrefixLabel(m_SmoothingThresholdTooltip); m_SmoothingAngle.value = EditorGUILayout.Slider(m_SmoothingAngle, 0.0001f, 45f); GUI.enabled = true; if (EditorGUI.EndChangeCheck()) ProBuilderSettings.Save(); GUILayout.FlexibleSpace(); GUI.enabled = enabled; if (GUILayout.Button("ProBuilderize")) EditorUtility.ShowNotification(PerformAction().notification); GUI.enabled = true; } protected override ActionResult PerformActionImplementation() { IEnumerable top = Selection.transforms.Select(x => x.GetComponent()).Where(y => y != null); IEnumerable all = Selection.gameObjects.SelectMany(x => x.GetComponentsInChildren()).Where(x => x != null); MeshImportSettings settings = new MeshImportSettings() { quads = m_Quads, smoothing = m_Smoothing, smoothingAngle = m_SmoothingAngle }; if (top.Count() != all.Count()) { int result = UnityEditor.EditorUtility.DisplayDialogComplex("ProBuilderize Selection", "ProBuilderize children of selection?", "Yes", "No", "Cancel"); if (result == 0) return DoProBuilderize(all, settings); else if (result == 1) return DoProBuilderize(top, settings); else return ActionResult.UserCanceled; } return DoProBuilderize(all, settings); } [System.Obsolete("Please use DoProBuilderize(IEnumerable, pb_MeshImporter.Settings")] public static ActionResult DoProBuilderize( IEnumerable selected, bool preserveFaces) { return DoProBuilderize(selected, new MeshImportSettings() { quads = preserveFaces, smoothing = false, smoothingAngle = 1f }); } /// /// Adds pb_Object component without duplicating the objcet. Is undo-able. /// /// /// /// public static ActionResult DoProBuilderize( IEnumerable selected, MeshImportSettings settings) { int i = 0; float count = selected.Count(); // Return immediately from the action so that the GUI can resolve. Displaying a progress bar interrupts the // event loop causing a layoutting error. EditorApplication.delayCall += () => { foreach (var mf in selected) { if (mf.sharedMesh == null) continue; GameObject go = mf.gameObject; Mesh sourceMesh = mf.sharedMesh; Material[] sourceMaterials = go.GetComponent()?.sharedMaterials; try { var destination = Undo.AddComponent(go); var meshImporter = new MeshImporter(sourceMesh, sourceMaterials, destination); meshImporter.Import(settings); destination.Rebuild(); destination.Optimize(); i++; } catch (System.Exception e) { Debug.LogWarning("Failed ProBuilderizing: " + go.name + "\n" + e.ToString()); } UnityEditor.EditorUtility.DisplayProgressBar("ProBuilderizing", mf.gameObject.name, i / count); } UnityEditor.EditorUtility.ClearProgressBar(); MeshSelection.OnObjectSelectionChanged(); ProBuilderEditor.Refresh(); }; if (i < 1) return new ActionResult(ActionResult.Status.Canceled, "Nothing Selected"); return new ActionResult(ActionResult.Status.Success, "ProBuilderize " + i + (i > 1 ? " Objects" : " Object").ToString()); } } }