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

View File

@ -7,7 +7,8 @@
namespace Nz
{
inline GraphicsComponent::GraphicsComponent()
inline GraphicsComponent::GraphicsComponent(bool initialyVisible) :
m_isVisible(initialyVisible)
{
m_worldInstance = std::make_shared<WorldInstance>(); //< FIXME: Use pools
}
@ -21,6 +22,14 @@ namespace Nz
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)
{
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;
}
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>

View File

@ -41,6 +41,7 @@ namespace Nz
void OnGraphicsDestroy(entt::registry& registry, entt::entity entity);
void OnNodeDestroy(entt::registry& registry, entt::entity entity);
void UpdateInstances(entt::registry& registry);
void UpdateVisibility(entt::registry& registry);
struct CameraEntity
{
@ -51,6 +52,7 @@ namespace Nz
{
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach);
NazaraSlot(GraphicsComponent, OnVisibilityUpdate, onVisibilityUpdate);
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
};
@ -64,6 +66,8 @@ namespace Nz
std::unique_ptr<FramePipeline> m_pipeline;
std::unordered_map<entt::entity, CameraEntity> m_cameraEntities;
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.rebuildForwardPass = true;
viewerData.prepare = true;
}
});
@ -118,6 +119,7 @@ namespace Nz
{
viewerData.rebuildDepthPrepass = true;
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
}
}
@ -447,6 +449,7 @@ namespace Nz
{
viewerData.rebuildDepthPrepass = true;
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
}

View File

@ -60,9 +60,12 @@ namespace Nz
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
if (entityGfx.IsVisible())
{
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_invalidatedWorldNode.insert(entity);
@ -75,17 +78,38 @@ namespace Nz
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
{
if (!gfx->IsVisible())
return;
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
});
graphicsEntity.onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
{
if (!gfx->IsVisible())
return;
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
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);
m_pipeline->Render(renderFrame);
@ -104,6 +128,8 @@ namespace Nz
{
m_graphicsEntities.erase(entity);
m_invalidatedWorldNode.erase(entity);
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
@ -113,6 +139,9 @@ namespace Nz
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
if (registry.try_get<CameraComponent>(entity))
OnCameraDestroy(registry, entity);
@ -146,4 +175,29 @@ namespace Nz
}
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();
}
}