Graphics/Renderable: Add InstanceData

Former-commit-id: f30f011ae91a445d5b22f33150a88bbda218950c
This commit is contained in:
Lynix 2015-06-11 14:14:11 +02:00
parent 6f2f8d6390
commit 48a54dfa5c
13 changed files with 195 additions and 37 deletions

View File

@ -8,6 +8,7 @@
#define NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP #define NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#include <Nazara/Graphics/Renderable.hpp> #include <Nazara/Graphics/Renderable.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp> #include <NDK/Component.hpp>
namespace Ndk namespace Ndk
@ -16,22 +17,49 @@ namespace Ndk
{ {
public: public:
GraphicsComponent() = default; GraphicsComponent() = default;
inline GraphicsComponent(const GraphicsComponent& graphicsComponent);
~GraphicsComponent() = default; ~GraphicsComponent() = default;
inline void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const; inline void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const;
inline void Attach(NzRenderableRef renderable); inline void Attach(NzRenderableRef renderable);
inline void EnsureTransformMatrixUpdate() const;
static ComponentIndex componentIndex; static ComponentIndex componentIndex;
private: private:
void InvalidateRenderableData(const NzRenderable* renderable, nzUInt32 flags, unsigned int index);
inline void InvalidateTransformMatrix();
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;
void OnComponentDetached(BaseComponent& component) override;
void OnDetached() override;
void OnNodeInvalidated(const NzNode* node);
void UpdateTransformMatrix() const;
NazaraSlot(NzNode, OnNodeInvalidation, m_nodeInvalidationSlot);
struct Renderable struct Renderable
{ {
NzBoundingVolumef volume; Renderable(NzMatrix4f& transformMatrix) :
data(transformMatrix),
dataUpdated(false)
{
}
NazaraSlot(NzRenderable, OnRenderableInvalidateInstanceData, renderableInvalidationSlot);
mutable NzRenderable::InstanceData data;
NzRenderableRef renderable; NzRenderableRef renderable;
mutable bool dataUpdated;
}; };
std::vector<Renderable> m_renderables; std::vector<Renderable> m_renderables;
mutable NzMatrix4f m_transformMatrix;
mutable bool m_transformMatrixUpdated;
}; };
} }

View File

@ -6,16 +6,48 @@
namespace Ndk namespace Ndk
{ {
inline void GraphicsComponent::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const inline GraphicsComponent::GraphicsComponent(const GraphicsComponent& graphicsComponent) :
Component(graphicsComponent),
m_transformMatrix(graphicsComponent.m_transformMatrix),
m_transformMatrixUpdated(graphicsComponent.m_transformMatrixUpdated)
{ {
m_renderables.reserve(graphicsComponent.m_renderables.size());
for (const Renderable& r : graphicsComponent.m_renderables)
Attach(r.renderable);
}
inline void GraphicsComponent::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
{
EnsureTransformMatrixUpdate();
for (const Renderable& object : m_renderables) for (const Renderable& object : m_renderables)
object.renderable->AddToRenderQueue(renderQueue, transformMatrix); {
if (!object.dataUpdated)
{
object.renderable->UpdateData(&object.data);
object.dataUpdated = true;
}
object.renderable->AddToRenderQueue(renderQueue, object.data);
}
} }
inline void GraphicsComponent::Attach(NzRenderableRef renderable) inline void GraphicsComponent::Attach(NzRenderableRef renderable)
{ {
m_renderables.resize(m_renderables.size() + 1); m_renderables.emplace_back(m_transformMatrix);
Renderable& r = m_renderables.back(); Renderable& r = m_renderables.back();
r.renderable = std::move(renderable); r.renderable = std::move(renderable);
r.renderableInvalidationSlot.Connect(r.renderable->OnRenderableInvalidateInstanceData, std::bind(InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size()-1));
}
inline void GraphicsComponent::EnsureTransformMatrixUpdate() const
{
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
}
inline void GraphicsComponent::InvalidateTransformMatrix()
{
m_transformMatrixUpdated = false;
} }
} }

View File

@ -3,8 +3,72 @@
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/Components/GraphicsComponent.hpp> #include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
namespace Ndk namespace Ndk
{ {
void GraphicsComponent::InvalidateRenderableData(const NzRenderable* renderable, nzUInt32 flags, unsigned int index)
{
NazaraUnused(renderable);
NazaraAssert(index < m_renderables.size(), "Invalid renderable index");
Renderable& r = m_renderables[index];
r.dataUpdated = false;
r.renderable->InvalidateData(&r.data, flags);
}
void GraphicsComponent::OnAttached()
{
if (m_entity->HasComponent<NodeComponent>())
m_nodeInvalidationSlot.Connect(m_entity->GetComponent<NodeComponent>().OnNodeInvalidation, this, OnNodeInvalidated);
InvalidateTransformMatrix();
}
void GraphicsComponent::OnComponentAttached(BaseComponent& component)
{
if (IsComponent<NodeComponent>(component))
{
NodeComponent& nodeComponent = static_cast<NodeComponent&>(component);
m_nodeInvalidationSlot.Connect(nodeComponent.OnNodeInvalidation, this, OnNodeInvalidated);
InvalidateTransformMatrix();
}
}
void GraphicsComponent::OnComponentDetached(BaseComponent& component)
{
if (IsComponent<NodeComponent>(component))
{
m_nodeInvalidationSlot.Disconnect();
InvalidateTransformMatrix();
}
}
void GraphicsComponent::OnDetached()
{
m_nodeInvalidationSlot.Disconnect();
InvalidateTransformMatrix();
}
void GraphicsComponent::OnNodeInvalidated(const NzNode* node)
{
NazaraUnused(node);
// Our view matrix depends on NodeComponent position/rotation
InvalidateTransformMatrix();
}
void GraphicsComponent::UpdateTransformMatrix() const
{
NazaraAssert(m_entity && m_entity->HasComponent<NodeComponent>(), "GraphicsComponent requires NodeComponent");
m_transformMatrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
m_transformMatrixUpdated = true;
}
ComponentIndex GraphicsComponent::componentIndex; ComponentIndex GraphicsComponent::componentIndex;
} }

View File

@ -29,7 +29,7 @@ namespace Ndk
GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>(); GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>();
NodeComponent& drawableNode = drawable->GetComponent<NodeComponent>(); NodeComponent& drawableNode = drawable->GetComponent<NodeComponent>();
graphicsComponent.AddToRenderQueue(renderQueue, drawableNode.GetTransformMatrix()); graphicsComponent.AddToRenderQueue(renderQueue);
} }
NzColorBackground background; NzColorBackground background;

View File

@ -29,12 +29,12 @@ class NAZARA_API NzLight : public NzRenderable
NzLight(const NzLight& light) = default; NzLight(const NzLight& light) = default;
~NzLight() = default; ~NzLight() = default;
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const override; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override;
NzLight* Clone() const; NzLight* Clone() const;
NzLight* Create() const; NzLight* Create() const;
bool Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const override; bool Cull(const NzFrustumf& frustum, const InstanceData& instanceData) const override;
float GetAmbientFactor() const; float GetAmbientFactor() const;
float GetAttenuation() const; float GetAttenuation() const;
@ -58,7 +58,7 @@ class NAZARA_API NzLight : public NzRenderable
void SetOuterAngle(float outerAngle); void SetOuterAngle(float outerAngle);
void SetRadius(float radius); void SetRadius(float radius);
void UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const; void UpdateBoundingVolume(InstanceData* instanceData) const;
NzLight& operator=(const NzLight& light) = default; NzLight& operator=(const NzLight& light) = default;

View File

@ -42,7 +42,7 @@ class NAZARA_API NzModel : public NzRenderable, public NzResource
NzModel(NzModel&& model) = default; NzModel(NzModel&& model) = default;
virtual ~NzModel(); virtual ~NzModel();
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const override; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override;
NzMaterial* GetMaterial(const NzString& subMeshName) const; NzMaterial* GetMaterial(const NzString& subMeshName) const;
NzMaterial* GetMaterial(unsigned int matIndex) const; NzMaterial* GetMaterial(unsigned int matIndex) const;

View File

@ -27,25 +27,45 @@ using NzRenderableRef = NzObjectRef<NzRenderable>;
class NAZARA_API NzRenderable : public NzRefCounted class NAZARA_API NzRenderable : public NzRefCounted
{ {
public: public:
struct InstanceData;
NzRenderable() = default; NzRenderable() = default;
inline NzRenderable(const NzRenderable& renderable); inline NzRenderable(const NzRenderable& renderable);
virtual ~NzRenderable(); virtual ~NzRenderable();
inline void EnsureBoundingVolumeUpdated() const; inline void EnsureBoundingVolumeUpdated() const;
virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const = 0; virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const = 0;
virtual bool Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const; virtual bool Cull(const NzFrustumf& frustum, const InstanceData& instanceData) const;
virtual const NzBoundingVolumef& GetBoundingVolume() const; virtual const NzBoundingVolumef& GetBoundingVolume() const;
virtual void UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const; virtual void InvalidateData(InstanceData* instanceData, nzUInt32 flags) const;
virtual void UpdateBoundingVolume(InstanceData* instanceData) const;
virtual void UpdateData(InstanceData* instanceData) const;
inline NzRenderable& operator=(const NzRenderable& renderable); inline NzRenderable& operator=(const NzRenderable& renderable);
// Signals: // Signals:
NazaraSignal(OnRenderableInvalidateInstanceData, const NzRenderable*, nzUInt32); //< Args: me, flags
NazaraSignal(OnRenderableRelease, const NzRenderable*); //< Args: me NazaraSignal(OnRenderableRelease, const NzRenderable*); //< Args: me
struct InstanceData
{
InstanceData(NzMatrix4f& referenceMatrix) :
transformMatrix(referenceMatrix),
flags(0)
{
}
std::vector<nzUInt8> data;
NzBoundingVolumef volume;
NzMatrix4f& transformMatrix;
nzUInt32 flags;
};
protected: protected:
virtual void MakeBoundingVolume() const = 0; virtual void MakeBoundingVolume() const = 0;
void InvalidateBoundingVolume(); void InvalidateBoundingVolume();
inline void InvalidateInstanceData(nzUInt32 flags);
inline void UpdateBoundingVolume() const; inline void UpdateBoundingVolume() const;
mutable NzBoundingVolumef m_boundingVolume; mutable NzBoundingVolumef m_boundingVolume;

View File

@ -19,6 +19,11 @@ inline void NzRenderable::InvalidateBoundingVolume()
m_boundingVolumeUpdated = false; m_boundingVolumeUpdated = false;
} }
inline void NzRenderable::InvalidateInstanceData(nzUInt32 flags)
{
OnRenderableInvalidateInstanceData(this, flags);
}
inline NzRenderable& NzRenderable::operator=(const NzRenderable& renderable) inline NzRenderable& NzRenderable::operator=(const NzRenderable& renderable)
{ {
m_boundingVolume = renderable.m_boundingVolume; m_boundingVolume = renderable.m_boundingVolume;

View File

@ -38,7 +38,7 @@ class NAZARA_API NzSkeletalModel : public NzModel, NzUpdatable
NzSkeletalModel(NzSkeletalModel&& model) = default; NzSkeletalModel(NzSkeletalModel&& model) = default;
~NzSkeletalModel() = default; ~NzSkeletalModel() = default;
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const override; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override;
void AdvanceAnimation(float elapsedTime); void AdvanceAnimation(float elapsedTime);
NzSkeletalModel* Clone() const; NzSkeletalModel* Clone() const;

View File

@ -28,7 +28,7 @@ m_type(type)
SetRadius(5.f); SetRadius(5.f);
} }
void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
switch (m_type) switch (m_type)
{ {
@ -38,7 +38,7 @@ void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatri
light.ambientFactor = m_ambientFactor; light.ambientFactor = m_ambientFactor;
light.color = m_color; light.color = m_color;
light.diffuseFactor = m_diffuseFactor; light.diffuseFactor = m_diffuseFactor;
light.direction = transformMatrix.Transform(NzVector3f::Forward(), 0.f); light.direction = instanceData.transformMatrix.Transform(NzVector3f::Forward(), 0.f);
renderQueue->AddDirectionalLight(light); renderQueue->AddDirectionalLight(light);
break; break;
@ -52,7 +52,7 @@ void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatri
light.color = m_color; light.color = m_color;
light.diffuseFactor = m_diffuseFactor; light.diffuseFactor = m_diffuseFactor;
light.invRadius = m_invRadius; light.invRadius = m_invRadius;
light.position = transformMatrix.GetTranslation(); light.position = instanceData.transformMatrix.GetTranslation();
light.radius = m_radius; light.radius = m_radius;
renderQueue->AddPointLight(light); renderQueue->AddPointLight(light);
@ -66,12 +66,12 @@ void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatri
light.attenuation = m_attenuation; light.attenuation = m_attenuation;
light.color = m_color; light.color = m_color;
light.diffuseFactor = m_diffuseFactor; light.diffuseFactor = m_diffuseFactor;
light.direction = transformMatrix.Transform(NzVector3f::Forward(), 0.f); light.direction = instanceData.transformMatrix.Transform(NzVector3f::Forward(), 0.f);
light.innerAngleCosine = m_innerAngleCosine; light.innerAngleCosine = m_innerAngleCosine;
light.invRadius = m_invRadius; light.invRadius = m_invRadius;
light.outerAngleCosine = m_outerAngleCosine; light.outerAngleCosine = m_outerAngleCosine;
light.outerAngleTangent = m_outerAngleTangent; light.outerAngleTangent = m_outerAngleTangent;
light.position = transformMatrix.GetTranslation(); light.position = instanceData.transformMatrix.GetTranslation();
light.radius = m_radius; light.radius = m_radius;
renderQueue->AddSpotLight(light); renderQueue->AddSpotLight(light);
@ -94,7 +94,7 @@ NzLight* NzLight::Create() const
return new NzLight; return new NzLight;
} }
bool NzLight::Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const bool NzLight::Cull(const NzFrustumf& frustum, const InstanceData& instanceData) const
{ {
switch (m_type) switch (m_type)
{ {
@ -102,19 +102,19 @@ bool NzLight::Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, c
return true; // Always visible return true; // Always visible
case nzLightType_Point: case nzLightType_Point:
return frustum.Contains(NzSpheref(transformMatrix.GetTranslation(), m_radius)); // A sphere test is much faster (and precise) return frustum.Contains(NzSpheref(instanceData.transformMatrix.GetTranslation(), m_radius)); // A sphere test is much faster (and precise)
case nzLightType_Spot: case nzLightType_Spot:
return frustum.Contains(volume); return frustum.Contains(instanceData.volume);
} }
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')'); NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
return false; return false;
} }
void NzLight::UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const void NzLight::UpdateBoundingVolume(InstanceData* instanceData) const
{ {
NazaraAssert(boundingVolume, "Invalid bounding volume"); NazaraAssert(instanceData, "Invalid data");
switch (m_type) switch (m_type)
{ {
@ -122,11 +122,11 @@ void NzLight::UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMa
break; // Nothing to do (bounding volume should be infinite) break; // Nothing to do (bounding volume should be infinite)
case nzLightType_Point: case nzLightType_Point:
boundingVolume->Update(transformMatrix.GetTranslation()); // The bounding volume only needs to be shifted instanceData->volume.Update(instanceData->transformMatrix.GetTranslation()); // The bounding volume only needs to be shifted
break; break;
case nzLightType_Spot: case nzLightType_Spot:
boundingVolume->Update(transformMatrix); instanceData->volume.Update(instanceData->transformMatrix);
break; break;
default: default:

View File

@ -36,7 +36,7 @@ NzModel::~NzModel()
Reset(); Reset();
} }
void NzModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const void NzModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
unsigned int submeshCount = m_mesh->GetSubMeshCount(); unsigned int submeshCount = m_mesh->GetSubMeshCount();
for (unsigned int i = 0; i < submeshCount; ++i) for (unsigned int i = 0; i < submeshCount; ++i)
@ -49,7 +49,7 @@ void NzModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatri
meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.primitiveMode = mesh->GetPrimitiveMode();
meshData.vertexBuffer = mesh->GetVertexBuffer(); meshData.vertexBuffer = mesh->GetVertexBuffer();
renderQueue->AddMesh(material, meshData, mesh->GetAABB(), transformMatrix); renderQueue->AddMesh(material, meshData, mesh->GetAABB(), instanceData.transformMatrix);
} }
} }

View File

@ -10,11 +10,9 @@ NzRenderable::~NzRenderable()
OnRenderableRelease(this); OnRenderableRelease(this);
} }
bool NzRenderable::Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const bool NzRenderable::Cull(const NzFrustumf& frustum, const InstanceData& instanceData) const
{ {
NazaraUnused(transformMatrix); return frustum.Contains(instanceData.volume);
return frustum.Contains(volume);
} }
const NzBoundingVolumef& NzRenderable::GetBoundingVolume() const const NzBoundingVolumef& NzRenderable::GetBoundingVolume() const
@ -24,11 +22,22 @@ const NzBoundingVolumef& NzRenderable::GetBoundingVolume() const
return m_boundingVolume; return m_boundingVolume;
} }
void NzRenderable::UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const void NzRenderable::InvalidateData(InstanceData* instanceData, nzUInt32 flags) const
{ {
NazaraAssert(boundingVolume, "Invalid bounding volume"); instanceData->flags |= flags;
}
boundingVolume->Update(transformMatrix); void NzRenderable::UpdateBoundingVolume(InstanceData* instanceData) const
{
NazaraAssert(instanceData, "Invalid instance data");
NazaraUnused(instanceData);
instanceData->volume.Update(instanceData->transformMatrix);
}
void NzRenderable::UpdateData(InstanceData* instanceData) const
{
NazaraAssert(instanceData, "Invalid instance data");
} }
NzRenderableLibrary::LibraryMap NzRenderable::s_library; NzRenderableLibrary::LibraryMap NzRenderable::s_library;

View File

@ -31,7 +31,7 @@ m_animationEnabled(true)
{ {
} }
void NzSkeletalModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const void NzSkeletalModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
if (!m_mesh) if (!m_mesh)
return; return;
@ -47,7 +47,7 @@ void NzSkeletalModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const
meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.primitiveMode = mesh->GetPrimitiveMode();
meshData.vertexBuffer = NzSkinningManager::GetBuffer(mesh, &m_skeleton); meshData.vertexBuffer = NzSkinningManager::GetBuffer(mesh, &m_skeleton);
renderQueue->AddMesh(material, meshData, m_skeleton.GetAABB(), transformMatrix); renderQueue->AddMesh(material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix);
} }
} }