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
#include <Nazara/Graphics/Renderable.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp>
namespace Ndk
@ -16,22 +17,49 @@ namespace Ndk
{
public:
GraphicsComponent() = default;
inline GraphicsComponent(const GraphicsComponent& graphicsComponent);
~GraphicsComponent() = default;
inline void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const;
inline void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const;
inline void Attach(NzRenderableRef renderable);
inline void EnsureTransformMatrixUpdate() const;
static ComponentIndex componentIndex;
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
{
NzBoundingVolumef volume;
Renderable(NzMatrix4f& transformMatrix) :
data(transformMatrix),
dataUpdated(false)
{
}
NazaraSlot(NzRenderable, OnRenderableInvalidateInstanceData, renderableInvalidationSlot);
mutable NzRenderable::InstanceData data;
NzRenderableRef renderable;
mutable bool dataUpdated;
};
std::vector<Renderable> m_renderables;
mutable NzMatrix4f m_transformMatrix;
mutable bool m_transformMatrixUpdated;
};
}

View File

@ -6,16 +6,48 @@
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)
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)
{
m_renderables.resize(m_renderables.size() + 1);
m_renderables.emplace_back(m_transformMatrix);
Renderable& r = m_renderables.back();
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
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
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;
}

View File

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

View File

@ -29,12 +29,12 @@ class NAZARA_API NzLight : public NzRenderable
NzLight(const NzLight& light) = 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* 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 GetAttenuation() const;
@ -58,7 +58,7 @@ class NAZARA_API NzLight : public NzRenderable
void SetOuterAngle(float outerAngle);
void SetRadius(float radius);
void UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const;
void UpdateBoundingVolume(InstanceData* instanceData) const;
NzLight& operator=(const NzLight& light) = default;

View File

@ -42,7 +42,7 @@ class NAZARA_API NzModel : public NzRenderable, public NzResource
NzModel(NzModel&& model) = default;
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(unsigned int matIndex) const;

View File

@ -27,25 +27,45 @@ using NzRenderableRef = NzObjectRef<NzRenderable>;
class NAZARA_API NzRenderable : public NzRefCounted
{
public:
struct InstanceData;
NzRenderable() = default;
inline NzRenderable(const NzRenderable& renderable);
virtual ~NzRenderable();
inline void EnsureBoundingVolumeUpdated() const;
virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const = 0;
virtual bool Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const;
virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const = 0;
virtual bool Cull(const NzFrustumf& frustum, const InstanceData& instanceData) 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);
// Signals:
NazaraSignal(OnRenderableInvalidateInstanceData, const NzRenderable*, nzUInt32); //< Args: me, flags
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:
virtual void MakeBoundingVolume() const = 0;
void InvalidateBoundingVolume();
inline void InvalidateInstanceData(nzUInt32 flags);
inline void UpdateBoundingVolume() const;
mutable NzBoundingVolumef m_boundingVolume;

View File

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

View File

@ -38,7 +38,7 @@ class NAZARA_API NzSkeletalModel : public NzModel, NzUpdatable
NzSkeletalModel(NzSkeletalModel&& model) = 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);
NzSkeletalModel* Clone() const;

View File

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

View File

@ -36,7 +36,7 @@ NzModel::~NzModel()
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();
for (unsigned int i = 0; i < submeshCount; ++i)
@ -49,7 +49,7 @@ void NzModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatri
meshData.primitiveMode = mesh->GetPrimitiveMode();
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);
}
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(volume);
return frustum.Contains(instanceData.volume);
}
const NzBoundingVolumef& NzRenderable::GetBoundingVolume() const
@ -24,11 +22,22 @@ const NzBoundingVolumef& NzRenderable::GetBoundingVolume() const
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;

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)
return;
@ -47,7 +47,7 @@ void NzSkeletalModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const
meshData.primitiveMode = mesh->GetPrimitiveMode();
meshData.vertexBuffer = NzSkinningManager::GetBuffer(mesh, &m_skeleton);
renderQueue->AddMesh(material, meshData, m_skeleton.GetAABB(), transformMatrix);
renderQueue->AddMesh(material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix);
}
}