Added player character and step in/out of dialogue in scene 101

This commit is contained in:
2026-08-15 15:22:47 +02:00
parent a42f25d5fa
commit 38ba2b0eff
2019 changed files with 181227 additions and 265 deletions
@@ -0,0 +1,61 @@
using UnityEngine.ProBuilder;
using UnityEngine;
using UnityEngine.ProBuilder.MeshOperations;
namespace UnityEditor.ProBuilder.Actions
{
sealed class CenterPivot : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Pivot_CenterOnObject";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Center Pivot",
@"Set the pivot point of this object to the center of its bounds."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 1)
return ActionResult.NoSelection;
Object[] objects = new Object[MeshSelection.selectedObjectCount * 2];
for (int i = 0, c = MeshSelection.selectedObjectCount; i < c; i++)
{
objects[i] = MeshSelection.topInternal[i];
objects[i + c] = MeshSelection.topInternal[i].transform;
}
UndoUtility.RegisterCompleteObjectUndo(objects, "Center Pivot");
foreach (var mesh in MeshSelection.topInternal)
{
TransformUtility.UnparentChildren(mesh.transform);
mesh.CenterPivot(null);
mesh.Optimize();
TransformUtility.ReparentChildren(mesh.transform);
}
ProBuilderEditor.Refresh();
return new ActionResult(ActionResult.Status.Success, "Center Pivot");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 460d1e5b4c054bfc8d012b87f9960bb9
timeCreated: 1461861662
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
using UnityEngine.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class ConformObjectNormals : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_ConformNormals";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
public override string menuTitle
{
get { return "Conform Normals"; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Conform Object Normals",
@"Check the object for faces that are flipped in the opposite direction of most other faces, then reverses any dissenters."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
UndoUtility.RecordSelection("Conform Object Normals");
ActionResult res = ActionResult.NoSelection;
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
{
res = UnityEngine.ProBuilder.MeshOperations.SurfaceTopology.ConformNormals(pb, pb.faces);
pb.ToMesh();
pb.Refresh();
pb.Optimize();
}
ProBuilderEditor.Refresh();
return res;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 916d519062254e79b6adc87200d2c142
timeCreated: 1457563051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
using UnityEngine.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class FlipObjectNormals : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_FlipNormals";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
public override string menuTitle
{
get { return "Flip Normals"; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Flip Object Normals",
@"Reverse the direction of all faces on the selected objects."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 1)
return ActionResult.NoSelection;
UndoUtility.RecordSelection("Flip Object Normals");
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
{
foreach (var face in pb.facesInternal)
face.Reverse();
pb.ToMesh();
pb.Refresh();
pb.Optimize();
}
ProBuilderEditor.Refresh();
return new ActionResult(ActionResult.Status.Success, "Flip Object Normals");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: add8532bafe747b88ea53556bd2e74e8
timeCreated: 1457563051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using UnityEngine.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class FreezeTransform : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Pivot_FreezeTransform";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Freeze Transform",
@"Set the pivot point to world coordinates (0,0,0) and clear all Transform values while keeping the mesh in place."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
public bool ShouldFlipFaces(Vector3 scale)
{
var globalSign = Mathf.Sign(scale.x) * Mathf.Sign(scale.y) * Mathf.Sign(scale.z);
return globalSign < 0;
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 1)
return ActionResult.NoSelection;
UndoUtility.RecordMeshAndTransformSelection("Freeze Transforms");
var selection = MeshSelection.topInternal;
Vector3[][] positions = new Vector3[selection.Count][];
for (int i = 0, c = selection.Count; i < c; i++)
positions[i] = selection[i].VerticesInWorldSpace();
for (int i = 0, c = selection.Count; i < c; i++)
{
ProBuilderMesh pb = selection[i];
bool flipFaces = ShouldFlipFaces(pb.transform.localScale);
pb.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
pb.transform.localScale = Vector3.one;
foreach(Face face in pb.facesInternal)
{
face.manualUV = true;
if(flipFaces)
face.Reverse();
}
pb.positions = positions[i];
pb.ToMesh();
pb.Refresh();
pb.Optimize();
}
ProBuilderEditor.Refresh();
SceneView.RepaintAll();
return new ActionResult(ActionResult.Status.Success, "Freeze Transforms");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cc6c734d87394ef99cf62171eb6fe416
timeCreated: 1457563050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,57 @@
using UnityEngine.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class GenerateUV2 : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_GenerateUV2";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
protected internal override bool hasFileMenuEntry
{
get { return false; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Lightmap UVs",
@"Generate Lightmap UVs for any meshes in the open scenes that are missing them."
);
public override bool enabled
{
get { return true; }
}
protected override MenuActionState optionsMenuState
{
get { return MenuActionState.VisibleAndEnabled; }
}
protected override ActionResult PerformActionImplementation()
{
var res = Lightmapping.RebuildMissingLightmapUVs(EditorUtility.FindObjectsByType<ProBuilderMesh>(), true);
if (res < 1)
return new ActionResult(ActionResult.Status.Success, "No Missing Lightmap UVs Found");
return new ActionResult(ActionResult.Status.Success, "Generate Lightmap UVs\n" +
(res > 1 ? string.Format("for {0} objects", res) : "for 1 object"));
}
protected override void DoAlternateAction()
{
EditorWindow.GetWindow<LightmapUVEditor>(true, "Lightmap UV Editor", true).position = LightmapUVEditor.desiredPosition;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 752d48e9eaa76c54ba0ff161eff2a3f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,89 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine.ProBuilder;
using UnityEditor.ProBuilder;
using UnityEngine;
using UnityEditor;
using UnityEditor.ProBuilder.UI;
using UnityEngine.ProBuilder.MeshOperations;
using UnityEngine.ProBuilder.Shapes;
namespace UnityEditor.ProBuilder.Actions
{
sealed class MergeObjects : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_Merge";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Merge Objects",
@"Merges all selected ProBuilder objects to a single mesh."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 1 && MeshSelection.activeMesh != null; }
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 2)
return new ActionResult(ActionResult.Status.Canceled, "Must Select 2+ Objects");
DoMergeObjectsAction();
return new ActionResult(ActionResult.Status.Success, "Merged Objects");
}
internal List<ProBuilderMesh> DoMergeObjectsAction()
{
var selected = MeshSelection.top.ToArray();
ProBuilderMesh currentMesh = MeshSelection.activeMesh;
UndoUtility.RecordObject(currentMesh, "Merge Objects");
List<ProBuilderMesh> res = CombineMeshes.Combine(MeshSelection.topInternal, currentMesh);
if (res != null)
{
foreach (var mesh in res)
{
mesh.Optimize();
if (mesh != currentMesh)
{
mesh.gameObject.name = Selection.activeGameObject.name + "-Merged";
UndoUtility.RegisterCreatedObjectUndo(mesh.gameObject, "Merge Objects");
Selection.objects = res.Select(x => x.gameObject).ToArray();
}
// Remove PolyShape and ProBuilderShape components if any are present post-merge
var polyShapeComp = mesh.gameObject.GetComponent<PolyShape>();
if (polyShapeComp != null )
UndoUtility.DestroyImmediate(polyShapeComp);
var proBuilderShape = mesh.gameObject.GetComponent<ProBuilderShape>();
if (proBuilderShape != null )
UndoUtility.DestroyImmediate(proBuilderShape);
}
// Delete donor objects if they are not part of the result
for (int i = 0; i < selected.Length; i++)
{
if (selected[i] != null && res.Contains(selected[i]) == false)
UndoUtility.DestroyImmediate(selected[i].gameObject);
}
}
return res;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ffab696c539c4041848596918dd4590f
timeCreated: 1457563050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.ProBuilder;
using UnityEngine.ProBuilder.MeshOperations;
using Object = UnityEngine.Object;
namespace UnityEditor.ProBuilder.Actions
{
sealed class MirrorObjects : MenuAction
{
Pref<MirrorSettings> m_MirrorAxes = new Pref<MirrorSettings>("MirrorObjects.mirrorAxes", MirrorSettings.X);
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_Mirror";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
[System.Flags]
enum MirrorSettings
{
X = 0x1,
Y = 0x2,
Z = 0x4,
Duplicate = 0x8
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Mirror Objects",
@"Mirroring objects will duplicate and flip objects on the specified axes."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override MenuActionState optionsMenuState
{
get { return MenuActionState.VisibleAndEnabled; }
}
public override VisualElement CreateSettingsContent()
{
var root = new VisualElement();
MirrorSettings scale = m_MirrorAxes;
bool x = (scale & MirrorSettings.X) != 0;
bool y = (scale & MirrorSettings.Y) != 0;
bool z = (scale & MirrorSettings.Z) != 0;
bool d = (scale & MirrorSettings.Duplicate) != 0;
var tooltip = "Mirror objects on the selected axes";
var toggle = new Toggle("X");
toggle.tooltip = tooltip;
toggle.SetValueWithoutNotify(x);
toggle.RegisterValueChangedCallback(evt =>
{
m_MirrorAxes.SetValue((evt.newValue ? MirrorSettings.X : 0) | m_MirrorAxes & MirrorSettings.Y | m_MirrorAxes & MirrorSettings.Z | m_MirrorAxes & MirrorSettings.Duplicate);
PreviewActionManager.UpdatePreview();
});
root.Add(toggle);
toggle = new Toggle("Y");
toggle.tooltip = tooltip;
toggle.SetValueWithoutNotify(y);
toggle.RegisterValueChangedCallback(evt =>
{
m_MirrorAxes.SetValue(m_MirrorAxes & MirrorSettings.X | (evt.newValue ? MirrorSettings.Y : 0) | m_MirrorAxes & MirrorSettings.Z | m_MirrorAxes & MirrorSettings.Duplicate);
PreviewActionManager.UpdatePreview();
});
root.Add(toggle);
toggle = new Toggle("Z");
toggle.tooltip = tooltip;
toggle.SetValueWithoutNotify(z);
toggle.RegisterValueChangedCallback(evt =>
{
m_MirrorAxes.SetValue(m_MirrorAxes & MirrorSettings.X | m_MirrorAxes & MirrorSettings.Y | (evt.newValue ? MirrorSettings.Z : 0) | m_MirrorAxes & MirrorSettings.Duplicate);
PreviewActionManager.UpdatePreview();
});
root.Add(toggle);
toggle = new Toggle("Duplicate");
toggle.tooltip = "If Duplicate is toggled a new object will be instantiated from the selection and mirrored, or if disabled the selection will be moved.";
toggle.SetValueWithoutNotify(d);
toggle.RegisterValueChangedCallback(evt =>
{
m_MirrorAxes.SetValue(m_MirrorAxes & MirrorSettings.X | m_MirrorAxes & MirrorSettings.Y | m_MirrorAxes & MirrorSettings.Z | (evt.newValue ? MirrorSettings.Duplicate : 0));
PreviewActionManager.UpdatePreview();
});
root.Add(toggle);
return root;
}
protected override void OnSettingsGUI()
{
GUILayout.Label("Mirror Settings", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("Mirror objects on the selected axes.\n\nIf Duplicate is toggled a new object will be instantiated from the selection and mirrored, or if disabled the selection will be moved.", MessageType.Info);
MirrorSettings scale = m_MirrorAxes;
bool x = (scale & MirrorSettings.X) != 0;
bool y = (scale & MirrorSettings.Y) != 0;
bool z = (scale & MirrorSettings.Z) != 0;
bool d = (scale & MirrorSettings.Duplicate) != 0;
EditorGUI.BeginChangeCheck();
x = EditorGUILayout.Toggle("X", x);
y = EditorGUILayout.Toggle("Y", y);
z = EditorGUILayout.Toggle("Z", z);
d = EditorGUILayout.Toggle("Duplicate", d);
if (EditorGUI.EndChangeCheck())
m_MirrorAxes.SetValue((MirrorSettings)
(x ? MirrorSettings.X : 0) |
(y ? MirrorSettings.Y : 0) |
(z ? MirrorSettings.Z : 0) |
(d ? MirrorSettings.Duplicate : 0));
GUILayout.FlexibleSpace();
if (GUILayout.Button("Mirror"))
EditorUtility.ShowNotification(PerformAction().notification);
}
protected override ActionResult PerformActionImplementation()
{
Vector3 scale = new Vector3(
(m_MirrorAxes & MirrorSettings.X) > 0 ? -1f : 1f,
(m_MirrorAxes & MirrorSettings.Y) > 0 ? -1f : 1f,
(m_MirrorAxes & MirrorSettings.Z) > 0 ? -1f : 1f);
bool duplicate = (m_MirrorAxes & MirrorSettings.Duplicate) != 0;
List<GameObject> res = new List<GameObject>();
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
res.Add(Mirror(pb, scale, duplicate).gameObject);
MeshSelection.SetSelection(res);
PreviewActionManager.selectionUpdateDisabled = true;
ProBuilderEditor.Refresh();
return res.Count > 0 ?
new ActionResult(ActionResult.Status.Success, string.Format("Mirror {0} {1}", res.Count, res.Count > 1 ? "Objects" : "Object")) :
new ActionResult(ActionResult.Status.NoChange, "No Objects Selected");
}
/**
* \brief Duplicates and mirrors the passed pb_Object.
* @param pb The donor pb_Object.
* @param axe The axis to mirror the object on.
* \returns The newly duplicated pb_Object.
* \sa ProBuilder.Axis
*/
public static ProBuilderMesh Mirror(ProBuilderMesh pb, Vector3 scale, bool duplicate = true)
{
ProBuilderMesh mirroredObject;
if (duplicate)
{
mirroredObject = Object.Instantiate(pb.gameObject, pb.transform.parent, false).GetComponent<ProBuilderMesh>();
mirroredObject.MakeUnique();
mirroredObject.transform.parent = pb.transform.parent;
mirroredObject.transform.localRotation = pb.transform.localRotation;
Undo.RegisterCreatedObjectUndo(mirroredObject.gameObject, "Mirror Object");
}
else
{
UndoUtility.RecordObject(pb, "Mirror");
mirroredObject = pb;
}
Vector3 lScale = mirroredObject.gameObject.transform.localScale;
mirroredObject.transform.localScale = scale;
// if flipping on an odd number of axes, flip winding order
if ((scale.x * scale.y * scale.z) < 0)
{
foreach (var face in mirroredObject.facesInternal)
face.Reverse();
}
mirroredObject.FreezeScaleTransform();
mirroredObject.transform.localScale = lScale;
mirroredObject.ToMesh();
mirroredObject.Refresh();
mirroredObject.Optimize();
return mirroredObject;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5cf10ee5e4b44eaca6e769bf235f7f5a
timeCreated: 1470064051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,294 @@
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
using UnityEngine.ProBuilder;
using UnityEngine.ProBuilder.MeshOperations;
using UnityEditor.Actions;
using UnityEngine.UIElements;
namespace UnityEditor.ProBuilder.Actions
{
sealed class ProBuilderize : MenuAction
{
bool m_Enabled;
Pref<bool> m_Quads = new Pref<bool>("meshImporter.quads", true);
Pref<bool> m_Smoothing = new Pref<bool>("meshImporter.smoothing", true);
Pref<float> m_SmoothingAngle = new Pref<float>("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<MeshFilter>()).Count();
m_Enabled = meshCount > 0 && meshCount != MeshSelection.selectedObjectCount;
}
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_ProBuilderize";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
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; }
}
// This boolean allows to call the action only once in case of multi-selection as PB actions
// are called on the entire selection and not per element.
static bool s_ActionAlreadyTriggered = false;
[InitializeOnEnterPlayMode]
static void ResetStaticsOnLoad()
{
s_ActionAlreadyTriggered = false;
}
[MenuItem("CONTEXT/MeshFilter/ProBuilderize", true, 11)]
static bool ProBuilderizeMeshAction_Validate(MenuCommand command)
{
return !MenuActionSettings.IsCurrentAction(new ProBuilderize());
}
[MenuItem("CONTEXT/MeshFilter/ProBuilderize", false, 11)]
static void ProBuilderizeMeshAction(MenuCommand command)
{
if (!s_ActionAlreadyTriggered)
{
var filter = (MeshFilter)command.context;
//Check if we are not trying to Probuilderize a PB mesh
if (filter.GetComponent<ProBuilderMesh>() != null)
return;
s_ActionAlreadyTriggered = true;
//Once again, delayCall is necessary to prevent multiple call in case of multi-selection
EditorApplication.delayCall += () =>
{
EditorAction.Start(new MenuActionSettings(new ProBuilderize()));
s_ActionAlreadyTriggered = false;
};
}
}
public override VisualElement CreateSettingsContent()
{
var root = new VisualElement();
var quadsToggle = new Toggle(m_QuadsTooltip.text);
quadsToggle.tooltip = m_QuadsTooltip.tooltip;
quadsToggle.SetValueWithoutNotify(m_Quads);
root.Add(quadsToggle);
var smoothingToggle = new Toggle(m_SmoothingTooltip.text);
smoothingToggle.tooltip = m_SmoothingTooltip.tooltip;
smoothingToggle.SetValueWithoutNotify(m_Smoothing);
root.Add(smoothingToggle);
var line = new VisualElement();
line.style.flexDirection = FlexDirection.Row;
root.Add(line);
var smoothingSlider = new Slider(m_SmoothingThresholdTooltip.text, 0.0001f, 45f);
smoothingSlider.tooltip = m_SmoothingThresholdTooltip.tooltip;
smoothingSlider.SetValueWithoutNotify(m_SmoothingAngle);
smoothingSlider.style.flexGrow = 1;
smoothingSlider.SetEnabled(m_Smoothing);
line.Add(smoothingSlider);
var smoothingSliderValue = new FloatField();
smoothingSliderValue.SetValueWithoutNotify(m_SmoothingAngle);
smoothingSliderValue.isDelayed = true;
smoothingSliderValue.style.width = 50;
line.Add(smoothingSliderValue);
quadsToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
m_Quads.SetValue(evt.newValue);
});
smoothingToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
m_Smoothing.SetValue(evt.newValue);
smoothingSlider.SetEnabled(m_Smoothing);
});
smoothingSlider.RegisterCallback<ChangeEvent<float>>(evt =>
{
m_SmoothingAngle.SetValue(evt.newValue);
smoothingSliderValue.SetValueWithoutNotify(m_SmoothingAngle);
});
smoothingSliderValue.RegisterCallback<ChangeEvent<float>>(evt =>
{
m_SmoothingAngle.SetValue(evt.newValue);
smoothingSlider.SetValueWithoutNotify(m_SmoothingAngle);
});
return root;
}
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<MeshFilter> top = Selection.transforms.Select(x => x.GetComponent<MeshFilter>()).Where(y => y != null);
IEnumerable<MeshFilter> all = Selection.gameObjects.SelectMany(x => x.GetComponentsInChildren<MeshFilter>()).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<MeshFilter>, pb_MeshImporter.Settings")]
public static ActionResult DoProBuilderize(
IEnumerable<MeshFilter> selected,
bool preserveFaces)
{
return DoProBuilderize(selected, new MeshImportSettings()
{
quads = preserveFaces,
smoothing = false,
smoothingAngle = 1f
});
}
/// <summary>
/// Adds pb_Object component without duplicating the objcet. Is undo-able.
/// </summary>
/// <param name="selected"></param>
/// <param name="settings"></param>
/// <returns></returns>
public static ActionResult DoProBuilderize(
IEnumerable<MeshFilter> 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;
var renderer = go.GetComponent<MeshRenderer>();
if (renderer.isPartOfStaticBatch)
{
Debug.LogError($"Probuilderize is not supported for renderers that have `IsPartOfStaticBatch` set.\n{go.name} will not probuilderize.");
continue;
}
Mesh sourceMesh = mf.sharedMesh;
Material[] sourceMaterials = go.GetComponent<MeshRenderer>()?.sharedMaterials;
try
{
var destination = Undo.AddComponent<ProBuilderMesh>(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());
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d0b5cffbc2ad41cb84067b39dedada94
timeCreated: 1471369223
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,65 @@
using UnityEngine.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class SetCollider : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Entity; }
}
public override string iconPath => string.Empty;
public override Texture2D icon => null;
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Set Collider",
"Apply the Collider material and adds a mesh collider (if no collider is present). The MeshRenderer will be automatically turned off on entering play mode."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
{
var existing = pb.GetComponents<EntityBehaviour>();
// For now just nuke any existing entity types (since there are only two). In the future we should be
// smarter about conflicting entity types.
for (int i = 0, c = existing.Length; i < c; i++)
Undo.DestroyObjectImmediate(existing[i]);
if (pb.TryGetComponent<Entity>(out var entity))
Undo.DestroyObjectImmediate(entity);
if (!pb.GetComponent<Collider>())
Undo.AddComponent<MeshCollider>(pb.gameObject);
if (!pb.GetComponent<Renderer>())
Undo.AddComponent<MeshRenderer>(pb.gameObject);
UndoUtility.RegisterCompleteObjectUndo(pb, "Set Collider");
Undo.AddComponent<ColliderBehaviour>(pb.gameObject).Initialize();
}
int selectionCount = MeshSelection.selectedObjectCount;
if (selectionCount < 1)
return new ActionResult(ActionResult.Status.NoChange, "Set Collider\nNo objects selected");
return new ActionResult(ActionResult.Status.Success, "Set Collider\nSet " + selectionCount + " Objects");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1376ed33245911e48ab91c560798f510
timeCreated: 1457563050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,66 @@
using System;
using UnityEngine.ProBuilder;
using UnityEditor.ProBuilder;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class SetTrigger : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Entity; }
}
public override string iconPath => string.Empty;
public override Texture2D icon => null;
public override TooltipContent tooltip
{
get { return _tooltip; }
}
static readonly TooltipContent _tooltip = new TooltipContent
(
"Set Trigger",
"Apply the Trigger material and adds a collider marked as a trigger. The MeshRenderer will be automatically turned off on entering play mode."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
{
var existing = pb.GetComponents<EntityBehaviour>();
// For now just nuke any existing entity types (since there are only two). In the future we should be
// smarter about conflicting entity types.
for (int i = 0, c = existing.Length; i < c; i++)
Undo.DestroyObjectImmediate(existing[i]);
if (pb.TryGetComponent<Entity>(out var entity))
Undo.DestroyObjectImmediate(entity);
if (!pb.GetComponent<Collider>())
Undo.AddComponent<MeshCollider>(pb.gameObject);
if (!pb.GetComponent<Renderer>())
Undo.AddComponent<MeshRenderer>(pb.gameObject);
UndoUtility.RegisterCompleteObjectUndo(pb, "Set Trigger");
Undo.AddComponent<TriggerBehaviour>(pb.gameObject).Initialize();
}
int selectionCount = MeshSelection.selectedObjectCount;
if (selectionCount < 1)
return new ActionResult(ActionResult.Status.NoChange, "Set Trigger\nNo objects selected");
return new ActionResult(ActionResult.Status.Success, "Set Trigger\nSet " + selectionCount + " Objects");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4ce00895d9eb2924f8f0c484eb3879ce
timeCreated: 1457563050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,60 @@
using UnityEngine.ProBuilder;
using UnityEngine.ProBuilder.MeshOperations;
using UnityEngine;
namespace UnityEditor.ProBuilder.Actions
{
sealed class SubdivideObject : MenuAction
{
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override string iconPath => "Toolbar/Object_Subdivide";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Subdivide Object",
"Increase the number of edges and vertices on this object by creating 4 new quads in every face."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 1)
return ActionResult.NoSelection;
UndoUtility.RecordSelection("Subdivide Selection");
int success = 0;
foreach (ProBuilderMesh pb in MeshSelection.topInternal)
{
pb.ToMesh();
if (pb.Subdivide())
success++;
else
Debug.LogError($"Subidivision of [{pb.name}] failed, complex concave objects are not supported");
pb.Refresh();
pb.Optimize();
pb.SetSelectedVertices(new int[0]);
}
ProBuilderEditor.Refresh();
return new ActionResult(ActionResult.Status.Success, "Subdivide " + success + " Objects");
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a6f7622c6d6346cca3539de7b00556a7
timeCreated: 1457563050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using UnityEngine.ProBuilder;
using UnityEngine;
using UnityEngine.ProBuilder.MeshOperations;
namespace UnityEditor.ProBuilder.Actions
{
sealed class TriangulateObject : MenuAction
{
public override ToolbarGroup group { get { return ToolbarGroup.Object; } }
public override string iconPath => "Toolbar/Object_Triangulate";
public override Texture2D icon => IconUtility.GetIcon(iconPath);
public override TooltipContent tooltip { get { return s_Tooltip; } }
public override string menuTitle { get { return "Triangulate"; } }
static readonly TooltipContent s_Tooltip = new TooltipContent
(
"Triangulate Objects",
@"Removes all quads and n-gons on the mesh and inserts triangles instead. Use this and a hard smoothing group to achieve a low-poly facetized look."
);
public override bool enabled
{
get { return base.enabled && MeshSelection.selectedObjectCount > 0; }
}
protected override ActionResult PerformActionImplementation()
{
if (MeshSelection.selectedObjectCount < 1)
return ActionResult.NoSelection;
UndoUtility.RecordSelection("Triangulate Objects");
foreach (var mesh in MeshSelection.topInternal)
{
mesh.ToMesh();
mesh.ToTriangles(mesh.facesInternal);
mesh.Refresh();
mesh.Optimize();
mesh.ClearSelection();
}
ProBuilderEditor.Refresh();
var c = MeshSelection.selectedObjectCount;
return new ActionResult(ActionResult.Status.Success, "Triangulate " + c + (c > 1 ? " Objects" : " Object"));
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b3983d7c6b954ee69e23e75009a8b81d
timeCreated: 1457563051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: