Add option for debug shapes drawing for particle emitters

#3267
This commit is contained in:
Wojtek Figat
2025-07-11 23:00:41 +02:00
parent 0bc595f16f
commit 3e82e550f3
9 changed files with 187 additions and 3 deletions

View File

@@ -2,8 +2,16 @@
#include "ParticleEmitterGraph.CPU.h"
#include "Engine/Core/Random.h"
#include "Engine/Core/Math/Vector2.h"
#include "Engine/Core/Math/Vector3.h"
#include "Engine/Core/Math/Vector4.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Quaternion.h"
#include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Core/Math/BoundingSphere.h"
#include "Engine/Core/Math/OrientedBoundingBox.h"
#include "Engine/Utilities/Noise.h"
#include "Engine/Core/Types/CommonValue.h"
#include "Engine/Debug/DebugDraw.h"
// ReSharper disable CppCStyleCast
// ReSharper disable CppClangTidyClangDiagnosticCastAlign
@@ -1468,3 +1476,89 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
#undef COLLISION_LOGIC
}
}
#if USE_EDITOR
void ParticleEmitterGraphCPUExecutor::DebugDrawModule(ParticleEmitterGraphCPUNode* node, const Transform& transform)
{
// Skip modules that rely on particle data
if (node->UsePerParticleDataResolve())
return;
const Color color = Color::White;
switch (node->TypeID)
{
case 202: // Position (sphere surface)
case 211: // Position (sphere volume)
{
const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2));
const float radius = (float)GetValue(node->GetBox(1), 3);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, radius), color, 0.0f, true);
break;
}
case 203: // Position (plane)
{
const Float3 center = (Float3)GetValue(node->GetBox(0), 2);
const Float2 size = (Float2)GetValue(node->GetBox(1), 3);
const Float3 halfExtent = Float3(size.X * 0.5f, 0.0f, size.Y * 0.5f);
OrientedBoundingBox box(halfExtent, Transform(center));
box.Transform(transform);
DEBUG_DRAW_WIRE_BOX(box, color, 0.0f, true);
break;
}
case 204: // Position (circle)
case 205: // Position (disc)
{
const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2));
const float radius = (float)GetValue(node->GetBox(1), 3);
DEBUG_DRAW_WIRE_CYLINDER(center, transform.Orientation * Quaternion::Euler(90, 0, 0), radius, 0.0f, color, 0.0f, true);
break;
}
case 206: // Position (box surface)
case 207: // Position (box volume)
{
const Float3 center = (Float3)GetValue(node->GetBox(0), 2);
const Float3 size = (Float3)GetValue(node->GetBox(1), 3);
OrientedBoundingBox box(size * 0.5f, Transform(center));
box.Transform(transform);
DEBUG_DRAW_WIRE_BOX(box, color, 0.0f, true);
break;
}
// Position (cylinder)
case 208:
{
const float height = (float)GetValue(node->GetBox(2), 4);
const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2) + Float3(0, 0, height * 0.5f));
const float radius = (float)GetValue(node->GetBox(1), 3);
DEBUG_DRAW_WIRE_CYLINDER(center, transform.Orientation * Quaternion::Euler(90, 0, 0), radius, height, color, 0.0f, true);
break;
}
// Position (line)
case 209:
{
const Float3 start = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2));
const Float3 end = transform.LocalToWorld((Float3)GetValue(node->GetBox(1), 3));
DEBUG_DRAW_LINE(start, end, color, 0.0f, true);
break;
}
// Position (torus)
case 210:
{
const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2));
const float radius = Math::Max((float)GetValue(node->GetBox(1), 3), ZeroTolerance);
const float thickness = (float)GetValue(node->GetBox(2), 4);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, radius + thickness), color, 0.0f, true);
break;
}
// Position (spiral)
case 214:
{
const Float3 center = transform.LocalToWorld((Float3)GetValue(node->GetBox(0), 2));
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(center, 5.0f), color, 0.0f, true);
break;
}
}
}
#endif

View File

@@ -7,6 +7,7 @@
#include "Engine/Particles/ParticleEffect.h"
#include "Engine/Engine/Time.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Debug/DebugDraw.h"
ThreadLocal<ParticleEmitterGraphCPUContext*> ParticleEmitterGraphCPUExecutor::Context;
@@ -423,6 +424,23 @@ void ParticleEmitterGraphCPUExecutor::Draw(ParticleEmitter* emitter, ParticleEff
}
}
#if USE_EDITOR
void ParticleEmitterGraphCPUExecutor::DrawDebug(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data)
{
// Prepare graph data
Init(emitter, effect, data);
Transform transform = emitter->SimulationSpace == ParticlesSimulationSpace::Local ? effect->GetTransform() : Transform::Identity;
// Draw modules
for (auto module : emitter->Graph.SpawnModules)
DebugDrawModule(module, transform);
for (auto module : emitter->Graph.InitModules)
DebugDrawModule(module, transform);
}
#endif
void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt, bool canSpawn)
{
// Prepare data

View File

@@ -162,6 +162,16 @@ public:
/// <param name="transform">The effect transform matrix.</param>
void Draw(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, RenderContext& renderContext, Matrix& transform);
#if USE_EDITOR
/// <summary>
/// Draws the particles debug shapes.
/// </summary>
/// <param name="emitter">The owning emitter.</param>
/// <param name="effect">The instance effect.</param>
/// <param name="data">The instance data.</param>
void DrawDebug(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data);
#endif
/// <summary>
/// Updates the particles simulation (the CPU simulation).
/// </summary>
@@ -195,6 +205,9 @@ private:
int32 ProcessSpawnModule(int32 index);
void ProcessModule(ParticleEmitterGraphCPUNode* node, int32 particlesStart, int32 particlesEnd);
#if USE_EDITOR
void DebugDrawModule(ParticleEmitterGraphCPUNode* node, const Transform& transform);
#endif
FORCE_INLINE Value GetValue(Box* box, int32 defaultValueBoxIndex)
{