Optimize Debug Draw wireframe sphere to use auto-LOD

This commit is contained in:
Wojtek Figat
2021-06-14 14:22:46 +02:00
parent da0c8ffff9
commit e455ada90a

View File

@@ -16,6 +16,7 @@
#include "Engine/Graphics/GPUPipelineState.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/DynamicBuffer.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
@@ -31,9 +32,11 @@
// Debug draw service configuration
#define DEBUG_DRAW_INITIAL_VB_CAPACITY (4 * 1024)
//
#define DEBUG_DRAW_SPHERE_RESOLUTION 64
#define DEBUG_DRAW_SPHERE_LINES_COUNT (DEBUG_DRAW_SPHERE_RESOLUTION + 1) * 3
#define DEBUG_DRAW_SPHERE_VERTICES DEBUG_DRAW_SPHERE_LINES_COUNT * 2
#define DEBUG_DRAW_SPHERE_LOD0_RESOLUTION 64
#define DEBUG_DRAW_SPHERE_LOD0_SCREEN_SIZE 0.2f
#define DEBUG_DRAW_SPHERE_LOD1_RESOLUTION 16
#define DEBUG_DRAW_SPHERE_LOD1_SCREEN_SIZE 0.08f
#define DEBUG_DRAW_SPHERE_LOD2_RESOLUTION 8
//
#define DEBUG_DRAW_CIRCLE_RESOLUTION 32
#define DEBUG_DRAW_CIRCLE_LINES_COUNT DEBUG_DRAW_CIRCLE_RESOLUTION
@@ -44,6 +47,39 @@
//
#define DEBUG_DRAW_TRIANGLE_SPHERE_RESOLUTION 12
struct DebugSphereCache
{
Array<Vector3, FixedAllocation<(DEBUG_DRAW_SPHERE_LOD0_RESOLUTION + 1) * 3 * 2>> Vertices;
void Init(int32 resolution)
{
const int32 verticesCount = (resolution + 1) * 3 * 2;
Vertices.Resize(verticesCount);
int32 index = 0;
const float step = TWO_PI / (float)resolution;
for (float a = 0.0f; a < TWO_PI; a += step)
{
// Calculate sines and cosines
const float sinA = Math::Sin(a);
const float cosA = Math::Cos(a);
const float sinB = Math::Sin(a + step);
const float cosB = Math::Cos(a + step);
// XY loop
Vertices[index++] = Vector3(cosA, sinA, 0.0f);
Vertices[index++] = Vector3(cosB, sinB, 0.0f);
// XZ loop
Vertices[index++] = Vector3(cosA, 0.0f, sinA);
Vertices[index++] = Vector3(cosB, 0.0f, sinB);
// YZ loop
Vertices[index++] = Vector3(0.0f, cosA, sinA);
Vertices[index++] = Vector3(0.0f, cosB, sinB);
}
}
};
struct DebugLine
{
Vector3 Start;
@@ -248,6 +284,8 @@ struct DebugDrawContext
{
DebugDrawData DebugDrawDefault;
DebugDrawData DebugDrawDepthTest;
Vector3 LastViewPos = Vector3::Zero;
Matrix LastViewProj = Matrix::Identity;
};
namespace
@@ -263,9 +301,9 @@ namespace
PsData DebugDrawPsTrianglesDefault;
PsData DebugDrawPsTrianglesDepthTest;
DynamicVertexBuffer* DebugDrawVB = nullptr;
Vector3 SphereCache[DEBUG_DRAW_SPHERE_VERTICES];
Vector3 CircleCache[DEBUG_DRAW_CIRCLE_VERTICES];
Array<Vector3> SphereTriangleCache;
DebugSphereCache SphereCache[3];
};
extern int32 BoxTrianglesIndicesCache[];
@@ -396,32 +434,13 @@ bool DebugDrawService::Init()
Context = &GlobalContext;
// Init wireframe sphere cache
int32 index = 0;
float step = TWO_PI / DEBUG_DRAW_SPHERE_RESOLUTION;
for (float a = 0.0f; a < TWO_PI; a += step)
{
// Calculate sines and cosines
float sinA = Math::Sin(a);
float cosA = Math::Cos(a);
float sinB = Math::Sin(a + step);
float cosB = Math::Cos(a + step);
// XY loop
SphereCache[index++] = Vector3(cosA, sinA, 0.0f);
SphereCache[index++] = Vector3(cosB, sinB, 0.0f);
// XZ loop
SphereCache[index++] = Vector3(cosA, 0.0f, sinA);
SphereCache[index++] = Vector3(cosB, 0.0f, sinB);
// YZ loop
SphereCache[index++] = Vector3(0.0f, cosA, sinA);
SphereCache[index++] = Vector3(0.0f, cosB, sinB);
}
SphereCache[0].Init(DEBUG_DRAW_SPHERE_LOD0_RESOLUTION);
SphereCache[1].Init(DEBUG_DRAW_SPHERE_LOD1_RESOLUTION);
SphereCache[2].Init(DEBUG_DRAW_SPHERE_LOD2_RESOLUTION);
// Init wireframe circle cache
index = 0;
step = TWO_PI / DEBUG_DRAW_CIRCLE_RESOLUTION;
int32 index = 0;
float step = TWO_PI / (float)DEBUG_DRAW_CIRCLE_RESOLUTION;
for (float a = 0.0f; a < TWO_PI; a += step)
{
// Calculate sines and cosines
@@ -648,6 +667,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
if (renderContext.Buffers == nullptr || !DebugDrawVB)
return;
auto context = GPUDevice::Instance->GetMainContext();
Context->LastViewPos = renderContext.View.Position;
Context->LastViewProj = renderContext.View.Projection;
// Fallback to task buffers
if (target == nullptr && renderContext.Task)
@@ -923,21 +944,6 @@ void DebugDraw::DrawBezier(const Vector3& p1, const Vector3& p2, const Vector3&
}
}
#define DRAW_WIRE_BOX_LINE(i0, i1, list) l.Start = corners[i0]; l.End = corners[i1]; Context->list.Add(l)
#define DRAW_WIRE_BOX(list) \
DRAW_WIRE_BOX_LINE(0, 1, list); \
DRAW_WIRE_BOX_LINE(0, 3, list); \
DRAW_WIRE_BOX_LINE(0, 4, list); \
DRAW_WIRE_BOX_LINE(1, 2, list); \
DRAW_WIRE_BOX_LINE(1, 5, list); \
DRAW_WIRE_BOX_LINE(2, 3, list); \
DRAW_WIRE_BOX_LINE(2, 6, list); \
DRAW_WIRE_BOX_LINE(3, 7, list); \
DRAW_WIRE_BOX_LINE(4, 5, list); \
DRAW_WIRE_BOX_LINE(4, 7, list); \
DRAW_WIRE_BOX_LINE(5, 6, list); \
DRAW_WIRE_BOX_LINE(6, 7, list)
void DebugDraw::DrawWireBox(const BoundingBox& box, const Color& color, float duration, bool depthTest)
{
// Get corners
@@ -1036,26 +1042,37 @@ void DebugDraw::DrawWireBox(const OrientedBoundingBox& box, const Color& color,
void DebugDraw::DrawWireSphere(const BoundingSphere& sphere, const Color& color, float duration, bool depthTest)
{
// Select LOD
int32 index;
const float screenRadiusSquared = RenderTools::ComputeBoundsScreenRadiusSquared(sphere.Center, sphere.Radius, Context->LastViewPos, Context->LastViewProj);
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)
index = 1;
else
index = 2;
auto& cache = SphereCache[index];
// Draw lines of the unit sphere after linear transform
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
if (duration > 0)
{
DebugLine l = { Vector3::Zero, Vector3::Zero, Color32(color), duration };
for (int32 i = 0; i < DEBUG_DRAW_SPHERE_VERTICES;)
for (int32 i = 0; i < cache.Vertices.Count();)
{
l.Start = sphere.Center + SphereCache[i++] * sphere.Radius;
l.End = sphere.Center + SphereCache[i++] * sphere.Radius;
l.Start = sphere.Center + cache.Vertices.Get()[i++] * sphere.Radius;
l.End = sphere.Center + cache.Vertices.Get()[i++] * sphere.Radius;
debugDrawData.DefaultLines.Add(l);
}
}
else
{
Vertex l = { Vector3::Zero, Color32(color) };
for (int32 i = 0; i < DEBUG_DRAW_SPHERE_VERTICES;)
for (int32 i = 0; i < cache.Vertices.Count();)
{
l.Position = sphere.Center + SphereCache[i++] * sphere.Radius;
l.Position = sphere.Center + cache.Vertices.Get()[i++] * sphere.Radius;
debugDrawData.OneFrameLines.Add(l);
l.Position = sphere.Center + SphereCache[i++] * sphere.Radius;
l.Position = sphere.Center + cache.Vertices.Get()[i++] * sphere.Radius;
debugDrawData.OneFrameLines.Add(l);
}
}
@@ -1263,7 +1280,8 @@ void DebugDraw::DrawWireTube(const Vector3& position, const Quaternion& orientat
else
{
// Set up
const float step = TWO_PI / DEBUG_DRAW_SPHERE_RESOLUTION;
const int32 resolution = 64;
const float step = TWO_PI / (float)resolution;
radius = Math::Max(radius, 0.05f);
length = Math::Max(length, 0.05f);
const float halfLength = length / 2.0f;