Files
HelloVulkan/App/editor/StatsPanel.cpp
T
atdunbg 432089747f Environment settings become scene entities (UE Skybox/SkyLight semantics)
Skybox/SkyLight are now Actor-carried components instead of resident
global settings, matching UE where SkyAtmosphere/SkyLight/fog are
Actors added from Place Actors and configured in Details.

- New SkyboxComponent (active + envPath asset slot) and SkyLightComponent
  (active + ambientColor); first-active entity wins per frame
- SceneRenderer collects env from components into FrameSceneData
  (DrawSkybox/envPath/ambient); Renderer performs delta sync - env
  reloads only when the resolved path changes, neutral fallback when
  empty or unloadable
- App-side env plumbing removed: kEnvPaths table and getEnvIndex/
  setEnvIndex callbacks deleted; StatsPanel keeps ClearColor + debug
  view, env params move to Details
- Serializer: scene-level Settings stores ClearColor only; env
  components serialize per entity; legacy v1 scenes (Environment header
  + Settings.AmbientColor/DrawSkybox) auto-migrate into an Environment
  entity on load for visual parity
- Inspector: Skybox/Sky Light sections with .hdr asset slot dropdown
  and Add Component entries; Outliner "+ Create" popup offers
  Empty/Light/Camera/Environment
2026-10-05 01:02:21 +08:00

219 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:视图相机位姿(只读遥测;跟随渲染源分派)----
{
if (ctx.renderer->GetDisplayMode() == kDisplayViewport && ctx.editorCamera)
{
const glm::vec3& pos = ctx.editorCamera->GetTransform().GetPosition();
ImGui::Text("Editor camera pos");
ImGui::Text("(%.3f, %.3f, %.3f)", pos.x, pos.y, pos.z);
}
else
{
Engine::ECS::TransformComponent* camT = nullptr;
if (ctx.scene->GetPrimaryCamera(&camT) != nullptr && camT != nullptr)
{
// world 位姿(相机实体可能挂父层级下)
const glm::vec3& pos = camT->GetWorldPosition();
ImGui::Text("Game 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:清屏色 + 调试视图(决定"看什么")。
// 环境贴图/环境光已迁为实体组件(Skybox/SkyLight),在 Details 配 ----
if (ImGui::CollapsingHeader("Environment", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::ColorEdit4("ClearColor",
glm::value_ptr(ctx.scene->GetSettings().ClearColor));
// 调试视图:单看某个 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);
}
}
// ---- 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();
}