Graphics/GraphicsComponent: Add visibility control

This commit is contained in:
Jérôme Leclercq 2021-11-24 22:07:56 +01:00
parent c9aba016a8
commit d2cfc5fdf5
5 changed files with 105 additions and 5 deletions

View File

@ -21,22 +21,32 @@ namespace Nz
public: public:
struct Renderable; struct Renderable;
GraphicsComponent(); inline GraphicsComponent(bool initialyVisible = true);
GraphicsComponent(const GraphicsComponent&) = default; GraphicsComponent(const GraphicsComponent&) = default;
GraphicsComponent(GraphicsComponent&&) = default; GraphicsComponent(GraphicsComponent&&) = default;
~GraphicsComponent() = default; ~GraphicsComponent() = default;
inline void AttachRenderable(std::shared_ptr<InstancedRenderable> renderable, UInt32 renderMask = 0xFFFFFFFF); inline void AttachRenderable(std::shared_ptr<InstancedRenderable> renderable, UInt32 renderMask = 0xFFFFFFFF);
inline void Clear();
inline void DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable); inline void DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable);
inline const std::vector<Renderable>& GetRenderables() const; inline const std::vector<Renderable>& GetRenderables() const;
inline const WorldInstancePtr& GetWorldInstance() const; inline const WorldInstancePtr& GetWorldInstance() const;
inline void Hide();
inline bool IsVisible() const;
inline void Show(bool show = true);
GraphicsComponent& operator=(const GraphicsComponent&) = default; GraphicsComponent& operator=(const GraphicsComponent&) = default;
GraphicsComponent& operator=(GraphicsComponent&&) = default; GraphicsComponent& operator=(GraphicsComponent&&) = default;
NazaraSignal(OnRenderableAttached, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/); NazaraSignal(OnRenderableAttached, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/);
NazaraSignal(OnRenderableDetach, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/); NazaraSignal(OnRenderableDetach, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/);
NazaraSignal(OnVisibilityUpdate, GraphicsComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
struct Renderable struct Renderable
{ {
@ -47,6 +57,7 @@ namespace Nz
private: private:
std::vector<Renderable> m_renderables; std::vector<Renderable> m_renderables;
WorldInstancePtr m_worldInstance; WorldInstancePtr m_worldInstance;
bool m_isVisible;
}; };
} }

View File

@ -7,7 +7,8 @@
namespace Nz namespace Nz
{ {
inline GraphicsComponent::GraphicsComponent() inline GraphicsComponent::GraphicsComponent(bool initialyVisible) :
m_isVisible(initialyVisible)
{ {
m_worldInstance = std::make_shared<WorldInstance>(); //< FIXME: Use pools m_worldInstance = std::make_shared<WorldInstance>(); //< FIXME: Use pools
} }
@ -21,6 +22,14 @@ namespace Nz
OnRenderableAttached(this, m_renderables.back()); OnRenderableAttached(this, m_renderables.back());
} }
inline void GraphicsComponent::Clear()
{
for (const auto& renderable : m_renderables)
OnRenderableDetach(this, renderable);
m_renderables.clear();
}
inline void GraphicsComponent::DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable) inline void GraphicsComponent::DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable)
{ {
auto it = std::find_if(m_renderables.begin(), m_renderables.end(), [&](const auto& renderableEntry) { return renderableEntry.renderable == renderable; }); auto it = std::find_if(m_renderables.begin(), m_renderables.end(), [&](const auto& renderableEntry) { return renderableEntry.renderable == renderable; });
@ -41,6 +50,25 @@ namespace Nz
{ {
return m_worldInstance; return m_worldInstance;
} }
inline void GraphicsComponent::Hide()
{
return Show(false);
}
inline bool GraphicsComponent::IsVisible() const
{
return m_isVisible;
}
inline void GraphicsComponent::Show(bool show)
{
if (m_isVisible != show)
{
OnVisibilityUpdate(this, show);
m_isVisible = show;
}
}
} }
#include <Nazara/Graphics/DebugOff.hpp> #include <Nazara/Graphics/DebugOff.hpp>

View File

@ -41,6 +41,7 @@ namespace Nz
void OnGraphicsDestroy(entt::registry& registry, entt::entity entity); void OnGraphicsDestroy(entt::registry& registry, entt::entity entity);
void OnNodeDestroy(entt::registry& registry, entt::entity entity); void OnNodeDestroy(entt::registry& registry, entt::entity entity);
void UpdateInstances(entt::registry& registry); void UpdateInstances(entt::registry& registry);
void UpdateVisibility(entt::registry& registry);
struct CameraEntity struct CameraEntity
{ {
@ -51,6 +52,7 @@ namespace Nz
{ {
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached); NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach); NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach);
NazaraSlot(GraphicsComponent, OnVisibilityUpdate, onVisibilityUpdate);
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation); NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
}; };
@ -64,6 +66,8 @@ namespace Nz
std::unique_ptr<FramePipeline> m_pipeline; std::unique_ptr<FramePipeline> m_pipeline;
std::unordered_map<entt::entity, CameraEntity> m_cameraEntities; std::unordered_map<entt::entity, CameraEntity> m_cameraEntities;
std::unordered_map<entt::entity, GraphicsEntity> m_graphicsEntities; std::unordered_map<entt::entity, GraphicsEntity> m_graphicsEntities;
std::unordered_set<entt::entity> m_newlyHiddenEntities;
std::unordered_set<entt::entity> m_newlyVisibleEntities;
}; };
} }

View File

@ -96,6 +96,7 @@ namespace Nz
{ {
viewerData.rebuildDepthPrepass = true; viewerData.rebuildDepthPrepass = true;
viewerData.rebuildForwardPass = true; viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
} }
}); });
@ -118,6 +119,7 @@ namespace Nz
{ {
viewerData.rebuildDepthPrepass = true; viewerData.rebuildDepthPrepass = true;
viewerData.rebuildForwardPass = true; viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
} }
} }
} }
@ -447,6 +449,7 @@ namespace Nz
{ {
viewerData.rebuildDepthPrepass = true; viewerData.rebuildDepthPrepass = true;
viewerData.rebuildForwardPass = true; viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
} }
} }

View File

@ -60,9 +60,12 @@ namespace Nz
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity); GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
NodeComponent& entityNode = registry.get<NodeComponent>(entity); NodeComponent& entityNode = registry.get<NodeComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance(); if (entityGfx.IsVisible())
for (const auto& renderableEntry : entityGfx.GetRenderables()) {
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask); const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_invalidatedWorldNode.insert(entity); m_invalidatedWorldNode.insert(entity);
@ -75,17 +78,38 @@ namespace Nz
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry) graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
{ {
if (!gfx->IsVisible())
return;
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance(); const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask); m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}); });
graphicsEntity.onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry) graphicsEntity.onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
{ {
if (!gfx->IsVisible())
return;
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance(); const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get()); m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}); });
graphicsEntity.onVisibilityUpdate.Connect(entityGfx.OnVisibilityUpdate, [this, entity](GraphicsComponent* /*gfx*/, bool isVisible)
{
if (isVisible)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.insert(entity);
}
else
{
m_newlyHiddenEntities.insert(entity);
m_newlyVisibleEntities.erase(entity);
}
});
}); });
UpdateVisibility(registry);
UpdateInstances(registry); UpdateInstances(registry);
m_pipeline->Render(renderFrame); m_pipeline->Render(renderFrame);
@ -104,6 +128,8 @@ namespace Nz
{ {
m_graphicsEntities.erase(entity); m_graphicsEntities.erase(entity);
m_invalidatedWorldNode.erase(entity); m_invalidatedWorldNode.erase(entity);
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity); GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance(); const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
@ -113,6 +139,9 @@ namespace Nz
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity) void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
{ {
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
if (registry.try_get<CameraComponent>(entity)) if (registry.try_get<CameraComponent>(entity))
OnCameraDestroy(registry, entity); OnCameraDestroy(registry, entity);
@ -146,4 +175,29 @@ namespace Nz
} }
m_invalidatedWorldNode.clear(); m_invalidatedWorldNode.clear();
} }
void RenderSystem::UpdateVisibility(entt::registry& registry)
{
// Unregister drawables for hidden entities
for (entt::entity entity : m_newlyHiddenEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}
m_newlyHiddenEntities.clear();
// Register drawables for newly visible entities
for (entt::entity entity : m_newlyVisibleEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_newlyVisibleEntities.clear();
}
} }