- App/editor: Hierarchy/Inspector/Viewport/Stats 四面板 + DockBuilder 默认布局,main.cpp 瘦身为场景搭建与生命周期 - 显示链: Tonemap→PresentTarget 经 ImGui::Image 呈现(零色偏),backbuffer 仅承载 ImGui;Direct/Viewport 双显示模式 + 面板分辨率上报 - 帧首同步 BeginFrameSync: resize/vsync/尺寸/模式意图统一帧首落定(修描述符悬垂);修复 vsync 意图未落 swapchain 导致的每帧重建交换链 - 输入: Editor 每帧判定键盘/鼠标归属(打字让位、Viewport hover/focus 放行、Fullscreen 全放行) - 材质: roughness 独立槽位 + 非 glTF 金属/粗糙贴图映射;透明队列 depthWrite=FALSE + translucent 独立 shader + scratch 清帧 - FBX: 非蒙皮网格烘焙节点链全局变换(Z-up 旋转/单位换算落顶点) - Hierarchy 行 ImGui ID 以 UUID 作用域(重名不冲突、改名不丢选中)
174 lines
5.6 KiB
C++
174 lines
5.6 KiB
C++
//
|
||
// StatsPanel.cpp:遥测与全局设置实现(原 main.cpp Scene Debug 搬迁)。
|
||
//
|
||
|
||
#include "StatsPanel.h"
|
||
#include "Engine/ECS/Components.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();
|
||
}
|
||
|
||
// ---- Scene:动画时钟冻结(沙盒 spinners 用)----
|
||
if (ctx.pauseAnim != nullptr)
|
||
{
|
||
ImGui::Checkbox("Pause Animation", ctx.pauseAnim);
|
||
}
|
||
|
||
// ---- 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));
|
||
}
|
||
}
|
||
|
||
// ---- 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 / app.GetDeltaTime(),
|
||
static_cast<unsigned long long>(app.GetFrameCount()));
|
||
}
|
||
|
||
ImGui::End();
|
||
}
|