From b2b2d03ae27a204a5820e79639f41b85a10c92f6 Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Sat, 26 Oct 2024 14:33:14 +0100 Subject: [PATCH 1/5] feat(engine): implement active component for cameras and light --- engine/CMakeLists.txt | 2 ++ .../cubos/engine/render/active/active.hpp | 20 +++++++++++ .../cubos/engine/render/active/plugin.hpp | 10 ++++++ .../cubos/engine/render/camera/camera.hpp | 1 - engine/src/render/active/active.cpp | 9 +++++ engine/src/render/active/plugin.cpp | 7 ++++ engine/src/render/camera/camera.cpp | 1 - engine/src/render/camera/plugin.cpp | 13 ++++++++ .../src/render/g_buffer_rasterizer/plugin.cpp | 8 +++-- engine/src/render/lights/plugin.cpp | 33 +++++++++++++++++++ 10 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 engine/include/cubos/engine/render/active/active.hpp create mode 100644 engine/include/cubos/engine/render/active/plugin.hpp create mode 100644 engine/src/render/active/active.cpp create mode 100644 engine/src/render/active/plugin.cpp diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index e29913c7ee..2c083f5fce 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -169,6 +169,8 @@ set(CUBOS_ENGINE_SOURCE "src/render/shadow_atlas_rasterizer/shadow_atlas_rasterizer.cpp" "src/render/cascaded_shadow_maps/plugin.cpp" "src/render/cascaded_shadow_maps_rasterizer/plugin.cpp" + "src/render/active/plugin.cpp" + "src/render/active/active.cpp" "src/tools/settings_inspector/plugin.cpp" "src/tools/selection/plugin.cpp" diff --git a/engine/include/cubos/engine/render/active/active.hpp b/engine/include/cubos/engine/render/active/active.hpp new file mode 100644 index 0000000000..0c121a55a7 --- /dev/null +++ b/engine/include/cubos/engine/render/active/active.hpp @@ -0,0 +1,20 @@ +/// @file +/// @brief Component @ref cubos::engine::Active +/// @ingroup render-active-plugin +#pragma once + +#include + +namespace cubos::engine +{ + /// @brief Component which stores the active state for an entity. + /// @note Added automatically once a specific camera or light is added. + /// @ingroup render-active-plugin + struct Active + { + CUBOS_REFLECT; + + /// @brief Whether the entity is active. + bool active = true; + }; +} // namespace cubos::engine \ No newline at end of file diff --git a/engine/include/cubos/engine/render/active/plugin.hpp b/engine/include/cubos/engine/render/active/plugin.hpp new file mode 100644 index 0000000000..c1b429fe08 --- /dev/null +++ b/engine/include/cubos/engine/render/active/plugin.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +#include + +namespace cubos::engine +{ + CUBOS_ENGINE_API void activePlugin(Cubos& cubos); +} \ No newline at end of file diff --git a/engine/include/cubos/engine/render/camera/camera.hpp b/engine/include/cubos/engine/render/camera/camera.hpp index 4b27bedcd2..4f456f574d 100644 --- a/engine/include/cubos/engine/render/camera/camera.hpp +++ b/engine/include/cubos/engine/render/camera/camera.hpp @@ -20,7 +20,6 @@ namespace cubos::engine CUBOS_REFLECT; /// @brief Whether the camera is drawing to a target. - bool active{true}; /// @brief Projection matrix of the camera. glm::mat4 projection{}; diff --git a/engine/src/render/active/active.cpp b/engine/src/render/active/active.cpp new file mode 100644 index 0000000000..52fd47511e --- /dev/null +++ b/engine/src/render/active/active.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include + +CUBOS_REFLECT_IMPL(cubos::engine::Active) +{ + return core::ecs::TypeBuilder("cubos::engine::Active").withField("active", &Active::active).build(); +} \ No newline at end of file diff --git a/engine/src/render/active/plugin.cpp b/engine/src/render/active/plugin.cpp new file mode 100644 index 0000000000..8af296286d --- /dev/null +++ b/engine/src/render/active/plugin.cpp @@ -0,0 +1,7 @@ +#include +#include + +void cubos::engine::activePlugin(Cubos& cubos) +{ + cubos.component(); +} \ No newline at end of file diff --git a/engine/src/render/camera/camera.cpp b/engine/src/render/camera/camera.cpp index 733dd10962..eee21701fb 100644 --- a/engine/src/render/camera/camera.cpp +++ b/engine/src/render/camera/camera.cpp @@ -7,7 +7,6 @@ CUBOS_REFLECT_IMPL(cubos::engine::Camera) { return core::ecs::TypeBuilder("cubos::engine::Camera") - .withField("active", &Camera::active) .withField("projection", &Camera::projection) .withField("zNear", &Camera::zNear) .withField("zFar", &Camera::zFar) diff --git a/engine/src/render/camera/plugin.cpp b/engine/src/render/camera/plugin.cpp index efb7b69027..c6fd170ccd 100644 --- a/engine/src/render/camera/plugin.cpp +++ b/engine/src/render/camera/plugin.cpp @@ -1,5 +1,7 @@ #include +#include +#include #include #include #include @@ -13,6 +15,7 @@ using namespace cubos::engine; void cubos::engine::cameraPlugin(Cubos& cubos) { cubos.depends(renderTargetPlugin); + cubos.depends(activePlugin); cubos.component(); cubos.component(); @@ -20,6 +23,16 @@ void cubos::engine::cameraPlugin(Cubos& cubos) cubos.relation(); + cubos.observer("add active component on add Camera") + .onAdd() + .without() + .call([](Commands cmds, Query query) { + for (auto [ent] : query) + { + cmds.add(ent, Active{}); + } + }); + cubos.observer("add Camera on add PerspectiveCamera") .onAdd() .without() diff --git a/engine/src/render/g_buffer_rasterizer/plugin.cpp b/engine/src/render/g_buffer_rasterizer/plugin.cpp index 84e4f65721..9b1a1e753c 100644 --- a/engine/src/render/g_buffer_rasterizer/plugin.cpp +++ b/engine/src/render/g_buffer_rasterizer/plugin.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include @@ -145,7 +147,7 @@ void cubos::engine::gBufferRasterizerPlugin(Cubos& cubos) .with() .related() .call([](State& state, const Window& window, const RenderMeshPool& pool, const RenderPalette& palette, - Assets& assets, Query cameras, + Assets& assets, Query cameras, Query targets, Query meshes) { auto& rd = window->renderDevice(); @@ -233,10 +235,10 @@ void cubos::engine::gBufferRasterizerPlugin(Cubos& cubos) } // Find the active cameras for this target. - for (auto [cameraLocalToWorld, camera, drawsTo] : cameras.pin(1, ent)) + for (auto [cameraLocalToWorld, camera, active, drawsTo] : cameras.pin(1, ent)) { // Skip inactive cameras. - if (!camera.active) + if (!active.active) { continue; } diff --git a/engine/src/render/lights/plugin.cpp b/engine/src/render/lights/plugin.cpp index e147146ca0..b24acb07f7 100644 --- a/engine/src/render/lights/plugin.cpp +++ b/engine/src/render/lights/plugin.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -7,8 +9,39 @@ void cubos::engine::lightsPlugin(Cubos& cubos) { cubos.resource(); + cubos.depends(activePlugin); cubos.component(); cubos.component(); cubos.component(); + + cubos.observer("add active component on add DirectionalLight") + .onAdd() + .without() + .call([](Commands cmds, Query query) { + for (auto [ent] : query) + { + cmds.add(ent, Active{}); + } + }); + + cubos.observer("add active component on add PointLight") + .onAdd() + .without() + .call([](Commands cmds, Query query) { + for (auto [ent] : query) + { + cmds.add(ent, Active{}); + } + }); + + cubos.observer("add active component on add SpotLight") + .onAdd() + .without() + .call([](Commands cmds, Query query) { + for (auto [ent] : query) + { + cmds.add(ent, Active{}); + } + }); } From 3784d4e521c139d3e8629f471ac956bf5e1c2922 Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Fri, 8 Nov 2024 20:34:19 +0000 Subject: [PATCH 2/5] feat(engine): implement active component for cameras and light --- engine/src/render/cascaded_shadow_maps/plugin.cpp | 11 ++++++----- .../cascaded_shadow_maps_rasterizer/plugin.cpp | 7 ++++--- engine/src/render/deferred_shading/plugin.cpp | 8 +++++--- engine/src/render/split_screen/plugin.cpp | 11 ++++++----- engine/src/render/ssao/plugin.cpp | 7 ++++--- engine/src/tools/debug_camera/plugin.cpp | 15 ++++++++------- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/engine/src/render/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index 1d0e7717da..d57ea0ae87 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using cubos::core::io::Window; @@ -26,7 +27,7 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) cubos.system("create cascaded shadow maps") .tagged(createCascadedShadowMapsTag) - .call([](const Window& window, Query query, Query cameras) { + .call([](const Window& window, Query query, Query cameras) { for (auto [caster] : query) { // Remove shadow maps for cameras that no longer exist @@ -38,9 +39,9 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) removedCameras.push_back(cameraEntity); } } - for (auto [entity, camera] : cameras) + for (auto [entity, camera, active] : cameras) { - if (!camera.active && caster.shadowMaps.contains(entity)) + if (!active.active && caster.shadowMaps.contains(entity)) { removedCameras.push_back(entity); } @@ -53,9 +54,9 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) caster.updateShadowMaps(window->renderDevice()); // Create shadow maps for new cameras - for (auto [entity, camera] : cameras) + for (auto [entity, camera, active] : cameras) { - if (camera.active && !caster.shadowMaps.contains(entity)) + if (active.active && !caster.shadowMaps.contains(entity)) { caster.shadowMaps[entity] = std::make_shared(); caster.shadowMaps[entity]->resize(window->renderDevice(), caster.size, diff --git a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp index 2d9c0dcfb9..60aca81861 100644 --- a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace cubos::core::gl; using cubos::core::io::Window; @@ -133,13 +134,13 @@ void cubos::engine::cascadedShadowMapsRasterizerPlugin(Cubos& cubos) .after(createGBufferTag) .call([](State& state, const Window& window, const RenderMeshPool& pool, Query lights, - Query cameras, + Query cameras, Query meshes) { auto& rd = window->renderDevice(); - for (auto [cameraEntity, cameraLocalToWorld, camera, drawsTo, gBuffer] : cameras) + for (auto [cameraEntity, cameraLocalToWorld, camera, active ,drawsTo, gBuffer] : cameras) { - if (!camera.active) + if (!active.active) { continue; } diff --git a/engine/src/render/deferred_shading/plugin.cpp b/engine/src/render/deferred_shading/plugin.cpp index cf142d51e2..aa4e270e94 100644 --- a/engine/src/render/deferred_shading/plugin.cpp +++ b/engine/src/render/deferred_shading/plugin.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include + using cubos::core::gl::AddressMode; using cubos::core::gl::ConstantBuffer; using cubos::core::gl::FramebufferDesc; @@ -211,15 +213,15 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) Query pointLights, Query> spotLights, Query targets, - Query cameras) { + Query cameras) { auto& rd = window->renderDevice(); for (auto [targetEnt, hdr, gBuffer, ssao, deferredShading] : targets) { // Find the cameras that draw to the GBuffer. - for (auto [cameraEntity, localToWorld, camera, drawsTo] : cameras.pin(1, targetEnt)) + for (auto [cameraEntity, localToWorld, camera, active, drawsTo] : cameras.pin(1, targetEnt)) { - if (!camera.active) + if (!active.active) { continue; } diff --git a/engine/src/render/split_screen/plugin.cpp b/engine/src/render/split_screen/plugin.cpp index 35871fbca6..2bf11e9daf 100644 --- a/engine/src/render/split_screen/plugin.cpp +++ b/engine/src/render/split_screen/plugin.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace cubos::engine; @@ -63,18 +64,18 @@ void cubos::engine::splitScreenPlugin(Cubos& cubos) cubos.system("split screen for each DrawsTo relation") .tagged(splitScreenTag) .call([](Query targets, - Query cameras) { + Query cameras) { for (auto [targetEnt, target] : targets) { int cameraCount = 0; // Find the cameras that draw to the target. - for (auto [localToWorld, camera, drawsTo, splitScreen] : cameras.pin(1, targetEnt)) + for (auto [localToWorld, camera, active, drawsTo, splitScreen] : cameras.pin(1, targetEnt)) { // Ignore unused argument warnings (void)splitScreen; - if (!camera.active) + if (!active.active) { continue; } @@ -88,12 +89,12 @@ void cubos::engine::splitScreenPlugin(Cubos& cubos) setViewportCameras({0, 0}, target.size, cameraCount, positions.begin(), sizes.begin()); unsigned long i = 0; - for (auto [localToWorld, camera, drawsTo, splitScreen] : cameras.pin(1, targetEnt)) + for (auto [localToWorld, camera, active ,drawsTo, splitScreen] : cameras.pin(1, targetEnt)) { // Ignore unused argument warnings (void)splitScreen; - if (!camera.active) + if (!active.active) { continue; } diff --git a/engine/src/render/ssao/plugin.cpp b/engine/src/render/ssao/plugin.cpp index a105ba0021..d5f9dfa746 100644 --- a/engine/src/render/ssao/plugin.cpp +++ b/engine/src/render/ssao/plugin.cpp @@ -22,6 +22,7 @@ #include #include #include +#include using namespace cubos::core::gl; using cubos::core::io::Window; @@ -146,7 +147,7 @@ void cubos::engine::ssaoPlugin(Cubos& cubos) cubos.system("apply SSAO to the GBuffer and output to the SSAO texture") .tagged(drawToSSAOTag) .call([](State& state, const Window& window, Query targets, - Query cameras) { + Query cameras) { auto& rd = window->renderDevice(); for (auto [targetEnt, gBuffer, ssao] : targets) @@ -188,9 +189,9 @@ void cubos::engine::ssaoPlugin(Cubos& cubos) } // Find the cameras that draw to the SSAO target. - for (auto [localToWorld, camera, drawsTo] : cameras.pin(1, targetEnt)) + for (auto [localToWorld, camera, active, drawsTo] : cameras.pin(1, targetEnt)) { - if (!camera.active) + if (!active.active) { continue; } diff --git a/engine/src/tools/debug_camera/plugin.cpp b/engine/src/tools/debug_camera/plugin.cpp index 310b6cc7fd..6f1f642314 100644 --- a/engine/src/tools/debug_camera/plugin.cpp +++ b/engine/src/tools/debug_camera/plugin.cpp @@ -15,6 +15,7 @@ #include #include #include +#include using namespace cubos::core::io; using cubos::core::ecs::Entity; @@ -51,7 +52,7 @@ void cubos::engine::debugCameraPlugin(Cubos& cubos) cubos.startupSystem("create Debug Camera").call([](Commands commands, State& debugCamera) { debugCamera.entity = commands.create() .named("debug-camera") - .add(Camera{.active = false}) + .add(Camera{}) .add(PerspectiveCamera{}) .add(Position{{}}) .add(FreeCameraController{ @@ -90,7 +91,7 @@ void cubos::engine::debugCameraPlugin(Cubos& cubos) cubos.system("update Debug Camera") .tagged(imguiTag) .onlyIf([](Toolbox& toolbox) { return toolbox.isOpen("Debug Camera"); }) - .call([](State& state, Commands cmds, Query cameras, + .call([](State& state, Commands cmds, Query cameras, Query targets) { ImGui::Begin("Debug Camera"); @@ -111,23 +112,23 @@ void cubos::engine::debugCameraPlugin(Cubos& cubos) } } - for (auto [cameraEnt, camera, _1, target] : cameras) + for (auto [cameraEnt, camera, active,_1, target] : cameras) { if (target.framebuffer == nullptr) { if (cameraEnt == state.entity) { - camera.active = state.active; + active.active = state.active; } - else if (camera.active && state.active) + else if (active.active && state.active) { state.deactivated.insert(cameraEnt); - camera.active = false; + active.active = false; } else if (!state.active && state.deactivated.contains(cameraEnt)) { state.deactivated.erase(cameraEnt); - camera.active = true; + active.active = true; } } } From 3347901eb0686e111ce8875dba533a78ab65176f Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Fri, 8 Nov 2024 20:35:27 +0000 Subject: [PATCH 3/5] feat(engine): implement active component for cameras and light --- .../render/cascaded_shadow_maps/plugin.cpp | 6 +- .../plugin.cpp | 232 +++++++++--------- engine/src/render/deferred_shading/plugin.cpp | 1 - engine/src/render/split_screen/plugin.cpp | 7 +- engine/src/render/ssao/plugin.cpp | 5 +- engine/src/tools/debug_camera/plugin.cpp | 7 +- 6 files changed, 133 insertions(+), 125 deletions(-) diff --git a/engine/src/render/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index d57ea0ae87..dc41516ef7 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -3,13 +3,14 @@ #include #include +#include #include #include #include #include #include #include -#include + using cubos::core::io::Window; @@ -27,7 +28,8 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) cubos.system("create cascaded shadow maps") .tagged(createCascadedShadowMapsTag) - .call([](const Window& window, Query query, Query cameras) { + .call([](const Window& window, Query query, + Query cameras) { for (auto [caster] : query) { // Remove shadow maps for cameras that no longer exist diff --git a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp index 60aca81861..22252fd99b 100644 --- a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -24,7 +25,7 @@ #include #include #include -#include + using namespace cubos::core::gl; using cubos::core::io::Window; @@ -132,134 +133,137 @@ void cubos::engine::cascadedShadowMapsRasterizerPlugin(Cubos& cubos) cubos.system("rasterize to cascaded shadow maps") .tagged(drawToCascadedShadowMapsTag) .after(createGBufferTag) - .call([](State& state, const Window& window, const RenderMeshPool& pool, - Query lights, - Query cameras, - Query meshes) { - auto& rd = window->renderDevice(); - - for (auto [cameraEntity, cameraLocalToWorld, camera, active ,drawsTo, gBuffer] : cameras) - { - if (!active.active) + .call( + [](State& state, const Window& window, const RenderMeshPool& pool, + Query lights, + Query cameras, + Query meshes) { + auto& rd = window->renderDevice(); + + for (auto [cameraEntity, cameraLocalToWorld, camera, active, drawsTo, gBuffer] : cameras) { - continue; - } - - for (auto [caster, light, localToWorld] : lights) - { - auto& shadowMap = caster.shadowMaps.at(cameraEntity); - // Check if we need to recreate the framebuffer. - if (shadowMap->previousCascades != shadowMap->cascades) + if (!active.active) { - // Store textures so we can check if they change in the next frame. - shadowMap->previousCascades = shadowMap->cascades; - - // Create the framebuffer. - FramebufferDesc desc{}; - desc.targetCount = 0; - desc.depthStencil.setTexture2DArrayTarget(shadowMap->cascades); - shadowMap->framebuffer = rd.createFramebuffer(desc); + continue; } - // Bind the framebuffer and set the viewport. - rd.setFramebuffer(shadowMap->framebuffer); - rd.setViewport(0, 0, static_cast(caster.getCurrentSize().x), - static_cast(caster.getCurrentSize().y)); - - // Set the raster and depth-stencil states. - rd.setRasterState(state.rasterState); - rd.setBlendState(nullptr); - rd.setDepthStencilState(state.depthStencilState); - - // Clear - rd.clearDepth(1.0F); - - // Send the PerScene data to the GPU. - PerScene perScene; - - float maxDistance = caster.maxDistance == 0 ? camera.zFar : caster.maxDistance; - float nearDistance = caster.nearDistance == 0 ? camera.zNear : caster.nearDistance; - int numCascades = static_cast(caster.getCurrentSplitDistances().size()) + 1; - for (int i = 0; i < numCascades; i++) + for (auto [caster, light, localToWorld] : lights) { - float near = glm::mix( - nearDistance, maxDistance, - i == 0 ? 0.0F : caster.getCurrentSplitDistances().at(static_cast(i) - 1)); - float far = glm::mix(nearDistance, maxDistance, - i == numCascades - 1 - ? 1.0F - : caster.getCurrentSplitDistances().at(static_cast(i))); - - auto cameraView = glm::inverse(cameraLocalToWorld.mat); - - std::vector cameraFrustumCorners; - core::geom::getCameraFrustumCorners(cameraView, camera.projection, near, far, - cameraFrustumCorners); - - glm::vec3 center = {0.0F, 0.0F, 0.0F}; - for (const auto& corner : cameraFrustumCorners) + auto& shadowMap = caster.shadowMaps.at(cameraEntity); + // Check if we need to recreate the framebuffer. + if (shadowMap->previousCascades != shadowMap->cascades) { - center += glm::vec3(corner); + // Store textures so we can check if they change in the next frame. + shadowMap->previousCascades = shadowMap->cascades; + + // Create the framebuffer. + FramebufferDesc desc{}; + desc.targetCount = 0; + desc.depthStencil.setTexture2DArrayTarget(shadowMap->cascades); + shadowMap->framebuffer = rd.createFramebuffer(desc); } - center /= cameraFrustumCorners.size(); - auto lightDir = glm::vec3(localToWorld.mat[2]); - auto view = glm::lookAt(center - lightDir, center, glm::vec3(0.0F, 1.0F, 0.0F)); + // Bind the framebuffer and set the viewport. + rd.setFramebuffer(shadowMap->framebuffer); + rd.setViewport(0, 0, static_cast(caster.getCurrentSize().x), + static_cast(caster.getCurrentSize().y)); - // Transform frustum corners to light view space - for (auto& corner : cameraFrustumCorners) - { - corner = view * corner; - } - // Find minimum/maximum coordinates along each axis - float minX = std::numeric_limits::max(); - float maxX = std::numeric_limits::lowest(); - float minY = std::numeric_limits::max(); - float maxY = std::numeric_limits::lowest(); - float minZ = std::numeric_limits::max(); - float maxZ = std::numeric_limits::lowest(); - for (const auto& corner : cameraFrustumCorners) + // Set the raster and depth-stencil states. + rd.setRasterState(state.rasterState); + rd.setBlendState(nullptr); + rd.setDepthStencilState(state.depthStencilState); + + // Clear + rd.clearDepth(1.0F); + + // Send the PerScene data to the GPU. + PerScene perScene; + + float maxDistance = caster.maxDistance == 0 ? camera.zFar : caster.maxDistance; + float nearDistance = caster.nearDistance == 0 ? camera.zNear : caster.nearDistance; + int numCascades = static_cast(caster.getCurrentSplitDistances().size()) + 1; + for (int i = 0; i < numCascades; i++) { - minX = std::min(minX, corner.x); - maxX = std::max(maxX, corner.x); - minY = std::min(minY, corner.y); - maxY = std::max(maxY, corner.y); - minZ = std::min(minZ, corner.z); - maxZ = std::max(maxZ, corner.z); + float near = glm::mix( + nearDistance, maxDistance, + i == 0 ? 0.0F + : caster.getCurrentSplitDistances().at(static_cast(i) - 1)); + float far = + glm::mix(nearDistance, maxDistance, + i == numCascades - 1 + ? 1.0F + : caster.getCurrentSplitDistances().at(static_cast(i))); + + auto cameraView = glm::inverse(cameraLocalToWorld.mat); + + std::vector cameraFrustumCorners; + core::geom::getCameraFrustumCorners(cameraView, camera.projection, near, far, + cameraFrustumCorners); + + glm::vec3 center = {0.0F, 0.0F, 0.0F}; + for (const auto& corner : cameraFrustumCorners) + { + center += glm::vec3(corner); + } + center /= cameraFrustumCorners.size(); + + auto lightDir = glm::vec3(localToWorld.mat[2]); + auto view = glm::lookAt(center - lightDir, center, glm::vec3(0.0F, 1.0F, 0.0F)); + + // Transform frustum corners to light view space + for (auto& corner : cameraFrustumCorners) + { + corner = view * corner; + } + // Find minimum/maximum coordinates along each axis + float minX = std::numeric_limits::max(); + float maxX = std::numeric_limits::lowest(); + float minY = std::numeric_limits::max(); + float maxY = std::numeric_limits::lowest(); + float minZ = std::numeric_limits::max(); + float maxZ = std::numeric_limits::lowest(); + for (const auto& corner : cameraFrustumCorners) + { + minX = std::min(minX, corner.x); + maxX = std::max(maxX, corner.x); + minY = std::min(minY, corner.y); + maxY = std::max(maxY, corner.y); + minZ = std::min(minZ, corner.z); + maxZ = std::max(maxZ, corner.z); + } + + // Expand space between Z planes, so that objects outside the frustum can cast shadows + minZ -= std::abs(minZ) * 0.5F; + maxZ += std::abs(maxZ) * 0.5F; + auto proj = glm::ortho(minX, maxX, minY, maxY, -maxZ, -minZ); + perScene.lightViewProj[i] = proj * view; + perScene.numCascades = numCascades; } + state.perSceneCB->fill(&perScene, sizeof(perScene)); - // Expand space between Z planes, so that objects outside the frustum can cast shadows - minZ -= std::abs(minZ) * 0.5F; - maxZ += std::abs(maxZ) * 0.5F; - auto proj = glm::ortho(minX, maxX, minY, maxY, -maxZ, -minZ); - perScene.lightViewProj[i] = proj * view; - perScene.numCascades = numCascades; - } - state.perSceneCB->fill(&perScene, sizeof(perScene)); - - // Bind the shader, vertex array and uniform buffer. - rd.setShaderPipeline(state.pipeline); - rd.setVertexArray(state.vertexArray); - state.perSceneBP->bind(state.perSceneCB); - state.perMeshBP->bind(state.perMeshCB); + // Bind the shader, vertex array and uniform buffer. + rd.setShaderPipeline(state.pipeline); + rd.setVertexArray(state.vertexArray); + state.perSceneBP->bind(state.perSceneCB); + state.perMeshBP->bind(state.perMeshCB); - // Iterate over all mesh buckets and issue draw calls. - for (auto [meshEnt, meshLocalToWorld, mesh, grid] : meshes) - { - // Send the PerMesh data to the GPU. - PerMesh perMesh{ - .model = meshLocalToWorld.mat * glm::translate(glm::mat4(1.0F), grid.offset), - }; - state.perMeshCB->fill(&perMesh, sizeof(perMesh)); - - // Iterate over the buckets of the mesh (it may be split over many of them). - for (auto bucket = mesh.firstBucketId; bucket != RenderMeshPool::BucketId::Invalid; - bucket = pool.next(bucket)) + // Iterate over all mesh buckets and issue draw calls. + for (auto [meshEnt, meshLocalToWorld, mesh, grid] : meshes) { - rd.drawTriangles(pool.bucketSize() * bucket.inner, pool.vertexCount(bucket)); + // Send the PerMesh data to the GPU. + PerMesh perMesh{ + .model = meshLocalToWorld.mat * glm::translate(glm::mat4(1.0F), grid.offset), + }; + state.perMeshCB->fill(&perMesh, sizeof(perMesh)); + + // Iterate over the buckets of the mesh (it may be split over many of them). + for (auto bucket = mesh.firstBucketId; bucket != RenderMeshPool::BucketId::Invalid; + bucket = pool.next(bucket)) + { + rd.drawTriangles(pool.bucketSize() * bucket.inner, pool.vertexCount(bucket)); + } } } } - } - }); + }); } diff --git a/engine/src/render/deferred_shading/plugin.cpp b/engine/src/render/deferred_shading/plugin.cpp index aa4e270e94..04539858bc 100644 --- a/engine/src/render/deferred_shading/plugin.cpp +++ b/engine/src/render/deferred_shading/plugin.cpp @@ -30,7 +30,6 @@ #include #include - using cubos::core::gl::AddressMode; using cubos::core::gl::ConstantBuffer; using cubos::core::gl::FramebufferDesc; diff --git a/engine/src/render/split_screen/plugin.cpp b/engine/src/render/split_screen/plugin.cpp index 2bf11e9daf..9697c929aa 100644 --- a/engine/src/render/split_screen/plugin.cpp +++ b/engine/src/render/split_screen/plugin.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,7 +10,7 @@ #include #include #include -#include + using namespace cubos::engine; @@ -64,7 +65,7 @@ void cubos::engine::splitScreenPlugin(Cubos& cubos) cubos.system("split screen for each DrawsTo relation") .tagged(splitScreenTag) .call([](Query targets, - Query cameras) { + Query cameras) { for (auto [targetEnt, target] : targets) { int cameraCount = 0; @@ -89,7 +90,7 @@ void cubos::engine::splitScreenPlugin(Cubos& cubos) setViewportCameras({0, 0}, target.size, cameraCount, positions.begin(), sizes.begin()); unsigned long i = 0; - for (auto [localToWorld, camera, active ,drawsTo, splitScreen] : cameras.pin(1, targetEnt)) + for (auto [localToWorld, camera, active, drawsTo, splitScreen] : cameras.pin(1, targetEnt)) { // Ignore unused argument warnings (void)splitScreen; diff --git a/engine/src/render/ssao/plugin.cpp b/engine/src/render/ssao/plugin.cpp index d5f9dfa746..a7053798b6 100644 --- a/engine/src/render/ssao/plugin.cpp +++ b/engine/src/render/ssao/plugin.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -22,7 +23,7 @@ #include #include #include -#include + using namespace cubos::core::gl; using cubos::core::io::Window; @@ -147,7 +148,7 @@ void cubos::engine::ssaoPlugin(Cubos& cubos) cubos.system("apply SSAO to the GBuffer and output to the SSAO texture") .tagged(drawToSSAOTag) .call([](State& state, const Window& window, Query targets, - Query cameras) { + Query cameras) { auto& rd = window->renderDevice(); for (auto [targetEnt, gBuffer, ssao] : targets) diff --git a/engine/src/tools/debug_camera/plugin.cpp b/engine/src/tools/debug_camera/plugin.cpp index 6f1f642314..b51ac68c9c 100644 --- a/engine/src/tools/debug_camera/plugin.cpp +++ b/engine/src/tools/debug_camera/plugin.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include #include -#include using namespace cubos::core::io; using cubos::core::ecs::Entity; @@ -91,7 +91,8 @@ void cubos::engine::debugCameraPlugin(Cubos& cubos) cubos.system("update Debug Camera") .tagged(imguiTag) .onlyIf([](Toolbox& toolbox) { return toolbox.isOpen("Debug Camera"); }) - .call([](State& state, Commands cmds, Query cameras, + .call([](State& state, Commands cmds, + Query cameras, Query targets) { ImGui::Begin("Debug Camera"); @@ -112,7 +113,7 @@ void cubos::engine::debugCameraPlugin(Cubos& cubos) } } - for (auto [cameraEnt, camera, active,_1, target] : cameras) + for (auto [cameraEnt, camera, active, _1, target] : cameras) { if (target.framebuffer == nullptr) { From da903313485d9ae440115a0c39c59d5970ede3e6 Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Fri, 8 Nov 2024 20:39:31 +0000 Subject: [PATCH 4/5] feat(engine): implement active component for cameras and light --- engine/src/render/cascaded_shadow_maps/plugin.cpp | 1 - engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/engine/src/render/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index dc41516ef7..53d2848fad 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -11,7 +11,6 @@ #include #include - using cubos::core::io::Window; CUBOS_DEFINE_TAG(cubos::engine::createCascadedShadowMapsTag); diff --git a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp index 22252fd99b..e829636847 100644 --- a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp @@ -26,7 +26,6 @@ #include #include - using namespace cubos::core::gl; using cubos::core::io::Window; using cubos::engine::RenderMeshVertex; From 84e161d0ccc460c06a91fb5c0ea3f9abfcb0ad18 Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Fri, 8 Nov 2024 21:01:35 +0000 Subject: [PATCH 5/5] feat(engine): implement active component for cameras and light --- engine/src/render/split_screen/plugin.cpp | 1 - engine/src/render/ssao/plugin.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/engine/src/render/split_screen/plugin.cpp b/engine/src/render/split_screen/plugin.cpp index 9697c929aa..a9b938b7f0 100644 --- a/engine/src/render/split_screen/plugin.cpp +++ b/engine/src/render/split_screen/plugin.cpp @@ -11,7 +11,6 @@ #include #include - using namespace cubos::engine; CUBOS_DEFINE_TAG(cubos::engine::splitScreenTag); diff --git a/engine/src/render/ssao/plugin.cpp b/engine/src/render/ssao/plugin.cpp index a7053798b6..7fae9d8f32 100644 --- a/engine/src/render/ssao/plugin.cpp +++ b/engine/src/render/ssao/plugin.cpp @@ -24,7 +24,6 @@ #include #include - using namespace cubos::core::gl; using cubos::core::io::Window;