Optimize terrain debug shape drawing by caching lines into a vertex buffer
#2841
This commit is contained in:
@@ -94,6 +94,13 @@ struct DebugLine
|
||||
float TimeLeft;
|
||||
};
|
||||
|
||||
struct DebugGeometryBuffer
|
||||
{
|
||||
GPUBuffer* Buffer;
|
||||
float TimeLeft;
|
||||
Matrix Transform;
|
||||
};
|
||||
|
||||
struct DebugTriangle
|
||||
{
|
||||
Float3 V0;
|
||||
@@ -122,12 +129,9 @@ struct DebugText3D
|
||||
float TimeLeft;
|
||||
};
|
||||
|
||||
PACK_STRUCT(struct Vertex {
|
||||
Float3 Position;
|
||||
Color32 Color;
|
||||
});
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
|
||||
GPU_CB_STRUCT(Data {
|
||||
GPU_CB_STRUCT(ShaderData {
|
||||
Matrix ViewProjection;
|
||||
Float2 Padding;
|
||||
float ClipPosZBias;
|
||||
@@ -231,6 +235,7 @@ void TeleportList(const Float3& delta, Array<DebugText3D>& list)
|
||||
|
||||
struct DebugDrawData
|
||||
{
|
||||
Array<DebugGeometryBuffer> GeometryBuffers;
|
||||
Array<DebugLine> DefaultLines;
|
||||
Array<Vertex> OneFrameLines;
|
||||
Array<DebugTriangle> DefaultTriangles;
|
||||
@@ -244,7 +249,7 @@ struct DebugDrawData
|
||||
|
||||
inline int32 Count() const
|
||||
{
|
||||
return LinesCount() + TrianglesCount() + TextCount();
|
||||
return LinesCount() + TrianglesCount() + TextCount() + GeometryBuffers.Count();
|
||||
}
|
||||
|
||||
inline int32 LinesCount() const
|
||||
@@ -280,6 +285,7 @@ struct DebugDrawData
|
||||
|
||||
inline void Update(float deltaTime)
|
||||
{
|
||||
UpdateList(deltaTime, GeometryBuffers);
|
||||
UpdateList(deltaTime, DefaultLines);
|
||||
UpdateList(deltaTime, DefaultTriangles);
|
||||
UpdateList(deltaTime, DefaultWireTriangles);
|
||||
@@ -784,7 +790,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
|
||||
// Update constant buffer
|
||||
const auto cb = DebugDrawShader->GetShader()->GetCB(0);
|
||||
Data data;
|
||||
ShaderData data;
|
||||
Matrix vp;
|
||||
Matrix::Multiply(view.View, view.Projection, vp);
|
||||
Matrix::Transpose(vp, data.ViewProjection);
|
||||
@@ -830,6 +836,22 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
context->Draw(depthTestTriangles.StartVertex, depthTestTriangles.VertexCount);
|
||||
}
|
||||
|
||||
// Geometries
|
||||
for (auto& geometry : Context->DebugDrawDepthTest.GeometryBuffers)
|
||||
{
|
||||
auto tmp = data;
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
|
||||
context->SetState(state->Get(enableDepthWrite, true));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
if (Context->DebugDrawDepthTest.GeometryBuffers.HasItems())
|
||||
context->UpdateCB(cb, &data);
|
||||
|
||||
if (data.EnableDepthTest)
|
||||
context->UnBindSR(0);
|
||||
}
|
||||
@@ -862,6 +884,19 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
context->BindVB(ToSpan(&vb, 1));
|
||||
context->Draw(defaultTriangles.StartVertex, defaultTriangles.VertexCount);
|
||||
}
|
||||
|
||||
// Geometries
|
||||
for (auto& geometry : Context->DebugDrawDefault.GeometryBuffers)
|
||||
{
|
||||
auto tmp = data;
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
context->SetState(DebugDrawPsLinesDefault.Get(false, false));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
}
|
||||
|
||||
// Text
|
||||
@@ -1088,6 +1123,24 @@ void DebugDraw::DrawLines(const Span<Float3>& lines, const Matrix& transform, co
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float duration, bool depthTest)
|
||||
{
|
||||
if (lines == nullptr || lines->GetSize() == 0)
|
||||
return;
|
||||
if (lines->GetSize() % (sizeof(Vertex) * 2) != 0)
|
||||
{
|
||||
DebugLog::ThrowException("Cannot draw debug lines with uneven amount of items in array");
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw lines
|
||||
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = lines;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
void DebugDraw::DrawLines(const Array<Float3>& lines, const Matrix& transform, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
DrawLines(Span<Float3>(lines.Get(), lines.Count()), transform, color, duration, depthTest);
|
||||
@@ -2147,6 +2200,7 @@ void DebugDraw::DrawText(const StringView& text, const Transform& transform, con
|
||||
|
||||
void DebugDraw::Clear(void* context)
|
||||
{
|
||||
DebugDraw::UpdateContext(context, MAX_float);
|
||||
UpdateContext(context, MAX_float);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Core/Math/Color.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Core/Types/Span.h"
|
||||
|
||||
struct RenderView;
|
||||
@@ -14,6 +16,7 @@ class Light;
|
||||
struct RenderContext;
|
||||
class GPUTextureView;
|
||||
class GPUContext;
|
||||
class GPUBuffer;
|
||||
class RenderTask;
|
||||
class SceneRenderTask;
|
||||
class Actor;
|
||||
@@ -26,6 +29,14 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(DebugDraw);
|
||||
|
||||
/// <summary>
|
||||
/// Vertex data for debug shapes.
|
||||
/// </summary>
|
||||
PACK_STRUCT(struct Vertex {
|
||||
Float3 Position;
|
||||
Color32 Color;
|
||||
});
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Allocates the context for Debug Drawing. Can be use to redirect debug shapes collecting to a separate container (instead of global state).
|
||||
@@ -175,6 +186,15 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawLines(const Span<Float3>& lines, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the lines using the provided vertex buffer that contains pairs of Vertex elements. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...).
|
||||
/// </summary>
|
||||
/// <param name="lines">The GPU buffer with vertices for lines (must have multiple of 2 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawLines(GPUBuffer* lines, const Matrix& transform, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the lines. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...).
|
||||
/// </summary>
|
||||
@@ -691,9 +711,9 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color = Color::White, int32 size = 32, float duration = 0.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all debug draw displayed on sceen.
|
||||
/// Clears all debug shapes displayed on screen.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name="context">The context.</param>
|
||||
API_FUNCTION() static void Clear(void* context = nullptr);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "GPUResourceProperty.h"
|
||||
#include "GPUBufferDescription.h"
|
||||
#include "PixelFormatExtensions.h"
|
||||
#include "RenderTask.h"
|
||||
#include "Async/Tasks/GPUCopyResourceTask.h"
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
@@ -358,6 +359,16 @@ void GPUBuffer::SetData(const void* data, uint32 size)
|
||||
Log::ArgumentOutOfRangeException(TEXT("Buffer.SetData"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_desc.Usage == GPUResourceUsage::Default && GPUDevice::Instance->IsRendering())
|
||||
{
|
||||
// Upload using the context (will use internal staging buffer inside command buffer)
|
||||
RenderContext::GPULocker.Lock();
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(this, data, size);
|
||||
RenderContext::GPULocker.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
void* mapped = Map(GPUResourceMapMode::Write);
|
||||
if (!mapped)
|
||||
return;
|
||||
|
||||
@@ -74,8 +74,7 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE uint32 GetElementsCount() const
|
||||
{
|
||||
ASSERT(_desc.Stride > 0);
|
||||
return _desc.Size / _desc.Stride;
|
||||
return _desc.Stride > 0 ? _desc.Size / _desc.Stride : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -90,6 +90,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c
|
||||
// Draw physics shapes
|
||||
if (EnumHasAnyFlags(view.Flags, ViewFlags::PhysicsDebug) || view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
PROFILE_CPU_NAMED("PhysicsDebug");
|
||||
const PhysicsDebugCallback* physicsDebugData = PhysicsDebug.Get();
|
||||
for (int32 i = 0; i < PhysicsDebug.Count(); i++)
|
||||
{
|
||||
@@ -100,6 +101,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c
|
||||
// Draw light shapes
|
||||
if (EnumHasAnyFlags(view.Flags, ViewFlags::LightsDebug))
|
||||
{
|
||||
PROFILE_CPU_NAMED("LightsDebug");
|
||||
const LightsDebugCallback* lightsDebugData = LightsDebug.Get();
|
||||
for (int32 i = 0; i < LightsDebug.Count(); i++)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/DynamicBuffer.h"
|
||||
#include "Engine/Engine/Units.h"
|
||||
#endif
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/RawDataAsset.h"
|
||||
|
||||
@@ -94,7 +99,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
}
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
SAFE_DELETE(_debugLines);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -1822,7 +1828,7 @@ bool TerrainPatch::UpdateHeightData(TerrainDataUpdateInfo& info, const Int2& mod
|
||||
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -1940,7 +1946,7 @@ bool TerrainPatch::UpdateCollision()
|
||||
{
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2082,7 +2088,7 @@ void TerrainPatch::UpdatePostManualDeserialization()
|
||||
{
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2211,7 +2217,8 @@ void TerrainPatch::DestroyCollision()
|
||||
_physicsShape = nullptr;
|
||||
_physicsHeightField = nullptr;
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
SAFE_DELETE(_debugLines);
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2224,15 +2231,26 @@ void TerrainPatch::DestroyCollision()
|
||||
void TerrainPatch::CacheDebugLines()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ASSERT(_debugLines.IsEmpty() && _physicsHeightField);
|
||||
ASSERT(_physicsHeightField);
|
||||
_debugLinesDirty = false;
|
||||
if (!_debugLines)
|
||||
_debugLines = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.DebugLines"));
|
||||
|
||||
int32 rows, cols;
|
||||
PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
|
||||
const int32 count = (rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2;
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
if (_debugLines->GetElementsCount() != count)
|
||||
{
|
||||
if (_debugLines->Init(GPUBufferDescription::Vertex(sizeof(Vertex), count)))
|
||||
return;
|
||||
}
|
||||
Array<Vertex> debugLines;
|
||||
debugLines.Resize(count);
|
||||
auto* data = debugLines.Get();
|
||||
const Color32 color(Color::GreenYellow * 0.8f);
|
||||
|
||||
_debugLines.Resize((rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2);
|
||||
Vector3* data = _debugLines.Get();
|
||||
|
||||
#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y)))
|
||||
#define GET_VERTEX(x, y) const Vertex v##x##y = { Float3((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))), color }
|
||||
|
||||
for (int32 row = 0; row < rows - 1; row++)
|
||||
{
|
||||
@@ -2243,7 +2261,7 @@ void TerrainPatch::CacheDebugLines()
|
||||
if (sample.MaterialIndex0 == (uint8)PhysicsBackend::HeightFieldMaterial::Hole)
|
||||
{
|
||||
for (int32 i = 0; i < 6; i++)
|
||||
*data++ = Vector3::Zero;
|
||||
*data++ = Vertex { Float3::Zero, Color32::Black };
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2284,18 +2302,16 @@ void TerrainPatch::CacheDebugLines()
|
||||
}
|
||||
|
||||
#undef GET_VERTEX
|
||||
|
||||
_debugLines->SetData(debugLines.Get(), _debugLines->GetSize());
|
||||
}
|
||||
|
||||
void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
#if COMPILE_WITH_DEBUG_DRAW
|
||||
const BoundingBox bounds(_bounds.Minimum - view.Origin, _bounds.Maximum - view.Origin);
|
||||
if (!_physicsShape || !view.CullingFrustum.Intersects(bounds))
|
||||
return;
|
||||
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true);
|
||||
@@ -2304,13 +2320,17 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
BoundingSphere sphere;
|
||||
BoundingSphere::FromBox(bounds, sphere);
|
||||
if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < 4000.0f)
|
||||
if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < METERS_TO_UNITS(500))
|
||||
{
|
||||
if (_debugLines.IsEmpty())
|
||||
if (!_debugLines || _debugLinesDirty)
|
||||
CacheDebugLines();
|
||||
DEBUG_DRAW_LINES(_debugLines, world, Color::GreenYellow * 0.8f, 0, true);
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
DebugDraw::DrawLines(_debugLines, world);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,12 +40,13 @@ private:
|
||||
Array<Color32> _cachedSplatMap[TERRAIN_MAX_SPLATMAPS_COUNT];
|
||||
bool _wasHeightModified;
|
||||
bool _wasSplatmapModified[TERRAIN_MAX_SPLATMAPS_COUNT];
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
bool _debugLinesDirty = true;
|
||||
class GPUBuffer* _debugLines = nullptr;
|
||||
#endif
|
||||
TextureBase::InitData* _dataHeightmap = nullptr;
|
||||
TextureBase::InitData* _dataSplatmap[TERRAIN_MAX_SPLATMAPS_COUNT] = {};
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
Array<Vector3> _debugLines; // TODO: large-worlds
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
Array<Vector3> _collisionTriangles; // TODO: large-worlds
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user