Add DebugDraw::DrawText for drawing 3D debug text in the world

This commit is contained in:
Wojtek Figat
2021-02-18 15:16:10 +01:00
parent 74823a8bcf
commit dc352edce7
2 changed files with 121 additions and 15 deletions

View File

@@ -65,6 +65,16 @@ struct DebugText2D
float TimeLeft; float TimeLeft;
}; };
struct DebugText3D
{
Array<Char, InlinedAllocation<64>> Text;
Transform Transform;
bool FaceCamera;
int32 Size;
Color Color;
float TimeLeft;
};
PACK_STRUCT(struct Vertex { PACK_STRUCT(struct Vertex {
Vector3 Position; Vector3 Position;
Color32 Color; Color32 Color;
@@ -146,10 +156,12 @@ struct DebugDrawData
Array<DebugTriangle> OneFrameWireTriangles; Array<DebugTriangle> OneFrameWireTriangles;
Array<DebugText2D> DefaultText2D; Array<DebugText2D> DefaultText2D;
Array<DebugText2D> OneFrameText2D; Array<DebugText2D> OneFrameText2D;
Array<DebugText3D> DefaultText3D;
Array<DebugText3D> OneFrameText3D;
inline int32 Count() const inline int32 Count() const
{ {
return LinesCount() + TrianglesCount() + Text2DCount(); return LinesCount() + TrianglesCount() + TextCount();
} }
inline int32 LinesCount() const inline int32 LinesCount() const
@@ -162,9 +174,9 @@ struct DebugDrawData
return DefaultTriangles.Count() + OneFrameTriangles.Count() + DefaultWireTriangles.Count() + OneFrameWireTriangles.Count(); return DefaultTriangles.Count() + OneFrameTriangles.Count() + DefaultWireTriangles.Count() + OneFrameWireTriangles.Count();
} }
inline int32 Text2DCount() const inline int32 TextCount() const
{ {
return DefaultText2D.Count() + OneFrameText2D.Count(); return DefaultText2D.Count() + OneFrameText2D.Count() + DefaultText3D.Count() + OneFrameText3D.Count();
} }
inline void Add(const DebugLine& l) inline void Add(const DebugLine& l)
@@ -197,11 +209,13 @@ struct DebugDrawData
UpdateList(deltaTime, DefaultTriangles); UpdateList(deltaTime, DefaultTriangles);
UpdateList(deltaTime, DefaultWireTriangles); UpdateList(deltaTime, DefaultWireTriangles);
UpdateList(deltaTime, DefaultText2D); UpdateList(deltaTime, DefaultText2D);
UpdateList(deltaTime, DefaultText3D);
OneFrameLines.Clear(); OneFrameLines.Clear();
OneFrameTriangles.Clear(); OneFrameTriangles.Clear();
OneFrameWireTriangles.Clear(); OneFrameWireTriangles.Clear();
OneFrameText2D.Clear(); OneFrameText2D.Clear();
OneFrameText3D.Clear();
} }
inline void Clear() inline void Clear()
@@ -214,6 +228,8 @@ struct DebugDrawData
OneFrameWireTriangles.Clear(); OneFrameWireTriangles.Clear();
DefaultText2D.Clear(); DefaultText2D.Clear();
OneFrameText2D.Clear(); OneFrameText2D.Clear();
DefaultText3D.Clear();
OneFrameText3D.Clear();
} }
inline void Release() inline void Release()
@@ -226,6 +242,8 @@ struct DebugDrawData
OneFrameWireTriangles.Resize(0); OneFrameWireTriangles.Resize(0);
DefaultText2D.Resize(0); DefaultText2D.Resize(0);
OneFrameText2D.Resize(0); OneFrameText2D.Resize(0);
DefaultText3D.Resize(0);
OneFrameText3D.Resize(0);
} }
}; };
@@ -324,6 +342,21 @@ DebugDrawCall WriteLists(int32& vertexCounter, const Array<T>& listA, const Arra
return drawCall; return drawCall;
} }
inline void DrawText3D(const DebugText3D& t, const RenderContext& renderContext, const Vector3& viewUp, const Matrix& f, const Matrix& vp, const Viewport& viewport, GPUContext* context, GPUTextureView* target, GPUTextureView* depthBuffer)
{
Matrix w, fw, m;
if (t.FaceCamera)
Matrix::CreateWorld(t.Transform.Translation, renderContext.View.Direction, viewUp, w);
else
t.Transform.GetWorld(w);
Matrix::Multiply(f, w, fw);
Matrix::Multiply(fw, vp, m);
Render2D::Begin(context, target, depthBuffer, viewport, m);
const StringView text(t.Text.Get(), t.Text.Count() - 1);
Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, Vector2::Zero);
Render2D::End();
}
class DebugDrawService : public EngineService class DebugDrawService : public EngineService
{ {
public: public:
@@ -594,7 +627,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
return; return;
auto context = GPUDevice::Instance->GetMainContext(); auto context = GPUDevice::Instance->GetMainContext();
// Fallback to task backbuffer // Fallback to task buffers
if (target == nullptr && renderContext.Task) if (target == nullptr && renderContext.Task)
target = renderContext.Task->GetOutputView(); target = renderContext.Task->GetOutputView();
@@ -696,21 +729,26 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
} }
} }
// Text 2D // Text
if (Context->DebugDrawDefault.TrianglesCount()) if (Context->DebugDrawDefault.TextCount() + Context->DebugDrawDepthTest.TextCount())
{ {
PROFILE_GPU_CPU_NAMED("2D"); PROFILE_GPU_CPU_NAMED("Text");
auto features = Render2D::Features;
Render2D::Features = (Render2D::RenderingFeatures)((uint32)features & ~(uint32)Render2D::RenderingFeatures::VertexSnapping);
if (!DebugDrawFont) if (!DebugDrawFont)
{
DebugDrawFont = Content::LoadAsyncInternal<FontAsset>(TEXT("Editor/Fonts/Roboto-Regular")); DebugDrawFont = Content::LoadAsyncInternal<FontAsset>(TEXT("Editor/Fonts/Roboto-Regular"));
}
if (DebugDrawFont && DebugDrawFont->IsLoaded()) if (DebugDrawFont && DebugDrawFont->IsLoaded())
{ {
Viewport viewport = renderContext.Task->GetViewport(); Viewport viewport = renderContext.Task->GetViewport();
if (Context->DebugDrawDefault.DefaultText2D.Count() + Context->DebugDrawDefault.OneFrameText2D.Count())
{
Render2D::Begin(context, target, nullptr, viewport); Render2D::Begin(context, target, nullptr, viewport);
for (auto& t : Context->DebugDrawDefault.DefaultText2D) for (auto& t : Context->DebugDrawDefault.DefaultText2D)
{ {
const StringView text(t.Text.Get(), t.Text.Count() - 1);
Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position);
} }
for (auto& t : Context->DebugDrawDefault.OneFrameText2D) for (auto& t : Context->DebugDrawDefault.OneFrameText2D)
{ {
@@ -719,6 +757,21 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
} }
Render2D::End(); Render2D::End();
} }
if (Context->DebugDrawDefault.DefaultText3D.Count() + Context->DebugDrawDefault.OneFrameText3D.Count())
{
Matrix f;
Matrix::RotationZ(PI, f);
Vector3 viewUp;
Vector3::Transform(Vector3::Up, Quaternion::LookRotation(renderContext.View.Direction, Vector3::Up), viewUp);
for (auto& t : Context->DebugDrawDefault.DefaultText3D)
DrawText3D(t, renderContext, viewUp, f, vp, viewport, context, target, nullptr);
for (auto& t : Context->DebugDrawDefault.OneFrameText3D)
DrawText3D(t, renderContext, viewUp, f, vp, viewport, context, target, nullptr);
}
}
Render2D::Features = features;
} }
} }
@@ -1337,4 +1390,36 @@ void DebugDraw::DrawText(const StringView& text, const Vector2& position, const
t.TimeLeft = duration; t.TimeLeft = duration;
} }
void DebugDraw::DrawText(const StringView& text, const Vector3& position, const Color& color, int32 size, float duration)
{
if (text.Length() == 0 || size < 4)
return;
Array<DebugText3D>* list = duration > 0 ? &Context->DebugDrawDefault.DefaultText3D : &Context->DebugDrawDefault.OneFrameText3D;
auto& t = list->AddOne();
t.Text.Resize(text.Length() + 1);
Platform::MemoryCopy(t.Text.Get(), text.Get(), text.Length() * sizeof(Char));
t.Text[text.Length()] = 0;
t.Transform = position;
t.FaceCamera = true;
t.Size = size;
t.Color = color;
t.TimeLeft = duration;
}
void DebugDraw::DrawText(const StringView& text, const Transform& transform, const Color& color, int32 size, float duration)
{
if (text.Length() == 0 || size < 4)
return;
Array<DebugText3D>* list = duration > 0 ? &Context->DebugDrawDefault.DefaultText3D : &Context->DebugDrawDefault.OneFrameText3D;
auto& t = list->AddOne();
t.Text.Resize(text.Length() + 1);
Platform::MemoryCopy(t.Text.Get(), text.Get(), text.Length() * sizeof(Char));
t.Text[text.Length()] = 0;
t.Transform = transform;
t.FaceCamera = false;
t.Size = size;
t.Color = color;
t.TimeLeft = duration;
}
#endif #endif

View File

@@ -15,6 +15,7 @@ class GPUContext;
class RenderTask; class RenderTask;
class SceneRenderTask; class SceneRenderTask;
class Actor; class Actor;
struct Transform;
/// <summary> /// <summary>
/// The debug shapes rendering service. Not available in final game. For use only in the editor. /// The debug shapes rendering service. Not available in final game. For use only in the editor.
@@ -317,6 +318,26 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(DebugDraw);
/// <param name="size">The font size.</param> /// <param name="size">The font size.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param> /// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
API_FUNCTION() static void DrawText(const StringView& text, const Vector2& position, const Color& color, int32 size = 20, float duration = 0.0f); API_FUNCTION() static void DrawText(const StringView& text, const Vector2& position, const Color& color, int32 size = 20, float duration = 0.0f);
/// <summary>
/// Draws the text (3D) that automatically faces the camera.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="position">The position of the text (world-space).</param>
/// <param name="color">The color.</param>
/// <param name="size">The font size.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
API_FUNCTION() static void DrawText(const StringView& text, const Vector3& position, const Color& color, int32 size = 32, float duration = 0.0f);
/// <summary>
/// Draws the text (3D).
/// </summary>
/// <param name="text">The text.</param>
/// <param name="transform">The transformation of the text (world-space).</param>
/// <param name="color">The color.</param>
/// <param name="size">The font size.</param>
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color, int32 size = 32, float duration = 0.0f);
}; };
#define DEBUG_DRAW_LINE(start, end, color, duration, depthTest) DebugDraw::DrawLine(start, end, color, duration, depthTest) #define DEBUG_DRAW_LINE(start, end, color, duration, depthTest) DebugDraw::DrawLine(start, end, color, duration, depthTest)