From 4f3542356d039dd7657c5a19244c678b7fb5ef48 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 2 Jul 2023 14:04:00 +0200 Subject: [PATCH] Graphics/RenderSystem: Handle visibility immediatly This fixes an issue when rendermask/scissor box is updated right after making an entity visible (e.g. widgets) --- .../Nazara/Graphics/Systems/RenderSystem.hpp | 10 +- src/Nazara/Graphics/Systems/RenderSystem.cpp | 165 ++++++------------ 2 files changed, 63 insertions(+), 112 deletions(-) diff --git a/include/Nazara/Graphics/Systems/RenderSystem.hpp b/include/Nazara/Graphics/Systems/RenderSystem.hpp index 5a7c7ae3b..28469256e 100644 --- a/include/Nazara/Graphics/Systems/RenderSystem.hpp +++ b/include/Nazara/Graphics/Systems/RenderSystem.hpp @@ -52,6 +52,9 @@ namespace Nz RenderSystem& operator=(RenderSystem&&) = delete; private: + struct GraphicsEntity; + struct LightEntity; + void OnCameraDestroy(entt::registry& registry, entt::entity entity); void OnDisabledConstructed(entt::registry& registry, entt::entity entity); void OnGraphicsDestroy(entt::registry& registry, entt::entity entity); @@ -59,9 +62,10 @@ namespace Nz void OnNodeDestroy(entt::registry& registry, entt::entity entity); void OnSharedSkeletonDestroy(entt::registry& registry, entt::entity entity); void OnSkeletonDestroy(entt::registry& registry, entt::entity entity); + void UpdateGraphicsVisibility(GraphicsEntity* gfxData, GraphicsComponent& gfxComponent, bool isVisible); + void UpdateLightVisibility(LightEntity* gfxData, LightComponent& lightComponent, bool isVisible); void UpdateInstances(); void UpdateObservers(); - void UpdateVisibility(); static constexpr std::size_t NoInstance = std::numeric_limits::max(); @@ -132,10 +136,6 @@ namespace Nz std::unordered_map m_graphicsEntities; std::unordered_map m_lightEntities; std::unordered_map m_sharedSkeletonInstances; - std::unordered_set m_newlyHiddenGfxEntities; - std::unordered_set m_newlyVisibleGfxEntities; - std::unordered_set m_newlyHiddenLightEntities; - std::unordered_set m_newlyVisibleLightEntities; std::vector> m_windowSwapchains; ElementRendererRegistry m_elementRegistry; MemoryPool m_cameraEntityPool; diff --git a/src/Nazara/Graphics/Systems/RenderSystem.cpp b/src/Nazara/Graphics/Systems/RenderSystem.cpp index 68a1e6ff8..46818efb6 100644 --- a/src/Nazara/Graphics/Systems/RenderSystem.cpp +++ b/src/Nazara/Graphics/Systems/RenderSystem.cpp @@ -58,7 +58,6 @@ namespace Nz void RenderSystem::Update(Time /*elapsedTime*/) { UpdateObservers(); - UpdateVisibility(); UpdateInstances(); for (auto& windowPtr : m_windowSwapchains) @@ -109,8 +108,6 @@ namespace Nz m_graphicsEntities.erase(entity); m_invalidatedGfxWorldNode.erase(graphicsEntity); - m_newlyHiddenGfxEntities.erase(graphicsEntity); - m_newlyVisibleGfxEntities.erase(graphicsEntity); GraphicsComponent& entityGfx = m_registry.get(entity); if (entityGfx.IsVisible()) @@ -142,8 +139,6 @@ namespace Nz m_lightEntities.erase(entity); m_invalidatedLightWorldNode.erase(lightEntity); - m_newlyHiddenLightEntities.erase(lightEntity); - m_newlyVisibleLightEntities.erase(lightEntity); LightComponent& entityLight = m_registry.get(entity); if (entityLight.IsVisible()) @@ -221,6 +216,58 @@ namespace Nz graphicsEntity->skeletonInstanceIndex = NoInstance; } + void RenderSystem::UpdateGraphicsVisibility(GraphicsEntity* gfxData, GraphicsComponent& gfxComponent, bool isVisible) + { + if (isVisible) + { + for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex) + { + const auto& renderableEntry = gfxComponent.GetRenderableEntry(renderableIndex); + if (!renderableEntry.renderable) + continue; + + gfxData->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(gfxData->worldInstanceIndex, gfxData->skeletonInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, gfxComponent.GetScissorBox()); + } + } + else + { + for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex) + { + const auto& renderableEntry = gfxComponent.GetRenderableEntry(renderableIndex); + if (!renderableEntry.renderable) + continue; + + m_pipeline->UnregisterRenderable(gfxData->renderableIndices[renderableIndex]); + } + } + } + + void RenderSystem::UpdateLightVisibility(LightEntity* gfxData, LightComponent& lightComponent, bool isVisible) + { + if (isVisible) + { + for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex) + { + const auto& lightEntry = lightComponent.GetLightEntry(renderableIndex); + if (!lightEntry.light) + continue; + + gfxData->lightIndices[renderableIndex] = m_pipeline->RegisterLight(lightEntry.light.get(), lightEntry.renderMask); + } + } + else + { + for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex) + { + const auto& lightEntry = lightComponent.GetLightEntry(lightIndex); + if (!lightEntry.light) + continue; + + m_pipeline->UnregisterLight(gfxData->lightIndices[lightIndex]); + } + } + } + void RenderSystem::UpdateInstances() { for (CameraEntity* cameraEntity : m_invalidatedCameraNode) @@ -344,23 +391,14 @@ namespace Nz } }); - graphicsEntity->onVisibilityUpdate.Connect(entityGfx.OnVisibilityUpdate, [this, graphicsEntity](GraphicsComponent* /*gfx*/, bool isVisible) + graphicsEntity->onVisibilityUpdate.Connect(entityGfx.OnVisibilityUpdate, [this, graphicsEntity](GraphicsComponent* gfx, bool isVisible) { - if (isVisible) - { - m_newlyHiddenGfxEntities.erase(graphicsEntity); - m_newlyVisibleGfxEntities.insert(graphicsEntity); - } - else - { - m_newlyHiddenGfxEntities.insert(graphicsEntity); - m_newlyVisibleGfxEntities.erase(graphicsEntity); - } + UpdateGraphicsVisibility(graphicsEntity, *gfx, isVisible); }); m_invalidatedGfxWorldNode.insert(graphicsEntity); if (entityGfx.IsVisible()) - m_newlyVisibleGfxEntities.insert(graphicsEntity); + UpdateGraphicsVisibility(graphicsEntity, m_registry.get(entity), true); assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end()); m_graphicsEntities.emplace(entity, graphicsEntity); @@ -402,33 +440,15 @@ namespace Nz m_pipeline->UnregisterLight(lightEntity->lightIndices[lightIndex]); }); - lightEntity->onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, lightEntity](LightComponent* /*light*/, bool isVisible) + lightEntity->onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, lightEntity](LightComponent* light, bool isVisible) { - if (isVisible) - { - m_newlyHiddenLightEntities.erase(lightEntity); - m_newlyVisibleLightEntities.insert(lightEntity); - } - else - { - m_newlyHiddenLightEntities.insert(lightEntity); - m_newlyVisibleLightEntities.erase(lightEntity); - } + UpdateLightVisibility(lightEntity, *light, isVisible); }); m_invalidatedLightWorldNode.insert(lightEntity); if (entityLight.IsVisible()) - { - for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex) - { - const auto& lightEntry = entityLight.GetLightEntry(lightIndex); - if (!lightEntry.light) - continue; - - lightEntity->lightIndices[lightIndex] = m_pipeline->RegisterLight(lightEntry.light.get(), lightEntry.renderMask); - } - } + UpdateLightVisibility(lightEntity, m_registry.get(entity), true); assert(m_lightEntities.find(entity) == m_lightEntities.end()); m_lightEntities.emplace(entity, lightEntity); @@ -466,73 +486,4 @@ namespace Nz graphicsEntity->skeletonInstanceIndex = m_pipeline->RegisterSkeleton(std::make_shared(skeleton)); }); } - - void RenderSystem::UpdateVisibility() - { - // Unregister drawable for hidden entities - for (GraphicsEntity* graphicsEntity : m_newlyHiddenGfxEntities) - { - GraphicsComponent& entityGfx = m_registry.get(graphicsEntity->entity); - - for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex) - { - const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex); - if (!renderableEntry.renderable) - continue; - - m_pipeline->UnregisterRenderable(graphicsEntity->renderableIndices[renderableIndex]); - } - } - m_newlyHiddenGfxEntities.clear(); - - // Register drawable for newly visible entities - for (GraphicsEntity* graphicsEntity : m_newlyVisibleGfxEntities) - { - GraphicsComponent& entityGfx = m_registry.get(graphicsEntity->entity); - - for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex) - { - const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex); - if (!renderableEntry.renderable) - continue; - - graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, graphicsEntity->skeletonInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox()); - } - } - m_newlyVisibleGfxEntities.clear(); - - // Unregister lights for hidden entities - for (LightEntity* lightEntity : m_newlyHiddenLightEntities) - { - LightComponent& entityLights = m_registry.get(lightEntity->entity); - - for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex) - { - const auto& lightEntry = entityLights.GetLightEntry(lightIndex); - if (!lightEntry.light) - continue; - - m_pipeline->UnregisterLight(lightEntity->lightIndices[lightIndex]); - } - } - m_newlyHiddenLightEntities.clear(); - - // Register lights for newly visible entities - for (LightEntity* lightEntity : m_newlyVisibleLightEntities) - { - LightComponent& entityLights = m_registry.get(lightEntity->entity); - - for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex) - { - const auto& lightEntry = entityLights.GetLightEntry(renderableIndex); - if (!lightEntry.light) - continue; - - lightEntity->lightIndices[renderableIndex] = m_pipeline->RegisterLight(lightEntry.light.get(), lightEntry.renderMask); - } - } - m_newlyVisibleLightEntities.clear(); - - //FIXME: Handle light visibility - } }