From e42ff5b18a06c242e98099fd04963e78c8bad749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 31 Aug 2018 17:32:48 +0200 Subject: [PATCH] Sdk/GraphicsComponent: Remake bounding volume handling GraphicsComponent now only have an AABB but their instanced renderable now have individual BoundingVolume --- .../NDK/Components/GraphicsComponent.hpp | 37 ++++---- .../NDK/Components/GraphicsComponent.inl | 87 ++++++++++--------- SDK/src/NDK/Components/GraphicsComponent.cpp | 54 ++++++------ SDK/src/NDK/Systems/DebugSystem.cpp | 33 ++++--- SDK/src/NDK/Systems/RenderSystem.cpp | 5 +- SDK/src/NDK/Widgets/ButtonWidget.cpp | 2 +- 6 files changed, 118 insertions(+), 100 deletions(-) diff --git a/SDK/include/NDK/Components/GraphicsComponent.hpp b/SDK/include/NDK/Components/GraphicsComponent.hpp index 3e7b05def..d55ad0035 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.hpp +++ b/SDK/include/NDK/Components/GraphicsComponent.hpp @@ -44,15 +44,17 @@ namespace Ndk inline bool DoesRequireRealTimeReflections() const; + inline void EnsureBoundingVolumesUpdate() const; + inline void EnsureTransformMatrixUpdate() const; + template void ForEachRenderable(const Func& func) const; - inline void EnsureBoundingVolumeUpdate() const; - inline void EnsureTransformMatrixUpdate() const; + inline const Nz::Boxf& GetAABB() const; inline void GetAttachedRenderables(RenderableList* renderables) const; inline std::size_t GetAttachedRenderableCount() const; - inline const Nz::BoundingVolumef& GetBoundingVolume() const; + inline const Nz::BoundingVolumef& GetBoundingVolume(std::size_t renderableIndex) const; inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const; @@ -68,7 +70,7 @@ namespace Ndk void ConnectInstancedRenderableSignals(Renderable& renderable); - inline void InvalidateBoundingVolume() const; + inline void InvalidateAABB() const; 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(); @@ -89,11 +91,20 @@ namespace Ndk void UnregisterMaterial(Nz::Material* material); - void UpdateBoundingVolume() const; + void UpdateBoundingVolumes() const; void UpdateTransformMatrix() const; NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot); + using CullingListBoxEntry = GraphicsComponentCullingList::BoxEntry; + + struct CullingBoxEntry + { + CullingListBoxEntry listEntry; + + NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot); + }; + struct MaterialEntry { NazaraSlot(Nz::Material, OnMaterialReflectionModeChange, reflectionModelChangeSlot); @@ -128,29 +139,21 @@ namespace Ndk NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableResetMaterials, renderableResetMaterialsSlot); NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableSkinChange, renderableSkinChangeSlot); + mutable Nz::BoundingVolumef boundingVolume; mutable Nz::InstancedRenderable::InstanceData data; Nz::InstancedRenderableRef renderable; mutable bool dataUpdated; }; - using VolumeCullingListEntry = GraphicsComponentCullingList::VolumeEntry; - - struct VolumeCullingEntry - { - VolumeCullingListEntry listEntry; - - NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot); - }; - std::size_t m_reflectiveMaterialCount; - mutable std::vector m_volumeCullingEntries; + mutable std::vector m_cullingBoxEntries; std::vector m_renderables; std::unordered_map m_materialEntries; - mutable Nz::BoundingVolumef m_boundingVolume; + mutable Nz::Boxf m_aabb; mutable Nz::Matrix4f m_transformMatrix; Nz::Recti m_scissorRect; Nz::TextureRef m_reflectionMap; - mutable bool m_boundingVolumeUpdated; + mutable bool m_boundingVolumesUpdated; mutable bool m_transformMatrixUpdated; unsigned int m_reflectionMapSize; }; diff --git a/SDK/include/NDK/Components/GraphicsComponent.inl b/SDK/include/NDK/Components/GraphicsComponent.inl index 08dc3c867..127be42f5 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.inl +++ b/SDK/include/NDK/Components/GraphicsComponent.inl @@ -24,10 +24,10 @@ namespace Ndk Component(graphicsComponent), HandledObject(graphicsComponent), m_reflectiveMaterialCount(0), - m_boundingVolume(graphicsComponent.m_boundingVolume), + m_aabb(graphicsComponent.m_aabb), m_transformMatrix(graphicsComponent.m_transformMatrix), m_scissorRect(graphicsComponent.m_scissorRect), - m_boundingVolumeUpdated(graphicsComponent.m_boundingVolumeUpdated), + m_boundingVolumesUpdated(graphicsComponent.m_boundingVolumesUpdated), m_transformMatrixUpdated(graphicsComponent.m_transformMatrixUpdated) { m_renderables.reserve(graphicsComponent.m_renderables.size()); @@ -37,12 +37,12 @@ namespace Ndk inline void GraphicsComponent::AddToCullingList(GraphicsComponentCullingList* cullingList) const { - m_volumeCullingEntries.emplace_back(); - VolumeCullingEntry& entry = m_volumeCullingEntries.back(); + m_cullingBoxEntries.emplace_back(); + CullingBoxEntry& entry = m_cullingBoxEntries.back(); entry.cullingListReleaseSlot.Connect(cullingList->OnCullingListRelease, this, &GraphicsComponent::RemoveFromCullingList); - entry.listEntry = cullingList->RegisterVolumeTest(this); + entry.listEntry = cullingList->RegisterBoxTest(this); - InvalidateBoundingVolume(); + InvalidateAABB(); } /*! @@ -71,7 +71,7 @@ namespace Ndk InvalidateReflectionMap(); } - InvalidateBoundingVolume(); + InvalidateAABB(); } /*! @@ -86,7 +86,7 @@ namespace Ndk { if (it->renderable == renderable) { - InvalidateBoundingVolume(); + InvalidateAABB(); std::size_t materialCount = renderable->GetMaterialCount(); for (std::size_t i = 0; i < materialCount; ++i) @@ -110,26 +110,14 @@ namespace Ndk return m_reflectiveMaterialCount != 0 && m_reflectionMap; } - /*! - * \brief Calls a function for every renderable attached to this component - * - * \param func Callback function which will be called with renderable data - */ - template - void GraphicsComponent::ForEachRenderable(const Func& func) const - { - for (const auto& renderableData : m_renderables) - func(renderableData.renderable, renderableData.data.localMatrix, renderableData.data.renderOrder); - } - /*! * \brief Ensures the bounding volume is up to date */ - inline void GraphicsComponent::EnsureBoundingVolumeUpdate() const + inline void GraphicsComponent::EnsureBoundingVolumesUpdate() const { - if (!m_boundingVolumeUpdated) - UpdateBoundingVolume(); + if (!m_boundingVolumesUpdated) + UpdateBoundingVolumes(); } /*! @@ -142,6 +130,17 @@ namespace Ndk UpdateTransformMatrix(); } + /*! + * \brief Gets the axis-aligned bounding box of the entity + * \return A constant reference to the AABB + */ + inline const Nz::Boxf& GraphicsComponent::GetAABB() const + { + EnsureBoundingVolumesUpdate(); + + return m_aabb; + } + /*! * \brief Gets the set of renderable elements * @@ -169,28 +168,36 @@ namespace Ndk return m_renderables.size(); } - /*! - * \brief Gets the bouding volume of the entity - * \return A constant reference to the bounding volume - */ - - inline const Nz::BoundingVolumef& GraphicsComponent::GetBoundingVolume() const + inline const Nz::BoundingVolumef& GraphicsComponent::GetBoundingVolume(std::size_t renderableIndex) const { - EnsureBoundingVolumeUpdate(); + EnsureBoundingVolumesUpdate(); - return m_boundingVolume; + assert(renderableIndex < m_renderables.size()); + return m_renderables[renderableIndex].boundingVolume; + } + + /*! + * \brief Calls a function for every renderable attached to this component + * + * \param func Callback function which will be called with renderable data + */ + template + void GraphicsComponent::ForEachRenderable(const Func& func) const + { + for (const auto& renderableData : m_renderables) + func(renderableData.renderable, renderableData.data.localMatrix, renderableData.data.renderOrder); } inline void GraphicsComponent::RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const { - for (auto it = m_volumeCullingEntries.begin(); it != m_volumeCullingEntries.end(); ++it) + for (auto it = m_cullingBoxEntries.begin(); it != m_cullingBoxEntries.end(); ++it) { if (it->listEntry.GetParent() == cullingList) { - if (m_volumeCullingEntries.size() > 1) - *it = std::move(m_volumeCullingEntries.back()); + if (m_cullingBoxEntries.size() > 1) + *it = std::move(m_cullingBoxEntries.back()); - m_volumeCullingEntries.pop_back(); + m_cullingBoxEntries.pop_back(); break; } } @@ -200,7 +207,7 @@ namespace Ndk { m_scissorRect = scissorRect; - for (VolumeCullingEntry& entry : m_volumeCullingEntries) + for (CullingBoxEntry& entry : m_cullingBoxEntries) entry.listEntry.ForceInvalidation(); //< Invalidate render queues } @@ -212,7 +219,7 @@ namespace Ndk { renderable.data.localMatrix = localMatrix; - InvalidateBoundingVolume(); + InvalidateAABB(); break; } } @@ -234,9 +241,9 @@ namespace Ndk * \brief Invalidates the bounding volume */ - inline void GraphicsComponent::InvalidateBoundingVolume() const + inline void GraphicsComponent::InvalidateAABB() const { - m_boundingVolumeUpdated = false; + m_boundingVolumesUpdated = false; } /*! @@ -257,7 +264,7 @@ namespace Ndk { m_transformMatrixUpdated = false; - InvalidateBoundingVolume(); + InvalidateAABB(); InvalidateRenderables(); } } diff --git a/SDK/src/NDK/Components/GraphicsComponent.cpp b/SDK/src/NDK/Components/GraphicsComponent.cpp index f865e749b..41c25fb90 100644 --- a/SDK/src/NDK/Components/GraphicsComponent.cpp +++ b/SDK/src/NDK/Components/GraphicsComponent.cpp @@ -60,12 +60,12 @@ namespace Ndk for (std::size_t i = 0; i < materialCount; ++i) RegisterMaterial(entry.renderable->GetMaterial(i)); - InvalidateBoundingVolume(); + InvalidateAABB(); } void GraphicsComponent::ConnectInstancedRenderableSignals(Renderable& entry) { - entry.renderableBoundingVolumeInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this](const Nz::InstancedRenderable*) { InvalidateBoundingVolume(); }); + entry.renderableBoundingVolumeInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this](const Nz::InstancedRenderable*) { InvalidateAABB(); }); entry.renderableDataInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1)); entry.renderableMaterialInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateMaterial, this, &GraphicsComponent::InvalidateRenderableMaterial); entry.renderableReleaseSlot.Connect(entry.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach); @@ -82,7 +82,7 @@ namespace Ndk r.dataUpdated = false; r.renderable->InvalidateData(&r.data, flags); - for (VolumeCullingEntry& entry : m_volumeCullingEntries) + for (CullingBoxEntry& entry : m_cullingBoxEntries) entry.listEntry.ForceInvalidation(); } @@ -234,10 +234,10 @@ namespace Ndk NazaraUnused(node); // Our view matrix depends on NodeComponent position/rotation - InvalidateBoundingVolume(); + InvalidateAABB(); InvalidateTransformMatrix(); - for (VolumeCullingEntry& entry : m_volumeCullingEntries) + for (CullingBoxEntry& entry : m_cullingBoxEntries) entry.listEntry.ForceInvalidation(); //< Force invalidation on movement } @@ -263,36 +263,32 @@ namespace Ndk * \brief Updates the bounding volume */ - void GraphicsComponent::UpdateBoundingVolume() const + void GraphicsComponent::UpdateBoundingVolumes() const { EnsureTransformMatrixUpdate(); - m_boundingVolume.MakeNull(); - for (const Renderable& r : m_renderables) - { - Nz::BoundingVolumef boundingVolume = r.renderable->GetBoundingVolume(); - - // 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 newCorner = r.data.localMatrix * (localBox.GetPosition() + localBox.GetLengths()); - Nz::Vector3f newLengths = newCorner - newPos; - - boundingVolume.Set(Nz::Boxf(newPos.x, newPos.y, newPos.z, newLengths.x, newLengths.y, newLengths.z)); - } - - m_boundingVolume.ExtendTo(boundingVolume); - } - RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem(); - m_boundingVolume.Update(Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), m_transformMatrix)); - m_boundingVolumeUpdated = true; + m_aabb.MakeZero(); + for (std::size_t i = 0; i < m_renderables.size(); ++i) + { + const Renderable& r = m_renderables[i]; + r.boundingVolume = r.renderable->GetBoundingVolume(); + if (r.boundingVolume.IsFinite()) + { + r.boundingVolume.Update(Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), Nz::Matrix4f::ConcatenateAffine(r.data.localMatrix, m_transformMatrix))); - for (VolumeCullingEntry& entry : m_volumeCullingEntries) - entry.listEntry.UpdateVolume(m_boundingVolume); + if (i > 0) + m_aabb.ExtendTo(r.boundingVolume.aabb); + else + m_aabb.Set(r.boundingVolume.aabb); + } + } + + m_boundingVolumesUpdated = true; + + for (CullingBoxEntry& entry : m_cullingBoxEntries) + entry.listEntry.UpdateBox(m_aabb); } /*! diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index 0da17c352..407267fcd 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -62,13 +62,22 @@ namespace Ndk const DebugComponent& entityDebug = m_entityOwner->GetComponent(); const GraphicsComponent& entityGfx = m_entityOwner->GetComponent(); - Nz::Boxf aabb = entityGfx.GetBoundingVolume().aabb; + auto DrawBox = [&](const Nz::Boxf& box) + { + Nz::Matrix4f transformMatrix = Nz::Matrix4f::Identity(); + transformMatrix.SetScale(box.GetLengths()); + transformMatrix.SetTranslation(box.GetCenter()); - Nz::Matrix4f transformMatrix = Nz::Matrix4f::Identity(); - transformMatrix.SetScale(aabb.GetLengths()); - transformMatrix.SetTranslation(aabb.GetCenter()); + renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect); + }; - renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect); + //DrawBox(entityGfx.GetAABB()); + for (std::size_t i = 0; i < entityGfx.GetAttachedRenderableCount(); ++i) + { + const Nz::BoundingVolumef& boundingVolume = entityGfx.GetBoundingVolume(i); + if (boundingVolume.IsFinite()) + DrawBox(boundingVolume.aabb); + } } std::unique_ptr Clone() const override @@ -86,10 +95,11 @@ namespace Ndk { NazaraAssert(m_entityOwner, "DebugRenderable has no owner"); - const DebugComponent& entityDebug = m_entityOwner->GetComponent(); + // TODO + /*const DebugComponent& entityDebug = m_entityOwner->GetComponent(); const GraphicsComponent& entityGfx = m_entityOwner->GetComponent(); - Nz::Boxf obb = entityGfx.GetBoundingVolume().obb.localBox; + Nz::Boxf obb = entityGfx.GetAABB().obb.localBox; Nz::Matrix4f transformMatrix = instanceData.transformMatrix; Nz::Vector3f obbCenter = transformMatrix.Transform(obb.GetCenter(), 0.f); //< Apply rotation/scale to obb center, to display it at a correct position @@ -97,7 +107,7 @@ namespace Ndk transformMatrix.ApplyScale(obb.GetLengths()); transformMatrix.ApplyTranslation(obbCenter); - renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect); + renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect);*/ } std::unique_ptr Clone() const override @@ -120,7 +130,7 @@ namespace Ndk */ DebugSystem::DebugSystem() { - Requires(); + Requires(); SetUpdateOrder(1000); //< Update last } @@ -181,6 +191,7 @@ namespace Ndk DebugComponent& entityDebug = entity->GetComponent(); GraphicsComponent& entityGfx = entity->GetComponent(); + NodeComponent& entityNode = entity->GetComponent(); DebugDrawFlags enabledFlags = entityDebug.GetEnabledFlags(); DebugDrawFlags flags = entityDebug.GetFlags(); @@ -195,14 +206,14 @@ namespace Ndk { case DebugDraw::Collider3D: { - const Nz::Boxf& obb = entityGfx.GetBoundingVolume().obb.localBox; + const Nz::Boxf& obb = entityGfx.GetAABB(); Nz::InstancedRenderableRef renderable = GenerateCollision3DMesh(entity); if (renderable) { renderable->SetPersistent(false); - entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter()), DebugDrawOrder); + entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter() - entityNode.GetPosition()), DebugDrawOrder); } entityDebug.UpdateDebugRenderable(option, std::move(renderable)); diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index e79c238b4..f01294865 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -195,11 +195,11 @@ namespace Ndk Nz::AbstractRenderQueue* renderQueue = m_renderTechnique->GetRenderQueue(); - // To make sure the bounding volume used by the culling list is updated + // To make sure the bounding volumes used by the culling list is updated for (const Ndk::EntityHandle& drawable : m_drawables) { GraphicsComponent& graphicsComponent = drawable->GetComponent(); - graphicsComponent.EnsureBoundingVolumeUpdate(); + graphicsComponent.EnsureBoundingVolumesUpdate(); } bool forceInvalidation = false; @@ -220,6 +220,7 @@ namespace Ndk for (const GraphicsComponent* gfxComponent : m_drawableCulling.GetFullyVisibleResults()) gfxComponent->AddToRenderQueue(renderQueue); + // FIXME: We should cull individual renderables here for (const GraphicsComponent* gfxComponent : m_drawableCulling.GetPartiallyVisibleResults()) gfxComponent->AddToRenderQueue(renderQueue); diff --git a/SDK/src/NDK/Widgets/ButtonWidget.cpp b/SDK/src/NDK/Widgets/ButtonWidget.cpp index 5d8360635..f432d86b7 100644 --- a/SDK/src/NDK/Widgets/ButtonWidget.cpp +++ b/SDK/src/NDK/Widgets/ButtonWidget.cpp @@ -87,7 +87,7 @@ namespace Ndk Nz::Vector2f origin = GetContentOrigin(); const Nz::Vector2f& contentSize = GetContentSize(); - Nz::Boxf textBox = m_textEntity->GetComponent().GetBoundingVolume().obb.localBox; + Nz::Boxf textBox = m_textEntity->GetComponent().GetAABB(); m_textEntity->GetComponent().SetPosition(origin.x + contentSize.x / 2 - textBox.width / 2, origin.y + contentSize.y / 2 - textBox.height / 2); }