From de7fee348a47a60fad9f0d72cec7ca7b6345e60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 2 Feb 2022 19:39:46 +0100 Subject: [PATCH] Graphics/ForwardFramePipeline: Frustum cull lights --- examples/PhysicsDemo/main.cpp | 2 +- include/Nazara/Graphics/DirectionalLight.hpp | 2 +- .../Nazara/Graphics/ForwardFramePipeline.hpp | 3 +- include/Nazara/Graphics/Light.hpp | 2 +- include/Nazara/Graphics/PointLight.hpp | 2 +- include/Nazara/Graphics/SpotLight.hpp | 2 +- src/Nazara/Graphics/DirectionalLight.cpp | 2 +- src/Nazara/Graphics/ForwardFramePipeline.cpp | 32 +++++++++++++------ src/Nazara/Graphics/PointLight.cpp | 2 +- src/Nazara/Graphics/SpotLight.cpp | 2 +- 10 files changed, 33 insertions(+), 18 deletions(-) diff --git a/examples/PhysicsDemo/main.cpp b/examples/PhysicsDemo/main.cpp index 0313da7de..2cd8c9216 100644 --- a/examples/PhysicsDemo/main.cpp +++ b/examples/PhysicsDemo/main.cpp @@ -187,7 +187,7 @@ int main() entt::entity headingEntity = registry.create(); { auto& entityLight = registry.emplace(playerEntity); - entityLight.AttachLight(std::make_shared(), 1); + entityLight.AttachLight(std::make_shared(), 1); auto& entityGfx = registry.emplace(playerEntity); entityGfx.AttachRenderable(model, 1); diff --git a/include/Nazara/Graphics/DirectionalLight.hpp b/include/Nazara/Graphics/DirectionalLight.hpp index aea839060..1e93ec200 100644 --- a/include/Nazara/Graphics/DirectionalLight.hpp +++ b/include/Nazara/Graphics/DirectionalLight.hpp @@ -26,7 +26,7 @@ namespace Nz float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; - void FillLightData(void* data) override; + void FillLightData(void* data) const override; inline float GetAmbientFactor() const; inline float GetDiffuseFactor() const; diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 2e680b9d0..69ef2f41e 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -156,7 +156,8 @@ namespace Nz std::unordered_set m_removedWorldInstances; std::vector> m_elementRenderers; std::vector m_renderStates; - std::vector m_visibleLights; + std::vector m_renderableLights; + std::vector m_visibleLights; std::vector m_lightDataBuffers; std::vector m_visibleRenderables; BakedFrameGraph m_bakedFrameGraph; diff --git a/include/Nazara/Graphics/Light.hpp b/include/Nazara/Graphics/Light.hpp index 7f05cb507..61f751dfb 100644 --- a/include/Nazara/Graphics/Light.hpp +++ b/include/Nazara/Graphics/Light.hpp @@ -31,7 +31,7 @@ namespace Nz virtual float ComputeContributionScore(const BoundingVolumef& boundingVolume) const = 0; - virtual void FillLightData(void* data) = 0; + virtual void FillLightData(void* data) const = 0; inline const BoundingVolumef& GetBoundingVolume() const; diff --git a/include/Nazara/Graphics/PointLight.hpp b/include/Nazara/Graphics/PointLight.hpp index 08ae44ce5..f3ad337c4 100644 --- a/include/Nazara/Graphics/PointLight.hpp +++ b/include/Nazara/Graphics/PointLight.hpp @@ -25,7 +25,7 @@ namespace Nz float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; - void FillLightData(void* data) override; + void FillLightData(void* data) const override; inline float GetAmbientFactor() const; inline float GetDiffuseFactor() const; diff --git a/include/Nazara/Graphics/SpotLight.hpp b/include/Nazara/Graphics/SpotLight.hpp index cba896c4c..2f7903aab 100644 --- a/include/Nazara/Graphics/SpotLight.hpp +++ b/include/Nazara/Graphics/SpotLight.hpp @@ -26,7 +26,7 @@ namespace Nz float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; - void FillLightData(void* data) override; + void FillLightData(void* data) const override; inline float GetAmbientFactor() const; inline float GetDiffuseFactor() const; diff --git a/src/Nazara/Graphics/DirectionalLight.cpp b/src/Nazara/Graphics/DirectionalLight.cpp index b1f1b8e06..5b13a9ba1 100644 --- a/src/Nazara/Graphics/DirectionalLight.cpp +++ b/src/Nazara/Graphics/DirectionalLight.cpp @@ -18,7 +18,7 @@ namespace Nz return -std::numeric_limits::infinity(); } - void DirectionalLight::FillLightData(void* data) + void DirectionalLight::FillLightData(void* data) const { auto lightOffset = PredefinedLightData::GetOffsets(); diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index e440d5fdf..603b8d26f 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -244,7 +244,7 @@ namespace Nz BoundingVolumef boundingVolume(renderable->GetAABB()); boundingVolume.Update(worldInstance->GetWorldMatrix()); - if (!frustum.Contains(boundingVolume.aabb)) + if (!frustum.Contains(boundingVolume)) continue; auto& visibleRenderable = m_visibleRenderables.emplace_back(); @@ -259,6 +259,20 @@ namespace Nz visibilityHash = CombineHash(visibilityHash, std::hash()(worldInstance.get())); } + // TODO: Lights update shouldn't trigger a rebuild of the depth prepass + m_visibleLights.clear(); + for (auto&& [light, lightData] : m_lights) + { + const BoundingVolumef& boundingVolume = light->GetBoundingVolume(); + + // TODO: Use more precise tests for point lights (frustum/sphere is cheap) + if (renderMask & lightData.renderMask && frustum.Contains(boundingVolume)) + { + m_visibleLights.push_back(light); + visibilityHash = CombineHash(visibilityHash, std::hash()(light)); + } + } + if (viewerData.visibilityHash != visibilityHash) { viewerData.rebuildDepthPrepass = true; @@ -317,26 +331,26 @@ namespace Nz renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix()); // Select lights (TODO: Cull lights in frustum) - m_visibleLights.clear(); - for (auto&& [light, lightData] : m_lights) + m_renderableLights.clear(); + for (const Light* light : m_visibleLights) { const BoundingVolumef& boundingVolume = light->GetBoundingVolume(); - if ((renderMask & lightData.renderMask) && boundingVolume.Intersect(renderableBoundingVolume.aabb)) - m_visibleLights.push_back(light); + if (boundingVolume.Intersect(renderableBoundingVolume.aabb)) + m_renderableLights.push_back(light); } // Sort lights - std::sort(m_visibleLights.begin(), m_visibleLights.end(), [&](Light* lhs, Light* rhs) + std::sort(m_renderableLights.begin(), m_renderableLights.end(), [&](const Light* lhs, const Light* rhs) { return lhs->ComputeContributionScore(renderableBoundingVolume) < rhs->ComputeContributionScore(renderableBoundingVolume); }); - std::size_t lightCount = std::min(m_visibleLights.size(), MaxLightCountPerDraw); + std::size_t lightCount = std::min(m_renderableLights.size(), MaxLightCountPerDraw); LightKey lightKey; lightKey.fill(nullptr); for (std::size_t i = 0; i < lightCount; ++i) - lightKey[i] = m_visibleLights[i]; + lightKey[i] = m_renderableLights[i]; RenderBufferView lightUboView; @@ -383,7 +397,7 @@ namespace Nz UInt8* lightPtr = static_cast(lightDataPtr) + lightOffsets.lightsOffset; for (std::size_t i = 0; i < lightCount; ++i) { - m_visibleLights[i]->FillLightData(lightPtr); + m_renderableLights[i]->FillLightData(lightPtr); lightPtr += lightOffsets.lightSize; } diff --git a/src/Nazara/Graphics/PointLight.cpp b/src/Nazara/Graphics/PointLight.cpp index cbf81387b..1c919e642 100644 --- a/src/Nazara/Graphics/PointLight.cpp +++ b/src/Nazara/Graphics/PointLight.cpp @@ -18,7 +18,7 @@ namespace Nz return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter()); } - void PointLight::FillLightData(void* data) + void PointLight::FillLightData(void* data) const { auto lightOffset = PredefinedLightData::GetOffsets(); diff --git a/src/Nazara/Graphics/SpotLight.cpp b/src/Nazara/Graphics/SpotLight.cpp index 72ecebdc3..a9abcbaa4 100644 --- a/src/Nazara/Graphics/SpotLight.cpp +++ b/src/Nazara/Graphics/SpotLight.cpp @@ -18,7 +18,7 @@ namespace Nz return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter()); } - void SpotLight::FillLightData(void* data) + void SpotLight::FillLightData(void* data) const { auto lightOffset = PredefinedLightData::GetOffsets();