Optimize ViewportRubberBandSelector

#3151
This commit is contained in:
Wojtek Figat
2025-03-11 13:05:15 +01:00
parent 273b366f44
commit a54299a560
7 changed files with 208 additions and 122 deletions

View File

@@ -188,25 +188,28 @@ namespace FlaxEditor.SceneGraph
/// <returns>An array of ActorNodes</returns>
public ActorNode[] GetAllChildActorNodes()
{
// Check itself
if (ChildNodes == null || ChildNodes.Count == 0)
return [];
// Check deeper
var nodes = new List<ActorNode>();
for (int i = 0; i < ChildNodes.Count; i++)
GetAllChildActorNodes(nodes);
return nodes.ToArray();
}
/// <summary>
/// Get all nested actor nodes under this actor node.
/// </summary>
/// <param name="nodes">The output list to fill with results.</param>
public void GetAllChildActorNodes(List<ActorNode> nodes)
{
var children = ChildNodes;
if (children == null)
return;
for (int i = 0; i < children.Count; i++)
{
if (ChildNodes[i] is ActorNode node)
if (children[i] is ActorNode node)
{
nodes.Add(node);
var childNodes = node.GetAllChildActorNodes();
if (childNodes.Length > 0)
{
nodes.AddRange(childNodes);
}
node.GetAllChildActorNodes(nodes);
}
}
return nodes.ToArray();
}
/// <summary>

View File

@@ -24,6 +24,9 @@ namespace FlaxEditor.SceneGraph.Actors
public sealed class StaticModelNode : ActorNode
{
private Dictionary<IntPtr, Mesh.Vertex[]> _vertices;
private Vector3[] _selectionPoints;
private Transform _selectionPointsTransform;
private Model _selectionPointsModel;
/// <inheritdoc />
public StaticModelNode(Actor actor)
@@ -31,6 +34,16 @@ namespace FlaxEditor.SceneGraph.Actors
{
}
/// <inheritdoc />
public override void OnDispose()
{
_vertices = null;
_selectionPoints = null;
_selectionPointsModel = null;
base.OnDispose();
}
/// <inheritdoc />
public override bool OnVertexSnap(ref Ray ray, Real hitDistance, out Vector3 result)
{
@@ -91,25 +104,40 @@ namespace FlaxEditor.SceneGraph.Actors
/// <inheritdoc />
public override Vector3[] GetActorSelectionPoints()
{
if (Actor is not StaticModel sm || !sm.Model)
return base.GetActorSelectionPoints();
// Check collision proxy points for more accurate selection.
var vecPoints = new List<Vector3>();
var m = sm.Model.LODs[0];
foreach (var mesh in m.Meshes)
if (Actor is StaticModel sm && sm.Model)
{
var points = mesh.GetCollisionProxyPoints();
foreach (var point in points)
// Try to use cache
var model = sm.Model;
var transform = Actor.Transform;
if (_selectionPoints != null &&
_selectionPointsTransform == transform &&
_selectionPointsModel == model)
return _selectionPoints;
Profiler.BeginEvent("GetActorSelectionPoints");
// Check collision proxy points for more accurate selection
var vecPoints = new List<Vector3>();
var m = model.LODs[0];
foreach (var mesh in m.Meshes)
{
vecPoints.Add(Actor.Transform.LocalToWorld(point));
var points = mesh.GetCollisionProxyPoints();
vecPoints.EnsureCapacity(vecPoints.Count + points.Length);
for (int i = 0; i < points.Length; i++)
{
vecPoints.Add(transform.LocalToWorld(points[i]));
}
}
Profiler.EndEvent();
if (vecPoints.Count != 0)
{
_selectionPoints = vecPoints.ToArray();
_selectionPointsTransform = transform;
_selectionPointsModel = model;
return _selectionPoints;
}
}
// Fall back to base actor editor box if no points from collision proxy.
if (vecPoints.Count == 0)
return base.GetActorSelectionPoints();
return vecPoints.ToArray();
return base.GetActorSelectionPoints();
}
private void OnAddMeshCollider(EditorWindow window)