From 8ed2d6da5695b3046e2e19758912b31a1f1d72e4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 14 Jul 2025 20:26:24 +0200 Subject: [PATCH] Optimize Debug Draw performance of splines to use frustum culling --- .../Viewport/MainEditorGizmoViewport.cs | 9 +++++++- .../Editor/Viewport/PrefabWindowViewport.cs | 7 +++++- .../Editor/Viewport/Previews/AssetPreview.cs | 1 + Source/Engine/Debug/DebugDraw.cpp | 22 ++++++++++++++----- Source/Engine/Debug/DebugDraw.h | 5 +++++ Source/Engine/Level/Actors/Spline.cpp | 4 +++- 6 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index c14b6dfd8..5343a1fe5 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -340,6 +340,13 @@ namespace FlaxEditor.Viewport { _debugDrawData.Clear(); + if (task is SceneRenderTask sceneRenderTask) + { + // Sync debug view to avoid lag on culling/LODing + var view = sceneRenderTask.View; + DebugDraw.SetView(ref view); + } + // Collect selected objects debug shapes and visuals var selectedParents = TransformGizmo.SelectedParents; if (selectedParents.Count > 0) @@ -374,7 +381,7 @@ namespace FlaxEditor.Viewport // Draw selected objects debug shapes and visuals if (DrawDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw) { - _debugDrawData.DrawActors(); + _debugDrawData.DrawActors(true); DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true); } } diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 8b508eedf..3968f0379 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -243,7 +243,12 @@ namespace FlaxEditor.Viewport _tempDebugDrawContext = DebugDraw.AllocateContext(); DebugDraw.SetContext(_tempDebugDrawContext); DebugDraw.UpdateContext(_tempDebugDrawContext, 1.0f); - + if (task is SceneRenderTask sceneRenderTask) + { + // Sync debug view to avoid lag on culling/LODing + var view = sceneRenderTask.View; + DebugDraw.SetView(ref view); + } for (int i = 0; i < selectedParents.Count; i++) { if (selectedParents[i].IsActiveInHierarchy) diff --git a/Source/Editor/Viewport/Previews/AssetPreview.cs b/Source/Editor/Viewport/Previews/AssetPreview.cs index 84f60f96a..3583a9ff0 100644 --- a/Source/Editor/Viewport/Previews/AssetPreview.cs +++ b/Source/Editor/Viewport/Previews/AssetPreview.cs @@ -264,6 +264,7 @@ namespace FlaxEditor.Viewport.Previews { DebugDraw.SetContext(_debugDrawContext); DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1)); + DebugDraw.SetView(ref renderContext.View); CustomDebugDraw?.Invoke(context, ref renderContext); OnDebugDraw(context, ref renderContext); DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true); diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 752e8bf24..3e5601532 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -357,7 +357,8 @@ struct DebugDrawContext DebugDrawData DebugDrawDefault; DebugDrawData DebugDrawDepthTest; Float3 LastViewPos = Float3::Zero; - Matrix LastViewProj = Matrix::Identity; + Matrix LastViewProjection = Matrix::Identity; + BoundingFrustum LastViewFrustum; inline int32 Count() const { @@ -779,9 +780,23 @@ Vector3 DebugDraw::GetViewPos() return Context->LastViewPos; } +BoundingFrustum DebugDraw::GetViewFrustum() +{ + return Context->LastViewFrustum; +} + +void DebugDraw::SetView(const RenderView& view) +{ + Context->LastViewPos = view.Position; + Context->LastViewProjection = view.Projection; + Context->LastViewFrustum = view.Frustum; +} + void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTextureView* depthBuffer, bool enableDepthTest) { PROFILE_GPU_CPU("Debug Draw"); + const RenderView& view = renderContext.View; + SetView(view); // Ensure to have shader loaded and any lines to render const int32 debugDrawDepthTestCount = Context->DebugDrawDepthTest.Count(); @@ -791,7 +806,6 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe if (renderContext.Buffers == nullptr || !DebugDrawVB) return; auto context = GPUDevice::Instance->GetMainContext(); - const RenderView& view = renderContext.View; if (Context->Origin != view.Origin) { // Teleport existing debug shapes to maintain their location @@ -800,8 +814,6 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe Context->DebugDrawDepthTest.Teleport(delta); Context->Origin = view.Origin; } - Context->LastViewPos = view.Position; - Context->LastViewProj = view.Projection; TaaJitterRemoveContext taaJitterRemove(view); // Fallback to task buffers @@ -1383,7 +1395,7 @@ void DebugDraw::DrawWireSphere(const BoundingSphere& sphere, const Color& color, int32 index; const Float3 centerF = sphere.Center - Context->Origin; const float radiusF = (float)sphere.Radius; - const float screenRadiusSquared = RenderTools::ComputeBoundsScreenRadiusSquared(centerF, radiusF, Context->LastViewPos, Context->LastViewProj); + const float screenRadiusSquared = RenderTools::ComputeBoundsScreenRadiusSquared(centerF, radiusF, Context->LastViewPos, Context->LastViewProjection); if (screenRadiusSquared > DEBUG_DRAW_SPHERE_LOD0_SCREEN_SIZE * DEBUG_DRAW_SPHERE_LOD0_SCREEN_SIZE * 0.25f) index = 0; else if (screenRadiusSquared > DEBUG_DRAW_SPHERE_LOD1_SCREEN_SIZE * DEBUG_DRAW_SPHERE_LOD1_SCREEN_SIZE * 0.25f) diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index 3b51c0e13..3f4ff8aff 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -76,6 +76,11 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw // Gets the last view position when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes. static Vector3 GetViewPos(); + // Gets the last view frustum when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes. + static BoundingFrustum GetViewFrustum(); + + // Sets the rendering view information beforehand. + API_FUNCTION() static void SetView(API_PARAM(ref) const RenderView& view); /// /// Draws the collected debug shapes to the output. diff --git a/Source/Engine/Level/Actors/Spline.cpp b/Source/Engine/Level/Actors/Spline.cpp index eb3df0771..8b690100c 100644 --- a/Source/Engine/Level/Actors/Spline.cpp +++ b/Source/Engine/Level/Actors/Spline.cpp @@ -3,6 +3,7 @@ #include "Spline.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Animations/CurveSerialization.h" +#include "Engine/Core/Math/BoundingFrustum.h" #include "Engine/Core/Math/Matrix.h" #include "Engine/Scripting/ManagedCLR/MCore.h" @@ -520,7 +521,8 @@ namespace void Spline::OnDebugDraw() { - DrawSpline(this, GetSplineColor().AlphaMultiplied(0.7f), _transform, true); + if (DebugDraw::GetViewFrustum().Intersects(_sphere)) + DrawSpline(this, GetSplineColor().AlphaMultiplied(0.7f), _transform, true); // Base Actor::OnDebugDraw();