Sdk/RenderSystem: Regenerate renderqueue only when needed

Former-commit-id: 8883c832e1ea34172cf7b21e949f931f188542cf [formerly 3e5d67644e985fd6b5dc0d24bd431e575b9192b7] [formerly 9240e84ee3e77f9b4fa525c5e614ee32c4a59501 [formerly 4f5f4c5d6f366619e888feb8e7fcc8379cf0fabd]]
Former-commit-id: ebc0908d6be73e8509e322450bfe6c2cfcc89ae8 [formerly b621f6434040e1c78841d51e905eda23fdad9b62]
Former-commit-id: 382e99294b674b9740dc9c9b5f5e6dd39b103c52
This commit is contained in:
Lynix 2016-09-15 14:21:06 +02:00
parent 0062a312a7
commit 416441bd3e
7 changed files with 145 additions and 26 deletions

View File

@ -61,6 +61,8 @@ namespace Ndk
inline void SetZFar(float zFar);
inline void SetZNear(float zNear);
inline bool UpdateVisibility(std::size_t visibilityHash);
static ComponentIndex componentIndex;
private:
@ -86,6 +88,7 @@ namespace Ndk
NazaraSlot(Nz::RenderTarget, OnRenderTargetRelease, m_targetReleaseSlot);
NazaraSlot(Nz::RenderTarget, OnRenderTargetSizeChange, m_targetResizeSlot);
std::size_t m_visibilityHash;
Nz::ProjectionType m_projectionType;
mutable Nz::Frustumf m_frustum;
mutable Nz::Matrix4f m_projectionMatrix;

View File

@ -13,6 +13,7 @@ namespace Ndk
*/
inline CameraComponent::CameraComponent() :
m_visibilityHash(0U),
m_projectionType(Nz::ProjectionType_Perspective),
m_targetRegion(0.f, 0.f, 1.f, 1.f),
m_target(nullptr),
@ -38,6 +39,7 @@ namespace Ndk
inline CameraComponent::CameraComponent(const CameraComponent& camera) :
Component(camera),
AbstractViewer(camera),
m_visibilityHash(camera.m_visibilityHash),
m_projectionType(camera.m_projectionType),
m_targetRegion(camera.m_targetRegion),
m_target(nullptr),
@ -371,6 +373,26 @@ namespace Ndk
InvalidateProjectionMatrix();
}
/*!
* \brief Update the camera component visibility hash
*
* This is used with CullingList (which produce a visibility hash)
*
* \param visibilityHash New visibility hash
*
* \return True if the visibility hash is not the same as before
*/
inline bool CameraComponent::UpdateVisibility(std::size_t visibilityHash)
{
if (m_visibilityHash != visibilityHash)
{
m_visibilityHash = visibilityHash;
return true;
}
return false;
}
/*!
* \brief Invalidates the frustum
*/

View File

@ -69,6 +69,7 @@ namespace Ndk
Nz::Matrix4f m_coordinateSystemMatrix;
Nz::RenderTexture m_shadowRT;
bool m_coordinateSystemInvalidated;
bool m_forceRenderQueueInvalidation;
};
}

View File

@ -89,6 +89,9 @@ namespace Ndk
Renderable& r = m_renderables[index];
r.dataUpdated = false;
r.renderable->InvalidateData(&r.data, flags);
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
entry.listEntry.ForceInvalidation();
}
/*!

View File

@ -30,7 +30,8 @@ namespace Ndk
*/
RenderSystem::RenderSystem() :
m_coordinateSystemMatrix(Nz::Matrix4f::Identity()),
m_coordinateSystemInvalidated(true)
m_coordinateSystemInvalidated(true),
m_forceRenderQueueInvalidation(false)
{
ChangeRenderTechnique<Nz::ForwardRenderTechnique>();
SetDefaultBackground(Nz::ColorBackground::New());
@ -44,6 +45,8 @@ namespace Ndk
*/
void RenderSystem::OnEntityRemoved(Entity* entity)
{
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
m_cameras.Remove(entity);
m_directionalLights.Remove(entity);
m_drawables.Remove(entity);
@ -102,6 +105,8 @@ namespace Ndk
if (entity->HasComponent<LightComponent>() && entity->HasComponent<NodeComponent>())
{
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
LightComponent& lightComponent = entity->GetComponent<LightComponent>();
if (lightComponent.GetLightType() == Nz::LightType_Directional)
{
@ -118,16 +123,26 @@ namespace Ndk
}
else
{
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
m_directionalLights.Remove(entity);
m_lights.Remove(entity);
m_pointSpotLights.Remove(entity);
}
if (entity->HasComponent<ParticleGroupComponent>())
{
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
m_particleGroups.Insert(entity);
}
else
{
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
m_particleGroups.Remove(entity);
}
}
/*!
* \brief Operation to perform when system is updated
@ -168,8 +183,11 @@ namespace Ndk
graphicsComponent.EnsureBoundingVolumeUpdate();
}
m_drawableCulling.Cull(camComponent.GetFrustum());
bool forceInvalidation = false;
std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation);
if (camComponent.UpdateVisibility(visibilityHash) || m_forceRenderQueueInvalidation || forceInvalidation)
{
renderQueue->Clear();
for (const GraphicsComponent* gfxComponent : m_drawableCulling)
gfxComponent->AddToRenderQueue(renderQueue);
@ -190,6 +208,9 @@ namespace Ndk
groupComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::Identity()); //< ParticleGroup doesn't use any transform matrix (yet)
}
m_forceRenderQueueInvalidation = false;
}
camComponent.ApplyView();
Nz::SceneData sceneData;

View File

@ -39,7 +39,7 @@ namespace Nz
CullingList(CullingList&& renderable) = delete;
~CullingList();
std::size_t Cull(const Frustumf& frustum);
std::size_t Cull(const Frustumf& frustum, bool* forceInvalidation = nullptr);
NoTestEntry RegisterNoTest(const T* renderable);
SphereEntry RegisterSphereTest(const T* renderable);
@ -73,6 +73,7 @@ namespace Nz
NazaraSignal(OnCullingListRelease, CullingList* /*cullingList*/);
private:
inline void NotifyForceInvalidation(CullTest type, std::size_t index);
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);
@ -82,6 +83,7 @@ namespace Nz
{
NoTestEntry* entry;
const T* renderable;
bool forceInvalidation;
};
struct SphereVisibilityEntry
@ -89,6 +91,7 @@ namespace Nz
Spheref sphere;
SphereEntry* entry;
const T* renderable;
bool forceInvalidation;
};
struct VolumeVisibilityEntry
@ -96,6 +99,7 @@ namespace Nz
BoundingVolumef volume;
VolumeEntry* entry;
const T* renderable;
bool forceInvalidation;
};
std::vector<NoTestVisibilityEntry> m_noTestList;
@ -114,6 +118,8 @@ namespace Nz
Entry(Entry&& entry);
~Entry();
void ForceInvalidation();
CullingList* GetParent() const;
void UpdateIndex(std::size_t index);

View File

@ -1,46 +1,71 @@
#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
#include <Nazara/Graphics/CullingList.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
template<typename T>
inline CullingList<T>::~CullingList()
CullingList<T>::~CullingList()
{
OnCullingListRelease(this);
}
template<typename T>
std::size_t CullingList<T>::Cull(const Frustumf& frustum)
std::size_t CullingList<T>::Cull(const Frustumf& frustum, bool* forceInvalidation)
{
m_results.clear();
bool forcedInvalidation = false;
std::size_t visibleHash = 0U;
for (const NoTestVisibilityEntry& entry : m_noTestList)
for (NoTestVisibilityEntry& entry : m_noTestList)
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
if (entry.forceInvalidation)
{
forcedInvalidation = true;
entry.forceInvalidation = false;
}
}
for (const SphereVisibilityEntry& entry : m_sphereTestList)
for (SphereVisibilityEntry& entry : m_sphereTestList)
{
if (frustum.Contains(entry.sphere))
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
if (entry.forceInvalidation)
{
forcedInvalidation = true;
entry.forceInvalidation = false;
}
}
}
for (const VolumeVisibilityEntry& entry : m_volumeTestList)
for (VolumeVisibilityEntry& entry : m_volumeTestList)
{
if (frustum.Contains(entry.volume))
{
m_results.push_back(entry.renderable);
Nz::HashCombine(visibleHash, entry.renderable);
if (entry.forceInvalidation)
{
forcedInvalidation = true;
entry.forceInvalidation = false;
}
}
}
if (forceInvalidation)
*forceInvalidation = forcedInvalidation;
return visibleHash;
}
@ -49,7 +74,7 @@ namespace Nz
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
m_noTestList.emplace_back(NoTestVisibilityEntry{&entry, renderable, false}); //< Address of entry will be updated when moving
return entry;
}
@ -58,7 +83,7 @@ namespace Nz
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
m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &entry, renderable, false}); //< Address of entry will be updated when moving
return entry;
}
@ -67,7 +92,7 @@ namespace Nz
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
m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &entry, renderable, false}); //< Address of entry will be updated when moving
return entry;
}
@ -157,6 +182,35 @@ namespace Nz
return m_results.size();
}
template<typename T>
void CullingList<T>::NotifyForceInvalidation(CullTest type, std::size_t index)
{
switch (type)
{
case CullTest::NoTest:
{
m_noTestList[index].forceInvalidation = true;
break;
}
case CullTest::Sphere:
{
m_sphereTestList[index].forceInvalidation = true;
break;
}
case CullTest::Volume:
{
m_volumeTestList[index].forceInvalidation = true;
break;
}
default:
NazaraInternalError("Unhandled culltype");
break;
}
}
template<typename T>
void CullingList<T>::NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr)
{
@ -279,6 +333,13 @@ namespace Nz
m_parent->NotifyRelease(Type, m_index);
}
template<typename T>
template<CullTest Type>
void CullingList<T>::Entry<Type>::ForceInvalidation()
{
m_parent->NotifyForceInvalidation(Type, m_index);
}
template<typename T>
template<CullTest Type>
CullingList<T>* CullingList<T>::Entry<Type>::GetParent() const
@ -361,3 +422,5 @@ namespace Nz
m_parent->NotifyVolumeUpdate(m_index, volume);
}
}
#include <Nazara/Graphics/DebugOff.hpp>