// // Created by atdunbg on 2026/9/20. // // SandboxApp:第一个基于 Application 框架的程序。 // // main 的全部职责:定义一个 Application 派生类并运行它。 // 窗口、渲染器、事件泵、帧计时、场景容器全部由框架管理; // 这里只写"程序逻辑":创建实体、逐帧更新组件、事件响应。 // #include #include #include #include #include #include #include #include #include #include #include #include #include "Engine/ImGui/ImGuiLayer.h" using namespace Engine; using namespace Engine::ECS; class SandboxApp final : public Application { public: SandboxApp() : Application("HelloVulkan", 800, 600) { } protected: // ---- 生命周期 ---- void OnInit() override { Scene& scene = GetScene(); // ImGui 叠加层(框架只做管线桥接,UI 内容全部在这里定义) EnableImGui(); // 模型资产(AssetManager 负责加载/缓存/生命周期,返回句柄) auto backpack = GetAssets().LoadModel("assets/models/backpack/backpack.obj"); // 地面:程序化纯色平面(半边长 15,中心 y=-2) auto ground = GetAssets().CreatePlane(15.0f, 140, 140, 145); m_Ground = scene.CreateEntity("Ground"); m_Ground.AddComponent() .SetPosition(glm::vec3(0.0f, -0.5f, 0.0f)) .Compose(); m_Ground.AddComponent(MeshRendererComponent{ground}); // 相机实体(primary = 当前渲染视角) m_Camera = scene.CreateEntity("MainCamera"); auto& camera = m_Camera.AddComponent(); camera.primary = true; camera.camera.SetPosition(glm::vec3(0.0f, 0.0f, 7.0f)); // 背包实体 × 3(悬浮在地面上方) for (int i = 0; i < 3; ++i) { auto e = scene.CreateEntity("Backpack" + std::to_string(i)); e.AddComponent() .SetPosition(glm::vec3((i - 1) * 1.5f, 0.0f, 0.0f)) .SetScale(glm::vec3(0.5f)) .Compose(); e.AddComponent(MeshRendererComponent{backpack}); m_Spinners.push_back(e); } // 灯光实体(第一个灯 = 阴影光源) m_KeyLight = scene.CreateEntity("KeyLight"); m_KeyLight.AddComponent( LightComponent{glm::vec3(-0.5f, -0.6f, -0.35f), glm::vec4(1.0f, 0.95f, 0.9f, 1.0f)}); scene.CreateEntity("FillLight") .AddComponent( LightComponent{glm::vec3(0.5f, -0.5f, 0.3f), glm::vec4(0.3f, 0.5f, 1.0f, 0.8f)}); } void OnUpdate(f32 deltaTime) override { m_Time += deltaTime; // 相机(WASD/Space/Shift 移动) m_Camera.GetComponent() .camera.Update(GetWindow(), deltaTime); // 旋转动画:编辑 Transform 分量后 Compose 重算 world for (size_t i = 0; i < m_Spinners.size(); ++i) { auto& t = m_Spinners[i].GetComponent(); t.position = glm::vec3((static_cast(i) - 1.0f) * 1.5f, 0.0f, 0.0f); t.rotation.y = m_Time * 60.0f + static_cast(i) * 40.0f; t.scale = glm::vec3(0.5f); t.Compose(); } } // ---- 事件 ---- // ---- 叠加层 UI(唯一允许出现 ImGui 控件的地方)---- void OnRenderOverlay() override { if (!m_OverlayVisible) return; ImGui::ShowDemoWindow(); ImGui::Begin("Scene Debug"); // 阴影光源方向:拖动滑条实时看影子变化 if (auto* light = m_KeyLight.TryGetComponent()) { ImGui::Text("Key Light (shadow caster)"); ImGui::SliderFloat3("direction", &light->direction.x, -1.0f, 1.0f); if (ImGui::Button("reset")) { light->direction = glm::vec3(-0.5f, -0.6f, -0.35f); } } // Tonemap + Bloom 参数(HDR 后处理输出端) auto& renderer = GetRenderer(); ImGui::Separator(); ImGui::Text("Tonemap"); 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); } ImGui::Text("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); } ImGui::Separator(); ImGui::Text("fps: %.1f frame: %llu", 1.0f / GetDeltaTime(), static_cast(GetFrameCount())); ImGui::End(); } void OnKeyPress(const Event& event) override { if (event.key == GLFW_KEY_GRAVE_ACCENT) { m_OverlayVisible = !m_OverlayVisible; // ` 反折叠加层 } if (event.key == GLFW_KEY_F1) { STATS.PrintComparison(); } if (event.key == GLFW_KEY_ESCAPE) { Close(); } } void OnWindowResize(const Event& event) override { ENGINE_INFO("App: window resized to {}x{}", event.width, event.height); } private: EntityHandle m_Camera{}; // Scene::CreateEntity 之前为空 EntityHandle m_Ground{}; EntityHandle m_KeyLight{}; std::vector m_Spinners; bool m_OverlayVisible = true; f32 m_Time = 0.0f; }; int main() { SandboxApp app; try { app.Run(); } catch (const std::exception& e) { ENGINE_FATAL("Exception: {}", e.what()); return -1; } return 0; }