新增调试绘制体系:DebugDraw 服务 + 物理调试 pass + 脚本侧力学线

通用图元(线/箭头四翼头/球/胶囊/盒)瞬时+持久双缓冲聚合;
物理 pass 画刚体速度/重力/接触反力;角色 collider 与力学
线归位(引擎只画资产、脚本画行为);线宽按设备上限钳制
This commit is contained in:
2026-10-08 17:02:27 +08:00
parent ff955b9e63
commit 36b1fc0566
10 changed files with 903 additions and 44 deletions
+139
View File
@@ -0,0 +1,139 @@
//
// DebugDraw:引擎级通用调试图元服务(Unity Debug.DrawLine / UE
// DrawDebugHelpers 的对应物)。
//
// 分层定位:全局静态 API,任何层(脚本/物理/动画/AI)调用即收集;
// Renderer 每帧取走缓冲,PhysicsDebugPass 统一上传叠加渲染。引擎侧
// 只写这一次,之后一切新可视化 = 调用方加几行,不再碰引擎代码。
//
// 语义对齐 Unity/UE:
// duration <= 0 → 只画当前帧(调用方每帧重调,Unity DrawLine 同)
// duration > 0 → 存活 duration 秒(内部持久列表,期间无需重调;
// 固定步长系统用 2×步长 即可跨渲染帧无缝续接)
// depthTest=false → 透视遮挡直显(UE DrawDebugLine bPersistent 位)
// width → 线宽(需 wideLines 特性,设备不支持时钳回 1.0)
//
// 线程模型:主线程单写单读(脚本 OnUpdate 收集 → Renderer 上传 →
// EndFrame 翻页)。
// 预算:kMaxVerts 截断 + 一次告警(调试图元打满是滥用信号)。
//
#ifndef HELLOVULKAN_DEBUGDRAW_H
#define HELLOVULKAN_DEBUGDRAW_H
#include <Engine/Core/Types.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <vector>
namespace Engine::Debug {
// 顶点(28B):与 PhysicsDebugVertex 同布局——渲染 pass 复用同一
// 顶点输入态(pos vec3 + color vec4)
struct Vertex {
glm::vec3 pos;
glm::vec4 color;
};
// 渲染批次:同 (拓扑, 线宽, 深度测试) 的连续顶点段。调用方按
// 参数自动分组,draw 侧每批一次状态切换(动态状态零管线对象)
struct Batch {
bool tris; // true = triangleList / false = lineList
f32 width;
bool depthTest;
u32 first; // 顶点偏移(顶点数,非字节)
u32 count;
};
// 单帧收集结果(Renderer 每帧消费,勿手动修改)
struct DebugFrame {
std::vector<Vertex> verts;
std::vector<Batch> batches;
void Clear() { verts.clear(); batches.clear(); }
bool Empty() const { return batches.empty(); }
};
// 顶点预算(每渲染帧):调试线框足够用,溢出截断 + 告警一次
inline constexpr u32 kMaxVerts = 1 << 16;
// ---- 全局开关 ----
void SetEnabled(bool on);
bool IsEnabled();
void Clear(); // 清空瞬时 + 持久图元(PIE 停止/场景切换时调用)
// ---- 线类(全部世界空间)----
void Line(const glm::vec3& a, const glm::vec3& b,
const glm::vec4& color,
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// Ray:from 出发沿单位方向 dirNorm 画 length 长(Unity DrawRay 同形)
void Ray(const glm::vec3& from, const glm::vec3& dirNorm, f32 length,
const glm::vec4& color,
f32 width = 1.0f, f32 duration = 0.0f, bool depthTest = true);
// 箭头:主干 + 两翼头(正交基自动构建,零向量方向安全退化成点)
void Arrow(const glm::vec3& from, const glm::vec3& to,
const glm::vec4& color, f32 headSize = 0.12f,
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// 十字标记(Unity Debug.DrawCross 同位)
void Cross(const glm::vec3& pos, f32 size, const glm::vec4& color,
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// ---- 形状线框 ----
// 三大圆经线圈(UE DrawDebugSphere 同形)
void WireSphere(const glm::vec3& center, f32 radius,
const glm::vec4& color, int segments = 16,
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// 朝向 normal 的平面圆
void WireCircle(const glm::vec3& center, f32 radius,
const glm::vec3& normal, const glm::vec4& color,
int segments = 24,
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// 轴对齐 / 旋转盒(rot 单位四元数 = AABB;UE DrawDebugBox 同形)
void WireBox(const glm::vec3& center, const glm::vec3& halfExtents,
const glm::vec4& color,
const glm::quat& rot = glm::quat(1.0f, 0.0f, 0.0f, 0.0f),
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// 胶囊线框:轴向 local +Y(Jolt 惯例),halfHeight = 圆柱段半长
//(总高 = 2×(halfHeight+radius),与引擎 CharacterController 参数一致)
void WireCapsule(const glm::vec3& center, f32 radius, f32 halfHeight,
const glm::vec4& color,
const glm::quat& rot = glm::quat(1.0f, 0.0f, 0.0f, 0.0f),
f32 width = 1.0f, f32 duration = 0.0f,
bool depthTest = true);
// ---- 便捷色:0xRRGGBB → 线性 HDR vec4(可 >1 过 tonemap 依旧醒目)----
constexpr glm::vec4 Rgb(u32 hex, f32 alpha = 1.0f)
{
constexpr f32 kInv = 1.0f / 255.0f;
return {(static_cast<f32>((hex >> 16) & 0xFF)) * kInv,
(static_cast<f32>((hex >> 8) & 0xFF)) * kInv,
(static_cast<f32>(hex & 0xFF)) * kInv,
alpha};
}
// ---- Renderer 消费端(业务代码勿调用)----
// 取当前帧缓冲(禁用/空 = Empty)。Renderer 上传窗口调用
const DebugFrame& Frame();
// 翻页:清瞬时缓冲 + 清过期持久项。Renderer 上传完成后调用
void EndFrame();
} // namespace Engine::Debug
#endif //HELLOVULKAN_DEBUGDRAW_H