Files
HelloVulkan/App/editor/StatsPanel.cpp
T
atdunbg 1449bea86d feat: HitProxy GPU 拾取 + UE 选中描边 + 编辑器拾取交互
- HitProxy 拾取:RG 管线渲染实体 id → host readback,点击帧
  PickEntity 精确命中;拾取按视觉几何(Model 联合包围球射线求交),
  与 Collider 解耦(UE/Unity 编辑器语义),命中打印实体名+碰撞体参数
- 选中描边(UE 语义):SelectionMask pass(R8Unorm 完整投影轮廓,
  无深度测试透墙可见)→ Outline pass(边缘检测 + alpha 叠加,
  必须注册在 Tonemap 后);edgeCut 贴视口边缘;widthPx=6 可调
- shader object 实证修复:VUID-08879 同程序 set layouts 超集一致、
  VUID-10065 push block 4×float 平铺、新 pass 析构销毁 VkShaderEXT
- RG:SideEffect() 保活"产出无 RG 内消费者"的 pass 链
- Editor:层次面板点击选中、Inspector 姿态编辑、Stats 面板拾取信息
- 相机 Update 改 const(姿态写入 Transform 引用,Camera 本身无状态变更)
2026-10-02 20:09:05 +08:00

223 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// StatsPanel.cpp:遥测与全局设置实现(原 main.cpp Scene Debug 搬迁)。
//
#include "StatsPanel.h"
#include "Engine/ECS/Components.h"
#include "Engine/Physics/PhysicsWorld.h"
#include "Engine/Core/Time.h"
#include <imgui.h>
#include <glm/gtc/type_ptr.hpp>
using namespace Engine; // f32(Engine/Core/Types.h)
void StatsPanel::Draw(const EditorContext& ctx)
{
ImGui::Begin("Stats");
auto& renderer = *ctx.renderer;
auto& app = *ctx.app;
// ---- Camera:主相机位姿(只读遥测;位姿编辑走 Inspector)----
{
Engine::ECS::TransformComponent* camT = nullptr;
if (ctx.scene->GetPrimaryCamera(&camT) != nullptr && camT != nullptr)
{
const glm::vec3& pos = camT->GetPosition();
ImGui::Text("Camera pos");
ImGui::Text("(%.3f, %.3f, %.3f)", pos.x, pos.y, pos.z);
}
else
{
ImGui::TextDisabled("(no primary camera)");
}
ImGui::Separator();
}
ImGui::Separator();
static const char* displayTarget[] = {
"Fullscreen",
"Viewport",
};
int mode = renderer.GetDisplayMode();
if (ImGui::Combo("##DisplayTarget", &mode, displayTarget, IM_ARRAYSIZE(displayTarget))) {
renderer.SetDisplayMode(mode);
}
ImGui::Separator();
// ---- Scene:暂停模拟(引擎 Time 门面:动画/物理统一冻结)----
{
bool paused = Time::TimeScale() == 0.0f;
if (ImGui::Checkbox("Pause Simulation", &paused))
{
Time::SetTimeScale(paused ? 0.0f : 1.0f);
}
}
// ---- Rendering:渲染管线参数与开关 ----
if (ImGui::CollapsingHeader("Rendering", ImGuiTreeNodeFlags_DefaultOpen))
{
f32 exposure = renderer.GetExposure();
if (ImGui::SliderFloat("exposure", &exposure, 0.1f, 4.0f))
{
renderer.SetExposure(exposure);
}
bool aces = renderer.GetUseACES();
if (ImGui::Checkbox("ACES", &aces))
{
renderer.SetUseACES(aces);
}
// Bloom:开关即显隐——勾上才显示参数
bool bloom = renderer.GetBloomEnabled();
if (ImGui::Checkbox("Bloom", &bloom))
{
renderer.SetBloomEnabled(bloom);
}
if (bloom)
{
f32 threshold = renderer.GetBloomThreshold();
if (ImGui::SliderFloat("threshold", &threshold, 0.0f, 2.0f))
{
renderer.SetBloomThreshold(threshold);
}
f32 strength = renderer.GetBloomStrength();
if (ImGui::SliderFloat("strength", &strength, 0.0f, 2.0f))
{
renderer.SetBloomStrength(strength);
}
}
// 无参数的纯开关:横排平铺
bool shadows = renderer.GetShadowsEnabled();
if (ImGui::Checkbox("Shadows", &shadows))
{
renderer.SetShadowsEnabled(shadows);
}
ImGui::SameLine();
bool taa = renderer.GetTAAEnabled();
if (ImGui::Checkbox("TAA", &taa))
{
renderer.SetTAAEnabled(taa);
}
ImGui::SameLine();
bool lod = renderer.GetLodEnabled();
if (ImGui::Checkbox("LOD", &lod))
{
renderer.SetLodEnabled(lod); // 关 = 恒绘原网格
}
}
// ---- Environment:IBL 环境 + 调试视图(决定"看什么")----
if (ImGui::CollapsingHeader("Environment", ImGuiTreeNodeFlags_DefaultOpen))
{
bool& drawSkybox = ctx.scene->GetSettings().DrawSkybox;
ImGui::Checkbox("DrawSkybox", &drawSkybox);
if (drawSkybox && ctx.getEnvIndex)
{
int envIdx = ctx.getEnvIndex();
if (ImGui::Combo("env", &envIdx, kEnvNames, kEnvCount))
{
ctx.setEnvIndex(envIdx);
const auto env = ctx.assets->LoadEnvironment(kEnvPaths[envIdx]);
ctx.renderer->SetEnvironment(ctx.assets->GetEnvironment(env));
}
// 调试视图:单看某个 pass 的中间输出(类 UE pass debug)
const auto& viewNames = renderer.GetDebugViewNames();
int view = renderer.GetDebugView();
if (ImGui::Combo("Debug View", &view, viewNames.data(),
static_cast<int>(viewNames.size())))
{
renderer.SetDebugView(view);
}
}
else
{
ImGui::ColorEdit4("ClearColor",
glm::value_ptr(ctx.scene->GetSettings().ClearColor));
}
}
// ---- Physics Debug:物理调试可视化(collider/约束/重力/速度/加速度)----
if (ImGui::CollapsingHeader("Physics Debug"))
{
auto& physics = app.GetPhysics();
u32 bits = physics.GetDebugDrawBits();
bool master = bits != 0;
if (ImGui::Checkbox("Enable##PhysDebug", &master))
{
bits = master ? kPhyDbgDefault : 0;
}
if (master)
{
ImGui::Indent();
auto toggle = [&bits](const char* label, u32 bit) {
bool on = (bits & bit) != 0;
if (ImGui::Checkbox(label, &on))
{
bits = on ? (bits | bit) : (bits & ~bit);
}
};
toggle("Colliders", kPhyDbgColliders);
toggle("Constraints", kPhyDbgConstraints);
toggle("Gravity", kPhyDbgGravity);
toggle("Velocity", kPhyDbgVelocity);
toggle("Acceleration", kPhyDbgAccel);
ImGui::Unindent();
}
physics.SetDebugDrawBits(bits);
// 碰撞事件计数(最近一次步进;掉落物触地时应 > 0)
ImGui::Text("contacts (frame): %zu", physics.GetEvents().size());
}
// ---- GPU Timings:只读遥测(默认折叠,不占面板高度)----
if (ImGui::CollapsingHeader("GPU Timings"))
{
ImGui::Text("instances: %u main / %u shadow",
renderer.GetMainInstanceCount(),
renderer.GetShadowInstanceCount());
if (renderer.GetInstancesTruncated())
{
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
"TRUNCATED: instance buffer full!");
}
const auto& names = renderer.GetPassNames();
const auto& times = renderer.GetPassGpuMs();
for (size_t i = 0; i < names.size() && i < times.size(); ++i)
{
ImGui::Text(" %-12s %.3f ms", names[i].c_str(), times[i]);
}
}
// ---- Frame:帧率控制与显示 ----
if (ImGui::CollapsingHeader("Frame", ImGuiTreeNodeFlags_DefaultOpen))
{
bool vsync = app.GetVSync();
if (ImGui::Checkbox("VSync", &vsync))
{
app.SetVSync(vsync);
if (!vsync)
{
const f32 target = app.GetTargetFps();
app.SetTargetFps(target);
}
}
if (!vsync)
{
f32 target = app.GetTargetFps();
if (ImGui::SliderFloat("target fps", &target, 24.0f, 360.0f, "%.0f"))
{
app.SetTargetFps(target);
}
}
ImGui::Text("fps: %.1f frame: %llu",
1.0f / Time::Current().UnscaledDt(),
static_cast<unsigned long long>(app.GetFrameCount()));
}
ImGui::End();
}