Graphics/RenderSystem: Handle visibility immediatly

This fixes an issue when rendermask/scissor box is updated right after making an entity visible (e.g. widgets)
This commit is contained in:
SirLynix 2023-07-02 14:04:00 +02:00
parent fff4029047
commit 4f3542356d
2 changed files with 63 additions and 112 deletions

View File

@ -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<std::size_t>::max();
@ -132,10 +136,6 @@ namespace Nz
std::unordered_map<entt::entity, GraphicsEntity*> m_graphicsEntities;
std::unordered_map<entt::entity, LightEntity*> m_lightEntities;
std::unordered_map<Skeleton*, SharedSkeleton> m_sharedSkeletonInstances;
std::unordered_set<GraphicsEntity*> m_newlyHiddenGfxEntities;
std::unordered_set<GraphicsEntity*> m_newlyVisibleGfxEntities;
std::unordered_set<LightEntity*> m_newlyHiddenLightEntities;
std::unordered_set<LightEntity*> m_newlyVisibleLightEntities;
std::vector<std::unique_ptr<WindowSwapchain>> m_windowSwapchains;
ElementRendererRegistry m_elementRegistry;
MemoryPool<CameraEntity> m_cameraEntityPool;

View File

@ -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<GraphicsComponent>(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<LightComponent>(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<GraphicsComponent>(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<LightComponent>(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<SkeletonInstance>(skeleton));
});
}
void RenderSystem::UpdateVisibility()
{
// Unregister drawable for hidden entities
for (GraphicsEntity* graphicsEntity : m_newlyHiddenGfxEntities)
{
GraphicsComponent& entityGfx = m_registry.get<GraphicsComponent>(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<GraphicsComponent>(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<LightComponent>(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<LightComponent>(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
}
}