Graphics: Add frustum culling

Former-commit-id: 2741c465f9acb4a190de0a29db4a3853700461fd [formerly be67ee144fe577767a11be40f79f3f2e85d030c0] [formerly 302a6d2c8a3222401890d217f01c24a03db9ebc8 [formerly 762367a1144c340b84b61eee9d7577dcdaf717c6]]
Former-commit-id: 6504b78e4ce04d8eea0c10e7ce27bdda4b95f2dc [formerly 8d0fba6c2dde5dcc43cbea0e6e5fd2980af4b801]
Former-commit-id: 75d1deaf21035eb1b630705017462b9e059149a9
This commit is contained in:
Lynix 2016-09-06 13:30:05 +02:00
parent 4345d540bb
commit 01330dcfdf
11 changed files with 732 additions and 78 deletions

View File

@ -8,6 +8,7 @@
#ifndef NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#define NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#include <Nazara/Graphics/CullingList.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp>
@ -16,6 +17,7 @@ namespace Ndk
{
class GraphicsComponent;
using GraphicsComponentCullingList = Nz::CullingList<GraphicsComponent>;
using GraphicsComponentHandle = Nz::ObjectHandle<GraphicsComponent>;
class NDK_API GraphicsComponent : public Component<GraphicsComponent>, public Nz::HandledObject<GraphicsComponent>
@ -29,10 +31,11 @@ namespace Ndk
inline GraphicsComponent(const GraphicsComponent& graphicsComponent);
~GraphicsComponent() = default;
inline void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;
inline void AddToCullingList(GraphicsComponentCullingList* cullingList) const;
void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;
inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);
inline void Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder = 0);
void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);
void Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder = 0);
inline void Clear();
@ -46,10 +49,12 @@ namespace Ndk
inline const Nz::BoundingVolumef& GetBoundingVolume() const;
inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const;
static ComponentIndex componentIndex;
private:
inline void InvalidateBoundingVolume();
inline void InvalidateBoundingVolume() const;
void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index);
inline void InvalidateRenderables();
inline void InvalidateTransformMatrix();
@ -77,7 +82,8 @@ namespace Ndk
data(std::move(renderable.data)),
renderable(std::move(renderable.renderable)),
dataUpdated(renderable.dataUpdated),
renderableInvalidationSlot(std::move(renderable.renderableInvalidationSlot)),
renderableBoundingVolumeInvalidationSlot(std::move(renderable.renderableBoundingVolumeInvalidationSlot)),
renderableDataInvalidationSlot(std::move(renderable.renderableDataInvalidationSlot)),
renderableReleaseSlot(std::move(renderable.renderableReleaseSlot))
{
}
@ -93,13 +99,15 @@ namespace Ndk
data = std::move(r.data);
dataUpdated = r.dataUpdated;
renderable = std::move(r.renderable);
renderableInvalidationSlot = std::move(r.renderableInvalidationSlot);
renderableBoundingVolumeInvalidationSlot = std::move(r.renderableBoundingVolumeInvalidationSlot);
renderableDataInvalidationSlot = std::move(r.renderableDataInvalidationSlot);
renderableReleaseSlot = std::move(r.renderableReleaseSlot);
return *this;
}
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateBoundingVolume, renderableBoundingVolumeInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableDataInvalidationSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableRelease, renderableReleaseSlot);
mutable Nz::InstancedRenderable::InstanceData data;
@ -107,6 +115,16 @@ namespace Ndk
mutable bool dataUpdated;
};
using VolumeCullingListEntry = GraphicsComponentCullingList::VolumeEntry;
struct VolumeCullingEntry
{
VolumeCullingListEntry listEntry;
NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot);
};
mutable std::vector<VolumeCullingEntry> m_volumeCullingEntries;
std::vector<Renderable> m_renderables;
mutable Nz::BoundingVolumef m_boundingVolume;
mutable Nz::Matrix4f m_transformMatrix;

View File

@ -28,52 +28,12 @@ namespace Ndk
Attach(r.renderable, r.data.renderOrder);
}
/*!
* \brief Adds the renderable elements to the render queue
*
* \param renderQueue Queue to be added
*/
inline void GraphicsComponent::AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const
inline void GraphicsComponent::AddToCullingList(GraphicsComponentCullingList* cullingList) const
{
EnsureTransformMatrixUpdate();
Ndk::RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<Ndk::RenderSystem>();
for (const Renderable& object : m_renderables)
{
if (!object.dataUpdated)
{
object.data.transformMatrix = Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), Nz::Matrix4f::ConcatenateAffine(object.data.localMatrix, m_transformMatrix));
object.renderable->UpdateData(&object.data);
object.dataUpdated = true;
}
object.renderable->AddToRenderQueue(renderQueue, object.data);
}
}
/*!
* \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(renderable, Nz::Matrix4f::Identity(), renderOrder);
}
inline void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder)
{
m_renderables.emplace_back(m_transformMatrix);
Renderable& r = m_renderables.back();
r.data.localMatrix = localMatrix;
r.data.renderOrder = renderOrder;
r.renderable = std::move(renderable);
r.renderableInvalidationSlot.Connect(r.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1));
r.renderableReleaseSlot.Connect(r.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach);
m_volumeCullingEntries.emplace_back(VolumeCullingEntry{});
VolumeCullingEntry& entry = m_volumeCullingEntries.back();
entry.cullingListReleaseSlot.Connect(cullingList->OnCullingListRelease, this, &GraphicsComponent::RemoveFromCullingList);
entry.listEntry = cullingList->RegisterVolumeTest(this);
InvalidateBoundingVolume();
}
@ -167,11 +127,26 @@ namespace Ndk
return m_boundingVolume;
}
inline void GraphicsComponent::RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const
{
for (auto it = m_volumeCullingEntries.begin(); it != m_volumeCullingEntries.end(); ++it)
{
if (it->listEntry.GetParent() == cullingList)
{
if (m_volumeCullingEntries.size() > 1)
*it = std::move(m_volumeCullingEntries.back());
m_volumeCullingEntries.pop_back();
break;
}
}
}
/*!
* \brief Invalidates the bounding volume
*/
inline void GraphicsComponent::InvalidateBoundingVolume()
inline void GraphicsComponent::InvalidateBoundingVolume() const
{
m_boundingVolumeUpdated = false;
}
@ -192,9 +167,9 @@ namespace Ndk
inline void GraphicsComponent::InvalidateTransformMatrix()
{
m_boundingVolumeUpdated = false;
m_transformMatrixUpdated = false;
InvalidateBoundingVolume();
InvalidateRenderables();
}
}

View File

@ -9,9 +9,11 @@
#define NDK_SYSTEMS_RENDERSYSTEM_HPP
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/CullingList.hpp>
#include <Nazara/Graphics/DepthRenderTechnique.hpp>
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
#include <Nazara/Renderer/RenderTexture.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/EntityList.hpp>
#include <NDK/System.hpp>
#include <unordered_map>
@ -19,8 +21,6 @@
namespace Ndk
{
class GraphicsComponent;
class NDK_API RenderSystem : public System<RenderSystem>
{
public:
@ -51,16 +51,19 @@ namespace Ndk
void OnEntityRemoved(Entity* entity) override;
void OnEntityValidation(Entity* entity, bool justAdded) override;
void OnUpdate(float elapsedTime) override;
void UpdateDirectionalShadowMaps(const Nz::AbstractViewer& viewer);
void UpdatePointSpotShadowMaps();
std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique;
std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries;
EntityList m_cameras;
EntityList m_drawables;
EntityList m_directionalLights;
EntityList m_lights;
EntityList m_pointSpotLights;
EntityList m_particleGroups;
GraphicsComponentCullingList m_drawableCulling;
Nz::BackgroundRef m_background;
Nz::DepthRenderTechnique m_shadowTechnique;
Nz::Matrix4f m_coordinateSystemMatrix;

View File

@ -15,6 +15,62 @@ namespace Ndk
* \brief NDK class that represents the component for graphics
*/
/*!
* \brief Adds the renderable elements to the render queue
*
* \param renderQueue Queue to be added
*/
void GraphicsComponent::AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const
{
EnsureTransformMatrixUpdate();
RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<RenderSystem>();
for (const Renderable& object : m_renderables)
{
if (!object.dataUpdated)
{
object.data.transformMatrix = Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), Nz::Matrix4f::ConcatenateAffine(object.data.localMatrix, m_transformMatrix));
object.renderable->UpdateData(&object.data);
object.dataUpdated = true;
}
object.renderable->AddToRenderQueue(renderQueue, object.data);
}
}
/*!
* \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
*
* \param renderable Reference to a renderable element
* \param localMatrix Local matrix that will be applied to the instanced renderable
* \param renderOrder Render order of the element
*/
void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder)
{
m_renderables.emplace_back(m_transformMatrix);
Renderable& r = m_renderables.back();
r.data.localMatrix = localMatrix;
r.data.renderOrder = renderOrder;
r.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));
r.renderableReleaseSlot.Connect(r.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach);
InvalidateBoundingVolume();
}
/*!
* \brief Invalidates the data for renderable
*
@ -115,10 +171,29 @@ namespace Ndk
m_boundingVolume.MakeNull();
for (const Renderable& r : m_renderables)
m_boundingVolume.ExtendTo(r.renderable->GetBoundingVolume());
{
Nz::BoundingVolumef boundingVolume = r.renderable->GetBoundingVolume();
m_boundingVolume.Update(m_transformMatrix);
// Adjust renderable bounding volume by local matrix
if (boundingVolume.IsFinite())
{
Nz::Boxf localBox = boundingVolume.obb.localBox;
Nz::Vector3f newPos = r.data.localMatrix * localBox.GetPosition();
Nz::Vector3f newLengths = r.data.localMatrix * localBox.GetLengths();
boundingVolume.Set(Nz::Boxf(newPos.x, newPos.y, newPos.z, newLengths.x, newLengths.y, newLengths.z));
}
m_boundingVolume.ExtendTo(r.renderable->GetBoundingVolume());
}
RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<RenderSystem>();
m_boundingVolume.Update(Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), m_transformMatrix));
m_boundingVolumeUpdated = true;
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
entry.listEntry.UpdateVolume(m_boundingVolume);
}
/*!
@ -131,8 +206,6 @@ namespace Ndk
{
NazaraAssert(m_entity && m_entity->HasComponent<NodeComponent>(), "GraphicsComponent requires NodeComponent");
Ndk::RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<Ndk::RenderSystem>();
m_transformMatrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
m_transformMatrixUpdated = true;
}

View File

@ -28,7 +28,6 @@ namespace Ndk
/*!
* \brief Constructs an RenderSystem object by default
*/
RenderSystem::RenderSystem() :
m_coordinateSystemMatrix(Nz::Matrix4f::Identity()),
m_coordinateSystemInvalidated(true)
@ -43,7 +42,6 @@ namespace Ndk
*
* \param entity Pointer to the entity
*/
void RenderSystem::OnEntityRemoved(Entity* entity)
{
m_cameras.Remove(entity);
@ -52,6 +50,12 @@ namespace Ndk
m_lights.Remove(entity);
m_particleGroups.Remove(entity);
m_pointSpotLights.Remove(entity);
if (entity->HasComponent<GraphicsComponent>())
{
GraphicsComponent& gfxComponent = entity->GetComponent<GraphicsComponent>();
gfxComponent.RemoveFromCullingList(&m_drawableCulling);
}
}
/*!
@ -60,7 +64,6 @@ namespace Ndk
* \param entity Pointer to the entity
* \param justAdded Is the entity newly added
*/
void RenderSystem::OnEntityValidation(Entity* entity, bool justAdded)
{
NazaraUnused(justAdded);
@ -77,10 +80,26 @@ namespace Ndk
m_cameras.Remove(entity);
if (entity->HasComponent<GraphicsComponent>() && entity->HasComponent<NodeComponent>())
{
m_drawables.Insert(entity);
if (justAdded)
{
GraphicsComponent& gfxComponent = entity->GetComponent<GraphicsComponent>();
gfxComponent.AddToCullingList(&m_drawableCulling);
}
}
else
{
m_drawables.Remove(entity);
if (entity->HasComponent<GraphicsComponent>())
{
GraphicsComponent& gfxComponent = entity->GetComponent<GraphicsComponent>();
gfxComponent.RemoveFromCullingList(&m_drawableCulling);
}
}
if (entity->HasComponent<LightComponent>() && entity->HasComponent<NodeComponent>())
{
LightComponent& lightComponent = entity->GetComponent<LightComponent>();
@ -141,17 +160,20 @@ namespace Ndk
//UpdateDirectionalShadowMaps(camComponent);
Nz::AbstractRenderQueue* renderQueue = m_renderTechnique->GetRenderQueue();
renderQueue->Clear();
//TODO: Culling
// To make sure the bounding volume used by the culling list is updated
for (const Ndk::EntityHandle& drawable : m_drawables)
{
GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>();
NodeComponent& drawableNode = drawable->GetComponent<NodeComponent>();
graphicsComponent.AddToRenderQueue(renderQueue);
graphicsComponent.EnsureBoundingVolumeUpdate();
}
m_drawableCulling.Cull(camComponent.GetFrustum());
renderQueue->Clear();
for (const GraphicsComponent* gfxComponent : m_drawableCulling)
gfxComponent->AddToRenderQueue(renderQueue);
for (const Ndk::EntityHandle& light : m_lights)
{
LightComponent& lightComponent = light->GetComponent<LightComponent>();
@ -165,7 +187,7 @@ namespace Ndk
{
ParticleGroupComponent& groupComponent = particleGroup->GetComponent<ParticleGroupComponent>();
groupComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::Identity()); //< ParticleGroup doesn't use Matrix4f
groupComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::Identity()); //< ParticleGroup doesn't use any transform matrix (yet)
}
camComponent.ApplyView();

View File

@ -0,0 +1,174 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_CULLINGLIST_HPP
#define NAZARA_CULLINGLIST_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/Signal.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Math/BoundingVolume.hpp>
#include <Nazara/Math/Frustum.hpp>
#include <Nazara/Math/Sphere.hpp>
#include <vector>
namespace Nz
{
template<typename T>
class CullingList
{
public:
template<CullTest T> class Entry;
class NoTestEntry;
class SphereEntry;
class VolumeEntry;
template<CullTest T> friend class Entry;
friend NoTestEntry;
friend SphereEntry;
friend VolumeEntry;
using ResultContainer = std::vector<const T*>;
CullingList() = default;
CullingList(const CullingList& renderable) = delete;
CullingList(CullingList&& renderable) = delete;
~CullingList();
std::size_t Cull(const Frustumf& frustum);
NoTestEntry RegisterNoTest(const T* renderable);
SphereEntry RegisterSphereTest(const T* renderable);
VolumeEntry RegisterVolumeTest(const T* renderable);
CullingList& operator=(const CullingList& renderable) = delete;
CullingList& operator=(CullingList&& renderable) = delete;
// STL API
typename ResultContainer::iterator begin();
typename ResultContainer::const_iterator begin() const;
typename ResultContainer::const_iterator cbegin() const;
typename ResultContainer::const_iterator cend() const;
typename ResultContainer::const_reverse_iterator crbegin() const;
typename ResultContainer::const_reverse_iterator crend() const;
bool empty() const;
typename ResultContainer::iterator end();
typename ResultContainer::const_iterator end() const;
typename ResultContainer::reverse_iterator rbegin();
typename ResultContainer::const_reverse_iterator rbegin() const;
typename ResultContainer::reverse_iterator rend();
typename ResultContainer::const_reverse_iterator rend() const;
typename ResultContainer::size_type size() const;
NazaraSignal(OnCullingListRelease, CullingList* /*cullingList*/);
private:
inline void NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr);
inline void NotifyRelease(CullTest type, std::size_t index);
inline void NotifySphereUpdate(std::size_t index, const Spheref& sphere);
inline void NotifyVolumeUpdate(std::size_t index, const BoundingVolumef& boundingVolume);
struct NoTestVisibilityEntry
{
NoTestEntry* entry;
const T* renderable;
};
struct SphereVisibilityEntry
{
Spheref sphere;
SphereEntry* entry;
const T* renderable;
};
struct VolumeVisibilityEntry
{
BoundingVolumef volume;
VolumeEntry* entry;
const T* renderable;
};
std::vector<NoTestVisibilityEntry> m_noTestList;
std::vector<SphereVisibilityEntry> m_sphereTestList;
std::vector<VolumeVisibilityEntry> m_volumeTestList;
ResultContainer m_results;
};
template<typename T>
template<typename CullTest Type>
class CullingList<T>::Entry
{
public:
Entry();
Entry(const Entry&) = delete;
Entry(Entry&& entry);
~Entry();
CullingList* GetParent() const;
void UpdateIndex(std::size_t index);
Entry& operator=(const Entry&) = delete;
Entry& operator=(Entry&& entry);
protected:
Entry(CullingList* parent, std::size_t index);
std::size_t m_index;
CullingList* m_parent;
};
template<typename T>
class CullingList<T>::NoTestEntry : public CullingList::Entry<CullTest::NoTest>
{
friend CullingList;
public:
NoTestEntry();
private:
NoTestEntry(CullingList* parent, std::size_t index);
};
template<typename T>
class CullingList<T>::SphereEntry : public CullingList::Entry<CullTest::Sphere>
{
friend CullingList;
public:
SphereEntry();
void UpdateSphere(const Spheref& sphere);
private:
SphereEntry(CullingList* parent, std::size_t index);
};
template<typename T>
class CullingList<T>::VolumeEntry : public CullingList::Entry<CullTest::Volume>
{
friend CullingList;
public:
VolumeEntry();
void UpdateVolume(const BoundingVolumef& sphere);
private:
VolumeEntry(CullingList* parent, std::size_t index);
};
}
#include <Nazara/Graphics/CullingList.inl>
#endif // NAZARA_CULLINGLIST_HPP

View File

@ -0,0 +1,363 @@
#include "CullingList.hpp"
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
namespace Nz
{
template<typename T>
inline CullingList<T>::~CullingList()
{
OnCullingListRelease(this);
}
template<typename T>
std::size_t CullingList<T>::Cull(const Frustumf& frustum)
{
m_results.clear();
std::size_t visibleHash = 0U;
for (const NoTestVisibilityEntry& entry : m_noTestList)
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
}
for (const SphereVisibilityEntry& entry : m_sphereTestList)
{
if (frustum.Contains(entry.sphere))
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
}
}
for (const VolumeVisibilityEntry& entry : m_volumeTestList)
{
if (frustum.Contains(entry.volume))
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
}
}
return visibleHash;
}
template<typename T>
typename CullingList<T>::NoTestEntry CullingList<T>::RegisterNoTest(const T* renderable)
{
NoTestEntry entry(this, m_noTestList.size());
m_noTestList.emplace_back(NoTestVisibilityEntry{&entry, renderable}); //< Address of entry will be updated when moving
return entry;
}
template<typename T>
typename CullingList<T>::SphereEntry CullingList<T>::RegisterSphereTest(const T* renderable)
{
SphereEntry entry(this, m_sphereTestList.size());
m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &entry, renderable}); //< Address of entry will be updated when moving
return entry;
}
template<typename T>
typename CullingList<T>::VolumeEntry CullingList<T>::RegisterVolumeTest(const T* renderable)
{
VolumeEntry entry(this, m_volumeTestList.size());
m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &entry, renderable}); //< Address of entry will be updated when moving
return entry;
}
// Interface STD
template<typename T>
typename CullingList<T>::ResultContainer::iterator CullingList<T>::begin()
{
return m_results.begin();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_iterator CullingList<T>::begin() const
{
return m_results.begin();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_iterator CullingList<T>::cbegin() const
{
return m_results.cbegin();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_iterator CullingList<T>::cend() const
{
return m_results.cend();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_reverse_iterator CullingList<T>::crbegin() const
{
return m_results.crbegin();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_reverse_iterator CullingList<T>::crend() const
{
return m_results.crend();
}
template<typename T>
bool CullingList<T>::empty() const
{
return m_results.empty();
}
template<typename T>
typename CullingList<T>::ResultContainer::iterator CullingList<T>::end()
{
return m_results.end();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_iterator CullingList<T>::end() const
{
return m_results.end();
}
template<typename T>
typename CullingList<T>::ResultContainer::reverse_iterator CullingList<T>::rbegin()
{
return m_results.rbegin();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_reverse_iterator CullingList<T>::rbegin() const
{
return m_results.rbegin();
}
template<typename T>
typename CullingList<T>::ResultContainer::reverse_iterator CullingList<T>::rend()
{
return m_results.rend();
}
template<typename T>
typename CullingList<T>::ResultContainer::const_reverse_iterator CullingList<T>::rend() const
{
return m_results.rend();
}
template<typename T>
typename CullingList<T>::ResultContainer::size_type CullingList<T>::size() const
{
return m_results.size();
}
template<typename T>
void CullingList<T>::NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr)
{
switch (type)
{
case CullTest::NoTest:
{
NoTestVisibilityEntry& entry = m_noTestList[index];
NazaraAssert(entry.entry == oldPtr, "Invalid entry");
entry.entry = static_cast<NoTestEntry*>(newPtr);
break;
}
case CullTest::Sphere:
{
SphereVisibilityEntry& entry = m_sphereTestList[index];
NazaraAssert(entry.entry == oldPtr, "Invalid sphere entry");
entry.entry = static_cast<SphereEntry*>(newPtr);
break;
}
case CullTest::Volume:
{
VolumeVisibilityEntry& entry = m_volumeTestList[index];
NazaraAssert(entry.entry == oldPtr, "Invalid volume entry");
entry.entry = static_cast<VolumeEntry*>(newPtr);
break;
}
default:
NazaraInternalError("Unhandled culltype");
break;
}
}
template<typename T>
void CullingList<T>::NotifyRelease(CullTest type, std::size_t index)
{
switch (type)
{
case CullTest::NoTest:
{
m_noTestList[index] = std::move(m_noTestList.back());
m_noTestList[index].entry->UpdateIndex(index);
m_noTestList.pop_back();
break;
}
case CullTest::Sphere:
{
m_sphereTestList[index] = std::move(m_sphereTestList.back());
m_sphereTestList[index].entry->UpdateIndex(index);
m_sphereTestList.pop_back();
break;
}
case CullTest::Volume:
{
m_volumeTestList[index] = std::move(m_volumeTestList.back());
m_volumeTestList[index].entry->UpdateIndex(index);
m_volumeTestList.pop_back();
break;
}
default:
NazaraInternalError("Unhandled culltype");
break;
}
}
template<typename T>
void CullingList<T>::NotifySphereUpdate(std::size_t index, const Spheref& sphere)
{
m_sphereTestList[index].sphere = sphere;
}
template<typename T>
void CullingList<T>::NotifyVolumeUpdate(std::size_t index, const BoundingVolumef& boundingVolume)
{
m_volumeTestList[index].volume = boundingVolume;
}
//////////////////////////////////////////////////////////////////////////
template<typename T>
template<CullTest Type>
CullingList<T>::Entry<Type>::Entry() :
m_parent(nullptr)
{
}
template<typename T>
template<CullTest Type>
CullingList<T>::Entry<Type>::Entry(CullingList* parent, std::size_t index) :
m_index(index),
m_parent(parent)
{
}
template<typename T>
template<CullTest Type>
CullingList<T>::Entry<Type>::Entry(Entry&& entry) :
m_index(entry.m_index),
m_parent(entry.m_parent)
{
if (m_parent)
m_parent->NotifyMovement(Type, m_index, &entry, this);
entry.m_parent = nullptr;
}
template<typename T>
template<CullTest Type>
CullingList<T>::Entry<Type>::~Entry()
{
if (m_parent)
m_parent->NotifyRelease(Type, m_index);
}
template<typename T>
template<CullTest Type>
CullingList<T>* CullingList<T>::Entry<Type>::GetParent() const
{
return m_parent;
}
template<typename T>
template<CullTest Type>
void CullingList<T>::Entry<Type>::UpdateIndex(std::size_t index)
{
m_index = index;
}
template<typename T>
template<CullTest Type>
typename CullingList<T>::Entry<Type>& CullingList<T>::Entry<Type>::operator=(Entry&& entry)
{
m_index = entry.m_index;
m_parent = entry.m_parent;
if (m_parent)
m_parent->NotifyMovement(Type, m_index, &entry, this);
entry.m_parent = nullptr;
return *this;
}
//////////////////////////////////////////////////////////////////////////
template<typename T>
CullingList<T>::NoTestEntry::NoTestEntry() :
Entry()
{
}
template<typename T>
CullingList<T>::NoTestEntry::NoTestEntry(CullingList* parent, std::size_t index) :
Entry(parent, index)
{
}
//////////////////////////////////////////////////////////////////////////
template<typename T>
CullingList<T>::SphereEntry::SphereEntry() :
Entry()
{
}
template<typename T>
CullingList<T>::SphereEntry::SphereEntry(CullingList* parent, std::size_t index) :
Entry(parent, index)
{
}
template<typename T>
void CullingList<T>::SphereEntry::UpdateSphere(const Spheref& sphere)
{
m_parent->NotifySphereUpdate(m_index, sphere);
}
//////////////////////////////////////////////////////////////////////////
template<typename T>
CullingList<T>::VolumeEntry::VolumeEntry() :
Entry()
{
}
template<typename T>
CullingList<T>::VolumeEntry::VolumeEntry(CullingList* parent, std::size_t index) :
Entry(parent, index)
{
}
template<typename T>
void Nz::CullingList<T>::VolumeEntry::UpdateVolume(const BoundingVolumef& volume)
{
m_parent->NotifyVolumeUpdate(m_index, volume);
}
}

View File

@ -19,6 +19,13 @@ namespace Nz
BackgroundType_Max = BackgroundType_User
};
enum class CullTest
{
NoTest,
Sphere,
Volume
};
enum ProjectionType
{
ProjectionType_Orthogonal,

View File

@ -13,6 +13,7 @@
#include <Nazara/Core/RefCounted.hpp>
#include <Nazara/Core/Signal.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/CullingList.hpp>
#include <Nazara/Math/BoundingVolume.hpp>
#include <Nazara/Math/Frustum.hpp>
#include <Nazara/Math/Matrix4.hpp>
@ -31,15 +32,17 @@ namespace Nz
public:
struct InstanceData;
InstancedRenderable() = default;
inline InstancedRenderable();
inline InstancedRenderable(const InstancedRenderable& renderable);
InstancedRenderable(InstancedRenderable&& renderable) = delete;
virtual ~InstancedRenderable();
virtual void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const = 0;
virtual bool Cull(const Frustumf& frustum, const InstanceData& instanceData) const;
inline void EnsureBoundingVolumeUpdated() const;
virtual void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const = 0;
virtual bool Cull(const Frustumf& frustum, const InstanceData& instanceData) const;
virtual const BoundingVolumef& GetBoundingVolume() const;
virtual void InvalidateData(InstanceData* instanceData, UInt32 flags) const;
virtual void UpdateBoundingVolume(InstanceData* instanceData) const;
@ -49,6 +52,7 @@ namespace Nz
InstancedRenderable& operator=(InstancedRenderable&& renderable) = delete;
// Signals:
NazaraSignal(OnInstancedRenderableInvalidateBoundingVolume, const InstancedRenderable* /*instancedRenderable*/);
NazaraSignal(OnInstancedRenderableInvalidateData, const InstancedRenderable* /*instancedRenderable*/, UInt32 /*flags*/);
NazaraSignal(OnInstancedRenderableRelease, const InstancedRenderable* /*instancedRenderable*/);
@ -83,14 +87,16 @@ namespace Nz
};
protected:
virtual void MakeBoundingVolume() const = 0;
void InvalidateBoundingVolume();
inline void InvalidateBoundingVolume();
inline void InvalidateInstanceData(UInt32 flags);
inline void UpdateBoundingVolume() const;
virtual void MakeBoundingVolume() const = 0;
mutable BoundingVolumef m_boundingVolume;
private:
inline void UpdateBoundingVolume() const;
mutable bool m_boundingVolumeUpdated;
static InstancedRenderableLibrary::LibraryMap s_library;

View File

@ -4,12 +4,19 @@
namespace Nz
{
/*!
* \brief Constructs a InstancedRenderable object by default
*/
inline InstancedRenderable::InstancedRenderable() :
m_boundingVolumeUpdated(false)
{
}
/*!
* \brief Constructs a InstancedRenderable object by assignation
*
* \param renderable InstancedRenderable to copy into this
*/
inline InstancedRenderable::InstancedRenderable(const InstancedRenderable& renderable) :
RefCounted(),
m_boundingVolume(renderable.m_boundingVolume),
@ -34,6 +41,8 @@ namespace Nz
inline void InstancedRenderable::InvalidateBoundingVolume()
{
m_boundingVolumeUpdated = false;
OnInstancedRenderableInvalidateBoundingVolume(this);
}
/*!
@ -69,6 +78,7 @@ namespace Nz
inline void InstancedRenderable::UpdateBoundingVolume() const
{
MakeBoundingVolume();
m_boundingVolumeUpdated = true;
}
}

View File

@ -25,7 +25,9 @@ namespace Nz
virtual ~Renderable();
virtual void AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const = 0;
virtual bool Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const;
inline void EnsureBoundingVolumeUpdated() const;
virtual const BoundingVolumef& GetBoundingVolume() const;
virtual void UpdateBoundingVolume(const Matrix4f& transformMatrix);
@ -36,11 +38,12 @@ namespace Nz
protected:
virtual void MakeBoundingVolume() const = 0;
inline void InvalidateBoundingVolume();
inline void UpdateBoundingVolume() const;
mutable BoundingVolumef m_boundingVolume;
private:
inline void UpdateBoundingVolume() const;
mutable bool m_boundingVolumeUpdated;
};
}