From 644c5b843b4f648ae866fab428358c4a68a7f75c Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Tue, 8 Apr 2025 20:55:18 +0200 Subject: [PATCH 1/3] improve and expand new add collision options --- .../SceneGraph/Actors/StaticModelNode.cs | 147 ++++++++++++------ 1 file changed, 99 insertions(+), 48 deletions(-) diff --git a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs index 3bf69d7a2..1e75b905d 100644 --- a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs +++ b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs @@ -28,6 +28,26 @@ namespace FlaxEditor.SceneGraph.Actors private Transform _selectionPointsTransform; private Model _selectionPointsModel; + /// + /// Wether the model of the static model is one of the primitive models. + /// + public bool IsPrimitive + { + get + { + Model model = ((StaticModel)Actor).Model; + + if (!model) + return false; + + string modelPath = model.Path; + return modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal) || + modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal) || + modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal) || + modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal); + } + } + /// public StaticModelNode(Actor actor) : base(actor) @@ -101,12 +121,43 @@ namespace FlaxEditor.SceneGraph.Actors { base.OnContextMenu(contextMenu, window); + // Check that every selected node is a primitive... + var selection = Array.Empty(); + if (window is SceneTreeWindow) + selection = Editor.Instance.SceneEditing.Selection.ToArray(); + else if (window is PrefabWindow prefabWindow) + selection = prefabWindow.Selection.ToArray(); + + bool autoOptionEnabled = true; + foreach (var node in selection) + { + if (node is not StaticModelNode staticModelNode) + continue; + var actor = (StaticModel)staticModelNode.Actor; + var model = ((StaticModel)staticModelNode.Actor).Model; + if (!model) + continue; + if (!staticModelNode.IsPrimitive) + { + autoOptionEnabled = false; + break; + } + } + var menu = contextMenu.AddChildMenu("Add collider"); menu.Enabled = ((StaticModel)Actor).Model != null; - menu.ContextMenu.AddButton("Box", () => OnAddCollider(window, CreateBox)); - menu.ContextMenu.AddButton("Sphere", () => OnAddCollider(window, CreateSphere)); - menu.ContextMenu.AddButton("Convex", () => OnAddCollider(window, CreateConvex)); - menu.ContextMenu.AddButton("Triangle Mesh", () => OnAddCollider(window, CreateTriangle)); + var b = menu.ContextMenu.AddButton("Auto", () => OnAddCollider(window, CreateAuto)); + b.TooltipText = "Add the best fitting collider to every model that uses an in-built Editor primitive."; + // ... and if not, disable the "Auto" option + b.Enabled = autoOptionEnabled; + b = menu.ContextMenu.AddButton("Box", () => OnAddCollider(window, CreateBox)); + b.TooltipText = "Add a box collider to every selected model that will auto resize based on the model bounds."; + b = menu.ContextMenu.AddButton("Sphere", () => OnAddCollider(window, CreateSphere)); + b.TooltipText = "Add a sphere collider to every selected model that will auto resize based on the model bounds."; + b = menu.ContextMenu.AddButton("Convex", () => OnAddCollider(window, CreateConvex)); + b.TooltipText = "Generate and add a convex collider for every selected model."; + b = menu.ContextMenu.AddButton("Triangle Mesh", () => OnAddCollider(window, CreateTriangle)); + b.TooltipText = "Generate and add a triangle mesh collider for every selected model."; } /// @@ -151,6 +202,50 @@ namespace FlaxEditor.SceneGraph.Actors private delegate void Spawner(Collider collider); private delegate void CreateCollider(StaticModel actor, Spawner spawner, bool singleNode); + private void CreateAuto(StaticModel actor, Spawner spawner, bool singleNode) + { + // Special case for in-built Editor models that can use analytical collision + Model model = actor.Model; + var modelPath = model.Path; + if (modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal)) + { + var collider = new BoxCollider + { + Transform = actor.Transform, + }; + spawner(collider); + } + else if (modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal)) + { + var collider = new SphereCollider + { + Transform = actor.Transform, + }; + spawner(collider); + collider.LocalTransform = Transform.Identity; + } + else if (modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal)) + { + spawner(new BoxCollider + { + Transform = actor.Transform, + Size = new Float3(100.0f, 100.0f, 1.0f), + }); + } + else if (modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal)) + { + var collider = new CapsuleCollider + { + Transform = actor.Transform, + Radius = 25.0f, + Height = 50.0f, + }; + spawner(collider); + collider.LocalPosition = new Vector3(0, 50.0f, 0); + collider.LocalOrientation = Quaternion.Euler(0, 0, 90.0f); + } + } + private void CreateBox(StaticModel actor, Spawner spawner, bool singleNode) { var collider = new BoxCollider @@ -227,50 +322,6 @@ namespace FlaxEditor.SceneGraph.Actors createdNodes.Add(colliderNode); }; - // Special case for in-built Editor models that can use analytical collision - var modelPath = model.Path; - if (modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal)) - { - var collider = new BoxCollider - { - Transform = actor.Transform, - }; - spawner(collider); - continue; - } - if (modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal)) - { - var collider = new SphereCollider - { - Transform = actor.Transform, - }; - spawner(collider); - collider.LocalTransform = Transform.Identity; - continue; - } - if (modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal)) - { - spawner(new BoxCollider - { - Transform = actor.Transform, - Size = new Float3(100.0f, 100.0f, 1.0f), - }); - continue; - } - if (modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal)) - { - var collider = new CapsuleCollider - { - Transform = actor.Transform, - Radius = 25.0f, - Height = 50.0f, - }; - spawner(collider); - collider.LocalPosition = new Vector3(0, 50.0f, 0); - collider.LocalOrientation = Quaternion.Euler(0, 0, 90.0f); - continue; - } - createCollider(actor, spawner, selection.Length == 1); } From 06f4808dccafc50051ba2949488d703c05ae3605 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Tue, 8 Apr 2025 21:27:45 +0200 Subject: [PATCH 2/3] improve auto enabled algorithm --- Source/Editor/SceneGraph/Actors/StaticModelNode.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs index 1e75b905d..3143002ba 100644 --- a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs +++ b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs @@ -133,9 +133,7 @@ namespace FlaxEditor.SceneGraph.Actors { if (node is not StaticModelNode staticModelNode) continue; - var actor = (StaticModel)staticModelNode.Actor; - var model = ((StaticModel)staticModelNode.Actor).Model; - if (!model) + if (!((StaticModel)staticModelNode.Actor).Model) continue; if (!staticModelNode.IsPrimitive) { From d351c96a400e7e77cc09731ca181596aa961ef70 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 13 Apr 2025 21:46:04 +0200 Subject: [PATCH 3/3] Cleanup code #3359 --- .../SceneGraph/Actors/StaticModelNode.cs | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs index 3143002ba..a7a3ed9b3 100644 --- a/Source/Editor/SceneGraph/Actors/StaticModelNode.cs +++ b/Source/Editor/SceneGraph/Actors/StaticModelNode.cs @@ -8,6 +8,7 @@ using Real = System.Single; using System; using System.Collections.Generic; +using System.Linq; using FlaxEditor.Content; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.Windows; @@ -29,22 +30,20 @@ namespace FlaxEditor.SceneGraph.Actors private Model _selectionPointsModel; /// - /// Wether the model of the static model is one of the primitive models. + /// Whether the model of the static model is one of the primitive models (box/sphere/capsule/etc.). /// public bool IsPrimitive { get { Model model = ((StaticModel)Actor).Model; - if (!model) return false; - - string modelPath = model.Path; - return modelPath.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal) || - modelPath.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal) || - modelPath.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal) || - modelPath.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal); + string path = model.Path; + return path.EndsWith("/Primitives/Cube.flax", StringComparison.Ordinal) || + path.EndsWith("/Primitives/Sphere.flax", StringComparison.Ordinal) || + path.EndsWith("/Primitives/Plane.flax", StringComparison.Ordinal) || + path.EndsWith("/Primitives/Capsule.flax", StringComparison.Ordinal); } } @@ -121,32 +120,22 @@ namespace FlaxEditor.SceneGraph.Actors { base.OnContextMenu(contextMenu, window); - // Check that every selected node is a primitive... - var selection = Array.Empty(); - if (window is SceneTreeWindow) - selection = Editor.Instance.SceneEditing.Selection.ToArray(); - else if (window is PrefabWindow prefabWindow) - selection = prefabWindow.Selection.ToArray(); - + // Check if every selected node is a primitive + var selection = GetSelection(window); bool autoOptionEnabled = true; foreach (var node in selection) { - if (node is not StaticModelNode staticModelNode) - continue; - if (!((StaticModel)staticModelNode.Actor).Model) - continue; - if (!staticModelNode.IsPrimitive) + if (node is StaticModelNode staticModelNode && !staticModelNode.IsPrimitive) { autoOptionEnabled = false; break; } - } + } var menu = contextMenu.AddChildMenu("Add collider"); menu.Enabled = ((StaticModel)Actor).Model != null; var b = menu.ContextMenu.AddButton("Auto", () => OnAddCollider(window, CreateAuto)); b.TooltipText = "Add the best fitting collider to every model that uses an in-built Editor primitive."; - // ... and if not, disable the "Auto" option b.Enabled = autoOptionEnabled; b = menu.ContextMenu.AddButton("Box", () => OnAddCollider(window, CreateBox)); b.TooltipText = "Add a box collider to every selected model that will auto resize based on the model bounds."; @@ -166,8 +155,8 @@ namespace FlaxEditor.SceneGraph.Actors // Try to use cache var model = sm.Model; var transform = Actor.Transform; - if (_selectionPoints != null && - _selectionPointsTransform == transform && + if (_selectionPoints != null && + _selectionPointsTransform == transform && _selectionPointsModel == model) return _selectionPoints; Profiler.BeginEvent("GetActorSelectionPoints"); @@ -198,8 +187,18 @@ namespace FlaxEditor.SceneGraph.Actors } private delegate void Spawner(Collider collider); + private delegate void CreateCollider(StaticModel actor, Spawner spawner, bool singleNode); + private IEnumerable GetSelection(EditorWindow window) + { + if (window is SceneTreeWindow) + return Editor.Instance.SceneEditing.Selection; + if (window is PrefabWindow prefabWindow) + return prefabWindow.Selection; + return Array.Empty(); + } + private void CreateAuto(StaticModel actor, Spawner spawner, bool singleNode) { // Special case for in-built Editor models that can use analytical collision @@ -296,13 +295,8 @@ namespace FlaxEditor.SceneGraph.Actors private void OnAddCollider(EditorWindow window, CreateCollider createCollider) { - // Allow collider to be added to evey static model selection - var selection = Array.Empty(); - if (window is SceneTreeWindow) - selection = Editor.Instance.SceneEditing.Selection.ToArray(); - else if (window is PrefabWindow prefabWindow) - selection = prefabWindow.Selection.ToArray(); - + // Allow collider to be added to every static model selection + var selection = GetSelection(window).ToArray(); var createdNodes = new List(); foreach (var node in selection) {