Components/GraphicsComponent: Watch every used material to handle reflective information

This commit is contained in:
Lynix 2017-03-28 23:36:08 +02:00
parent 5b236ab09a
commit 6851428c3c
5 changed files with 163 additions and 57 deletions

View File

@ -12,6 +12,7 @@
#include <Nazara/Graphics/InstancedRenderable.hpp> #include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Utility/Node.hpp> #include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp> #include <NDK/Component.hpp>
#include <unordered_map>
namespace Ndk namespace Ndk
{ {
@ -34,7 +35,7 @@ namespace Ndk
inline void AddToCullingList(GraphicsComponentCullingList* cullingList) const; inline void AddToCullingList(GraphicsComponentCullingList* cullingList) const;
void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const; void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;
void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0); inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);
void Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder = 0); void Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder = 0);
inline void Clear(); inline void Clear();
@ -54,22 +55,42 @@ namespace Ndk
static ComponentIndex componentIndex; static ComponentIndex componentIndex;
private: private:
struct Renderable;
void ConnectInstancedRenderableSignals(Renderable& renderable);
inline void InvalidateBoundingVolume() const; inline void InvalidateBoundingVolume() const;
void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index); void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index);
void InvalidateRenderableMaterial(const Nz::InstancedRenderable* renderable, std::size_t skinIndex, std::size_t matIndex, const Nz::MaterialRef& newMat);
inline void InvalidateRenderables(); inline void InvalidateRenderables();
inline void InvalidateTransformMatrix(); inline void InvalidateTransformMatrix();
void RegisterMaterial(Nz::Material* material, std::size_t count = 1);
void OnAttached() override; void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override; void OnComponentAttached(BaseComponent& component) override;
void OnComponentDetached(BaseComponent& component) override; void OnComponentDetached(BaseComponent& component) override;
void OnDetached() override; void OnDetached() override;
void OnInstancedRenderableResetMaterials(const Nz::InstancedRenderable* renderable, std::size_t newMaterialCount);
void OnInstancedRenderableSkinChange(const Nz::InstancedRenderable* renderable, std::size_t newSkinIndex);
void OnMaterialReflectionChange(const Nz::Material* material, Nz::ReflectionMode reflectionMode);
void OnNodeInvalidated(const Nz::Node* node); void OnNodeInvalidated(const Nz::Node* node);
void UnregisterMaterial(Nz::Material* material);
void UpdateBoundingVolume() const; void UpdateBoundingVolume() const;
void UpdateTransformMatrix() const; void UpdateTransformMatrix() const;
NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot); NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot);
struct MaterialEntry
{
NazaraSlot(Nz::Material, OnMaterialReflectionChange, reflectionModelChangeSlot);
std::size_t renderableCounter;
};
struct Renderable struct Renderable
{ {
Renderable(const Nz::Matrix4f& transformMatrix) : Renderable(const Nz::Matrix4f& transformMatrix) :
@ -78,15 +99,8 @@ namespace Ndk
{ {
} }
Renderable(Renderable&& rhs) noexcept : Renderable(const Renderable&) = delete;
renderableBoundingVolumeInvalidationSlot(std::move(rhs.renderableBoundingVolumeInvalidationSlot)), Renderable(Renderable&& rhs) noexcept = default;
renderableDataInvalidationSlot(std::move(rhs.renderableDataInvalidationSlot)),
renderableReleaseSlot(std::move(rhs.renderableReleaseSlot)),
data(std::move(rhs.data)),
renderable(std::move(rhs.renderable)),
dataUpdated(rhs.dataUpdated)
{
}
~Renderable() ~Renderable()
{ {
@ -94,21 +108,15 @@ namespace Ndk
renderableReleaseSlot.Disconnect(); renderableReleaseSlot.Disconnect();
} }
Renderable& operator=(Renderable&& r) noexcept Renderable& operator=(const Renderable&) = delete;
{ Renderable& operator=(Renderable&& r) noexcept = default;
data = std::move(r.data);
dataUpdated = r.dataUpdated;
renderable = std::move(r.renderable);
renderableBoundingVolumeInvalidationSlot = std::move(r.renderableBoundingVolumeInvalidationSlot);
renderableDataInvalidationSlot = std::move(r.renderableDataInvalidationSlot);
renderableReleaseSlot = std::move(r.renderableReleaseSlot);
return *this;
}
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateBoundingVolume, renderableBoundingVolumeInvalidationSlot); NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateBoundingVolume, renderableBoundingVolumeInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableDataInvalidationSlot); NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableDataInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateMaterial, renderableMaterialInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableRelease, renderableReleaseSlot); NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableRelease, renderableReleaseSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableResetMaterials, renderableResetMaterialsSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableSkinChange, renderableSkinChangeSlot);
mutable Nz::InstancedRenderable::InstanceData data; mutable Nz::InstancedRenderable::InstanceData data;
Nz::InstancedRenderableRef renderable; Nz::InstancedRenderableRef renderable;
@ -124,11 +132,14 @@ namespace Ndk
NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot); NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot);
}; };
std::size_t m_reflectiveMaterialCount;
mutable std::vector<VolumeCullingEntry> m_volumeCullingEntries; mutable std::vector<VolumeCullingEntry> m_volumeCullingEntries;
std::vector<Renderable> m_renderables; std::vector<Renderable> m_renderables;
std::unordered_map<const Nz::Material*, MaterialEntry> m_materialEntries;
mutable Nz::BoundingVolumef m_boundingVolume; mutable Nz::BoundingVolumef m_boundingVolume;
mutable Nz::Matrix4f m_transformMatrix; mutable Nz::Matrix4f m_transformMatrix;
mutable bool m_boundingVolumeUpdated; mutable bool m_boundingVolumeUpdated;
bool m_shouldRenderReflectionMap;
mutable bool m_transformMatrixUpdated; mutable bool m_transformMatrixUpdated;
}; };
} }

View File

@ -38,6 +38,17 @@ namespace Ndk
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Attaches a renderable to the entity
*
* \param renderable Reference to a renderable element
* \param renderOrder Render order of the element
*/
inline void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, int renderOrder)
{
return Attach(std::move(renderable), Nz::Matrix4f::Identity(), renderOrder);
}
/*! /*!
* \brief Clears every renderable elements * \brief Clears every renderable elements
*/ */
@ -62,6 +73,11 @@ namespace Ndk
if (it->renderable == renderable) if (it->renderable == renderable)
{ {
InvalidateBoundingVolume(); InvalidateBoundingVolume();
std::size_t materialCount = renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
m_renderables.erase(it); m_renderables.erase(it);
break; break;
} }

View File

@ -39,17 +39,6 @@ namespace Ndk
} }
} }
/*!
* \brief Attaches a renderable to the entity
*
* \param renderable Reference to a renderable element
* \param renderOrder Render order of the element
*/
void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, int renderOrder)
{
return Attach(renderable, Nz::Matrix4f::Identity(), renderOrder);
}
/*! /*!
* \brief Attaches a renderable to the entity with a specific matrix * \brief Attaches a renderable to the entity with a specific matrix
* *
@ -60,26 +49,29 @@ namespace Ndk
void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder) void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder)
{ {
m_renderables.emplace_back(m_transformMatrix); m_renderables.emplace_back(m_transformMatrix);
Renderable& r = m_renderables.back(); Renderable& entry = m_renderables.back();
r.data.localMatrix = localMatrix; entry.data.localMatrix = localMatrix;
r.data.renderOrder = renderOrder; entry.data.renderOrder = renderOrder;
r.renderable = std::move(renderable); entry.renderable = std::move(renderable);
r.renderableBoundingVolumeInvalidationSlot.Connect(r.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this] (const Nz::InstancedRenderable*) { InvalidateBoundingVolume(); });
r.renderableDataInvalidationSlot.Connect(r.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1)); ConnectInstancedRenderableSignals(entry);
r.renderableReleaseSlot.Connect(r.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach);
std::size_t materialCount = entry.renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
RegisterMaterial(entry.renderable->GetMaterial(i));
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*! void GraphicsComponent::ConnectInstancedRenderableSignals(Renderable& entry)
* \brief Invalidates the data for renderable {
* entry.renderableBoundingVolumeInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this](const Nz::InstancedRenderable*) { InvalidateBoundingVolume(); });
* \param renderable Renderable to invalidate entry.renderableDataInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1));
* \param flags Flags for the instance entry.renderableMaterialInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateMaterial, this, &GraphicsComponent::InvalidateRenderableMaterial);
* \param index Index of the renderable to invalidate entry.renderableReleaseSlot.Connect(entry.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach);
* entry.renderableResetMaterialsSlot.Connect(entry.renderable->OnInstancedRenderableResetMaterials, this, &GraphicsComponent::OnInstancedRenderableResetMaterials);
* \remark Produces a NazaraAssert if index is out of bound entry.renderableSkinChangeSlot.Connect(entry.renderable->OnInstancedRenderableSkinChange, this, &GraphicsComponent::OnInstancedRenderableSkinChange);
*/ }
void GraphicsComponent::InvalidateRenderableData(const Nz::InstancedRenderable* renderable , Nz::UInt32 flags, std::size_t index) void GraphicsComponent::InvalidateRenderableData(const Nz::InstancedRenderable* renderable , Nz::UInt32 flags, std::size_t index)
{ {
@ -94,6 +86,38 @@ namespace Ndk
entry.listEntry.ForceInvalidation(); entry.listEntry.ForceInvalidation();
} }
void GraphicsComponent::InvalidateRenderableMaterial(const Nz::InstancedRenderable* renderable, std::size_t skinIndex, std::size_t matIndex, const Nz::MaterialRef& newMat)
{
if (renderable->GetSkin() != skinIndex)
return;
RegisterMaterial(newMat);
const Nz::MaterialRef& oldMat = renderable->GetMaterial(skinIndex, matIndex);
UnregisterMaterial(oldMat);
}
void GraphicsComponent::RegisterMaterial(Nz::Material* material, std::size_t count)
{
auto it = m_materialEntries.find(material);
if (it == m_materialEntries.end())
{
MaterialEntry matEntry;
matEntry.reflectionModelChangeSlot.Connect(material->OnMaterialReflectionChange, this, &GraphicsComponent::OnMaterialReflectionChange);
matEntry.renderableCounter = count;
if (material->GetReflectionMode() == Nz::ReflectionMode_RealTime)
{
if (m_reflectiveMaterialCount++ == 0)
m_entity->Invalidate();
}
m_materialEntries.emplace(material, std::move(matEntry));
}
else
it->second.renderableCounter += count;
}
/*! /*!
* \brief Operation to perform when component is attached to an entity * \brief Operation to perform when component is attached to an entity
*/ */
@ -150,11 +174,39 @@ namespace Ndk
InvalidateTransformMatrix(); InvalidateTransformMatrix();
} }
/*! void GraphicsComponent::OnInstancedRenderableResetMaterials(const Nz::InstancedRenderable* renderable, std::size_t newMaterialCount)
* \brief Operation to perform when the node is invalidated {
* RegisterMaterial(Nz::Material::GetDefault(), newMaterialCount);
* \param node Pointer to the node
*/ std::size_t materialCount = renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
}
void GraphicsComponent::OnInstancedRenderableSkinChange(const Nz::InstancedRenderable* renderable, std::size_t newSkinIndex)
{
std::size_t materialCount = renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
RegisterMaterial(renderable->GetMaterial(newSkinIndex, i));
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
}
void GraphicsComponent::OnMaterialReflectionChange(const Nz::Material* material, Nz::ReflectionMode reflectionMode)
{
// Since this signal is only called when the new reflection mode is different from the current one, no need to compare both
if (material->GetReflectionMode() == Nz::ReflectionMode_RealTime)
{
if (--m_reflectiveMaterialCount == 0)
m_entity->Invalidate();
}
else if (reflectionMode == Nz::ReflectionMode_RealTime)
{
if (m_reflectiveMaterialCount++ == 0)
m_entity->Invalidate();
}
}
void GraphicsComponent::OnNodeInvalidated(const Nz::Node* node) void GraphicsComponent::OnNodeInvalidated(const Nz::Node* node)
{ {
@ -168,6 +220,24 @@ namespace Ndk
entry.listEntry.ForceInvalidation(); //< Force invalidation on movement entry.listEntry.ForceInvalidation(); //< Force invalidation on movement
} }
void GraphicsComponent::UnregisterMaterial(Nz::Material* material)
{
auto it = m_materialEntries.find(material);
NazaraAssert(it != m_materialEntries.end(), "Material not registered");
MaterialEntry& matEntry = it->second;
if (--matEntry.renderableCounter == 0)
{
if (material->GetReflectionMode() == Nz::ReflectionMode_RealTime)
{
if (--m_reflectiveMaterialCount == 0)
m_entity->Invalidate();
}
m_materialEntries.erase(it);
}
}
/*! /*!
* \brief Updates the bounding volume * \brief Updates the bounding volume
*/ */

View File

@ -68,6 +68,8 @@ namespace Nz
NazaraSignal(OnInstancedRenderableInvalidateData, const InstancedRenderable* /*instancedRenderable*/, UInt32 /*flags*/); NazaraSignal(OnInstancedRenderableInvalidateData, const InstancedRenderable* /*instancedRenderable*/, UInt32 /*flags*/);
NazaraSignal(OnInstancedRenderableInvalidateMaterial, const InstancedRenderable* /*instancedRenderable*/, std::size_t /*skinIndex*/, std::size_t /*matIndex*/, const MaterialRef& /*newMat*/); NazaraSignal(OnInstancedRenderableInvalidateMaterial, const InstancedRenderable* /*instancedRenderable*/, std::size_t /*skinIndex*/, std::size_t /*matIndex*/, const MaterialRef& /*newMat*/);
NazaraSignal(OnInstancedRenderableRelease, const InstancedRenderable* /*instancedRenderable*/); NazaraSignal(OnInstancedRenderableRelease, const InstancedRenderable* /*instancedRenderable*/);
NazaraSignal(OnInstancedRenderableResetMaterials, const InstancedRenderable* /*instancedRenderable*/, std::size_t /*newMaterialCount*/);
NazaraSignal(OnInstancedRenderableSkinChange, const InstancedRenderable* /*instancedRenderable*/, std::size_t /*newSkinIndex*/);
struct InstanceData struct InstanceData
{ {

View File

@ -124,11 +124,16 @@ namespace Nz
{ {
NazaraAssert(skinIndex < m_skinCount, "Skin index out of bounds"); NazaraAssert(skinIndex < m_skinCount, "Skin index out of bounds");
if (m_skin != skinIndex)
{
OnInstancedRenderableSkinChange(this, skinIndex);
m_skin = skinIndex; m_skin = skinIndex;
// Force render queue invalidation // Force render queue invalidation
InvalidateInstanceData(0); InvalidateInstanceData(0);
} }
}
/*! /*!
* \brief Changes the maximum skin count of the object * \brief Changes the maximum skin count of the object
@ -186,6 +191,8 @@ namespace Nz
{ {
NazaraAssert(skinCount != 0, "Invalid skin count (cannot be zero)"); NazaraAssert(skinCount != 0, "Invalid skin count (cannot be zero)");
OnInstancedRenderableResetMaterials(this, matCount);
m_materials.clear(); m_materials.clear();
m_materials.resize(matCount * skinCount, Material::GetDefault()); m_materials.resize(matCount * skinCount, Material::GetDefault());