From ff7aef15a2ac33ba2ac0849d28b5f0ce9437b7fd Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Sat, 26 Oct 2024 14:33:14 +0100 Subject: [PATCH 1/3] 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 + .../render/cascaded_shadow_maps/plugin.cpp | 12 +- .../plugin.cpp | 230 +++++++++--------- engine/src/render/deferred_shading/plugin.cpp | 7 +- .../src/render/g_buffer_rasterizer/plugin.cpp | 8 +- engine/src/render/lights/plugin.cpp | 33 +++ engine/src/render/split_screen/plugin.cpp | 11 +- engine/src/render/ssao/plugin.cpp | 7 +- engine/src/tools/debug_camera/plugin.cpp | 16 +- 16 files changed, 246 insertions(+), 141 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 13a420688d..e5a6fbfb35 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -172,6 +172,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/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index 1d0e7717da..53d2848fad 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,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 @@ -38,9 +40,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 +55,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..e829636847 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 @@ -131,134 +132,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, drawsTo, gBuffer] : cameras) - { - if (!camera.active) - { - continue; - } - - for (auto [caster, light, localToWorld] : lights) + .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) { - 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 cf142d51e2..04539858bc 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 @@ -211,15 +212,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/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{}); + } + }); } diff --git a/engine/src/render/split_screen/plugin.cpp b/engine/src/render/split_screen/plugin.cpp index 35871fbca6..a9b938b7f0 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 @@ -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..7fae9d8f32 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 @@ -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..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 @@ -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,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"); @@ -111,23 +113,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 a236f4e77f6c17e15bf26ebf673c401744637361 Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Mon, 11 Nov 2024 18:13:13 +0000 Subject: [PATCH 2/3] feat(engine): implement active component for cameras and light --- .../render/cascaded_shadow_maps/plugin.cpp | 8 +++-- .../plugin.cpp | 12 ++++--- engine/src/render/deferred_shading/plugin.cpp | 31 ++++++++++++++----- engine/src/render/shadow_atlas/plugin.cpp | 6 ++-- .../render/shadow_atlas_rasterizer/plugin.cpp | 10 ++++-- engine/src/render/ssao/plugin.cpp | 7 ----- 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/engine/src/render/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index 53d2848fad..c6bf5c9eb6 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -27,10 +27,14 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) cubos.system("create cascaded shadow maps") .tagged(createCascadedShadowMapsTag) - .call([](const Window& window, Query query, + .call([](const Window& window, Query query, Query cameras) { - for (auto [caster] : query) + for (auto [caster, active] : query) { + if (!active.active) + { + continue; + } // Remove shadow maps for cameras that no longer exist std::vector removedCameras; for (auto& [cameraEntity, shadowMap] : caster.shadowMaps) diff --git a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp index e829636847..b0c873e9cb 100644 --- a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp @@ -134,20 +134,24 @@ void cubos::engine::cascadedShadowMapsRasterizerPlugin(Cubos& cubos) .after(createGBufferTag) .call( [](State& state, const Window& window, const RenderMeshPool& pool, - Query lights, + Query lights, Query cameras, Query meshes) { auto& rd = window->renderDevice(); - for (auto [cameraEntity, cameraLocalToWorld, camera, active, drawsTo, gBuffer] : cameras) + for (auto [cameraEntity, cameraLocalToWorld, camera, CameraActive, drawsTo, gBuffer] : cameras) { - if (!active.active) + if (!CameraActive.active) { continue; } - for (auto [caster, light, localToWorld] : lights) + for (auto [caster, light, localToWorld, lightActive] : lights) { + if (!lightActive.active) + { + continue; + } auto& shadowMap = caster.shadowMaps.at(cameraEntity); // Check if we need to recreate the framebuffer. if (shadowMap->previousCascades != shadowMap->cascades) diff --git a/engine/src/render/deferred_shading/plugin.cpp b/engine/src/render/deferred_shading/plugin.cpp index 04539858bc..a6432e5b70 100644 --- a/engine/src/render/deferred_shading/plugin.cpp +++ b/engine/src/render/deferred_shading/plugin.cpp @@ -207,10 +207,10 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) .tagged(deferredShadingTag) .call([](State& state, const Window& window, const RenderEnvironment& environment, const ShadowAtlas& shadowAtlas, - Query> + Query> directionalLights, - Query pointLights, - Query> spotLights, + Query pointLights, + Query> spotLights, Query targets, Query cameras) { auto& rd = window->renderDevice(); @@ -218,9 +218,9 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) for (auto [targetEnt, hdr, gBuffer, ssao, deferredShading] : targets) { // Find the cameras that draw to the GBuffer. - for (auto [cameraEntity, localToWorld, camera, active, drawsTo] : cameras.pin(1, targetEnt)) + for (auto [cameraEntity, localToWorld, camera, cameraActive, drawsTo] : cameras.pin(1, targetEnt)) { - if (!active.active) + if (!cameraActive.active) { continue; } @@ -257,8 +257,13 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) int directionalLightIndex = 0; Texture2DArray directionalShadowMap = nullptr; - for (auto [lightLocalToWorld, light, caster] : directionalLights) + for (auto [lightLocalToWorld, light, lightActive, caster] : directionalLights) { + if (!lightActive.active) + { + continue; + } + auto& perLight = perScene.directionalLights[perScene.numDirectionalLights++]; perLight.direction = glm::normalize(lightLocalToWorld.mat * glm::vec4(0.0F, 0.0F, 1.0F, 0.0F)); perLight.color = glm::vec4(light.color, 1.0F); @@ -338,8 +343,13 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) directionalLightIndex++; } - for (auto [lightLocalToWorld, light] : pointLights) + for (auto [lightLocalToWorld, light, lightActive] : pointLights) { + if (!lightActive.active) + { + continue; + } + auto& perLight = perScene.pointLights[perScene.numPointLights++]; perLight.position = lightLocalToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); perLight.color = glm::vec4(light.color, 1.0F); @@ -347,8 +357,13 @@ void cubos::engine::deferredShadingPlugin(Cubos& cubos) perLight.range = light.range; } - for (auto [lightLocalToWorld, light, caster] : spotLights) + for (auto [lightLocalToWorld, light, lightActive, caster] : spotLights) { + if (!lightActive.active) + { + continue; + } + auto& perLight = perScene.spotLights[perScene.numSpotLights++]; perLight.position = lightLocalToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); perLight.direction = glm::normalize(lightLocalToWorld.mat * glm::vec4(0.0F, 0.0F, 1.0F, 0.0F)); diff --git a/engine/src/render/shadow_atlas/plugin.cpp b/engine/src/render/shadow_atlas/plugin.cpp index 36aec55a31..f8c8491f87 100644 --- a/engine/src/render/shadow_atlas/plugin.cpp +++ b/engine/src/render/shadow_atlas/plugin.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,7 @@ void cubos::engine::shadowAtlasPlugin(Cubos& cubos) cubos.system("reserve space for shadow casters") .tagged(reserveShadowCastersTag) - .call([](ShadowAtlas& atlas, Query casters) { + .call([](ShadowAtlas& atlas, Query casters) { atlas.slots.clear(); atlas.slotsMap.clear(); atlas.slots.push_back( @@ -46,8 +47,9 @@ void cubos::engine::shadowAtlasPlugin(Cubos& cubos) int id = 1; - for (auto [caster] : casters) + for (auto [caster, active] : casters) { + bool foundSlot = false; caster.baseSettings.id = id++; for (const auto& slot : atlas.slots) diff --git a/engine/src/render/shadow_atlas_rasterizer/plugin.cpp b/engine/src/render/shadow_atlas_rasterizer/plugin.cpp index 93597df459..be4e622772 100644 --- a/engine/src/render/shadow_atlas_rasterizer/plugin.cpp +++ b/engine/src/render/shadow_atlas_rasterizer/plugin.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -124,7 +125,7 @@ void cubos::engine::shadowAtlasRasterizerPlugin(Cubos& cubos) .tagged(drawToShadowAtlasTag) .call([](State& state, const Window& window, const RenderMeshPool& pool, ShadowAtlas& atlas, ShadowAtlasRasterizer& rasterizer, - Query lights, + Query lights, Query meshes) { auto& rd = window->renderDevice(); @@ -159,8 +160,13 @@ void cubos::engine::shadowAtlasRasterizerPlugin(Cubos& cubos) atlas.cleared = true; } - for (auto [caster, light, localToWorld] : lights) + for (auto [caster, light, localToWorld, active] : lights) { + if (!active.active) + { + continue; + } + // Get light viewport auto slot = atlas.slotsMap.at(caster.baseSettings.id); diff --git a/engine/src/render/ssao/plugin.cpp b/engine/src/render/ssao/plugin.cpp index 7fae9d8f32..ad7025c6fc 100644 --- a/engine/src/render/ssao/plugin.cpp +++ b/engine/src/render/ssao/plugin.cpp @@ -11,13 +11,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include #include From 48b13082e47fb04e081b752464c47b9fb6542c9f Mon Sep 17 00:00:00 2001 From: RodrigoVintem Date: Tue, 12 Nov 2024 15:08:15 +0000 Subject: [PATCH 3/3] feat(engine): implement active component for cameras and light --- engine/include/cubos/engine/render/camera/camera.hpp | 2 -- engine/src/render/cascaded_shadow_maps/plugin.cpp | 10 +++++----- .../render/cascaded_shadow_maps_rasterizer/plugin.cpp | 4 ++-- engine/src/render/shadow_atlas/plugin.cpp | 4 ++++ engine/src/tools/debug_camera/plugin.cpp | 1 - 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/engine/include/cubos/engine/render/camera/camera.hpp b/engine/include/cubos/engine/render/camera/camera.hpp index 4f456f574d..80882d348d 100644 --- a/engine/include/cubos/engine/render/camera/camera.hpp +++ b/engine/include/cubos/engine/render/camera/camera.hpp @@ -19,8 +19,6 @@ namespace cubos::engine { CUBOS_REFLECT; - /// @brief Whether the camera is drawing to a target. - /// @brief Projection matrix of the camera. glm::mat4 projection{}; diff --git a/engine/src/render/cascaded_shadow_maps/plugin.cpp b/engine/src/render/cascaded_shadow_maps/plugin.cpp index c6bf5c9eb6..3a9e45dc9d 100644 --- a/engine/src/render/cascaded_shadow_maps/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps/plugin.cpp @@ -27,7 +27,7 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) cubos.system("create cascaded shadow maps") .tagged(createCascadedShadowMapsTag) - .call([](const Window& window, Query query, + .call([](const Window& window, Query query, Query cameras) { for (auto [caster, active] : query) { @@ -44,9 +44,9 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) removedCameras.push_back(cameraEntity); } } - for (auto [entity, camera, active] : cameras) + for (auto [entity, camera, cameraActive] : cameras) { - if (!active.active && caster.shadowMaps.contains(entity)) + if (!cameraActive.active && caster.shadowMaps.contains(entity)) { removedCameras.push_back(entity); } @@ -59,9 +59,9 @@ void cubos::engine::cascadedShadowMapsPlugin(Cubos& cubos) caster.updateShadowMaps(window->renderDevice()); // Create shadow maps for new cameras - for (auto [entity, camera, active] : cameras) + for (auto [entity, camera, cameraActive] : cameras) { - if (active.active && !caster.shadowMaps.contains(entity)) + if (cameraActive.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 b0c873e9cb..3c4ca96b98 100644 --- a/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp +++ b/engine/src/render/cascaded_shadow_maps_rasterizer/plugin.cpp @@ -139,9 +139,9 @@ void cubos::engine::cascadedShadowMapsRasterizerPlugin(Cubos& cubos) Query meshes) { auto& rd = window->renderDevice(); - for (auto [cameraEntity, cameraLocalToWorld, camera, CameraActive, drawsTo, gBuffer] : cameras) + for (auto [cameraEntity, cameraLocalToWorld, camera, cameraActive, drawsTo, gBuffer] : cameras) { - if (!CameraActive.active) + if (!cameraActive.active) { continue; } diff --git a/engine/src/render/shadow_atlas/plugin.cpp b/engine/src/render/shadow_atlas/plugin.cpp index f8c8491f87..ccf9df5e28 100644 --- a/engine/src/render/shadow_atlas/plugin.cpp +++ b/engine/src/render/shadow_atlas/plugin.cpp @@ -49,6 +49,10 @@ void cubos::engine::shadowAtlasPlugin(Cubos& cubos) for (auto [caster, active] : casters) { + if (!active.active) + { + continue; + } bool foundSlot = false; caster.baseSettings.id = id++; diff --git a/engine/src/tools/debug_camera/plugin.cpp b/engine/src/tools/debug_camera/plugin.cpp index b51ac68c9c..7a1128d2b9 100644 --- a/engine/src/tools/debug_camera/plugin.cpp +++ b/engine/src/tools/debug_camera/plugin.cpp @@ -52,7 +52,6 @@ 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{}) .add(PerspectiveCamera{}) .add(Position{{}}) .add(FreeCameraController{