Graphics/ForwardFramePipeline: Frustum cull lights
This commit is contained in:
parent
29cd77db55
commit
de7fee348a
|
|
@ -187,7 +187,7 @@ int main()
|
||||||
entt::entity headingEntity = registry.create();
|
entt::entity headingEntity = registry.create();
|
||||||
{
|
{
|
||||||
auto& entityLight = registry.emplace<Nz::LightComponent>(playerEntity);
|
auto& entityLight = registry.emplace<Nz::LightComponent>(playerEntity);
|
||||||
entityLight.AttachLight(std::make_shared<Nz::DirectionalLight>(), 1);
|
entityLight.AttachLight(std::make_shared<Nz::SpotLight>(), 1);
|
||||||
|
|
||||||
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(playerEntity);
|
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(playerEntity);
|
||||||
entityGfx.AttachRenderable(model, 1);
|
entityGfx.AttachRenderable(model, 1);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Nz
|
||||||
|
|
||||||
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
||||||
|
|
||||||
void FillLightData(void* data) override;
|
void FillLightData(void* data) const override;
|
||||||
|
|
||||||
inline float GetAmbientFactor() const;
|
inline float GetAmbientFactor() const;
|
||||||
inline float GetDiffuseFactor() const;
|
inline float GetDiffuseFactor() const;
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,8 @@ namespace Nz
|
||||||
std::unordered_set<WorldInstancePtr> m_removedWorldInstances;
|
std::unordered_set<WorldInstancePtr> m_removedWorldInstances;
|
||||||
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
|
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
|
||||||
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
||||||
std::vector<Light*> m_visibleLights;
|
std::vector<const Light*> m_renderableLights;
|
||||||
|
std::vector<const Light*> m_visibleLights;
|
||||||
std::vector<LightDataUbo> m_lightDataBuffers;
|
std::vector<LightDataUbo> m_lightDataBuffers;
|
||||||
std::vector<VisibleRenderable> m_visibleRenderables;
|
std::vector<VisibleRenderable> m_visibleRenderables;
|
||||||
BakedFrameGraph m_bakedFrameGraph;
|
BakedFrameGraph m_bakedFrameGraph;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Nz
|
||||||
|
|
||||||
virtual float ComputeContributionScore(const BoundingVolumef& boundingVolume) const = 0;
|
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;
|
inline const BoundingVolumef& GetBoundingVolume() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Nz
|
||||||
|
|
||||||
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
||||||
|
|
||||||
void FillLightData(void* data) override;
|
void FillLightData(void* data) const override;
|
||||||
|
|
||||||
inline float GetAmbientFactor() const;
|
inline float GetAmbientFactor() const;
|
||||||
inline float GetDiffuseFactor() const;
|
inline float GetDiffuseFactor() const;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Nz
|
||||||
|
|
||||||
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
|
||||||
|
|
||||||
void FillLightData(void* data) override;
|
void FillLightData(void* data) const override;
|
||||||
|
|
||||||
inline float GetAmbientFactor() const;
|
inline float GetAmbientFactor() const;
|
||||||
inline float GetDiffuseFactor() const;
|
inline float GetDiffuseFactor() const;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Nz
|
||||||
return -std::numeric_limits<float>::infinity();
|
return -std::numeric_limits<float>::infinity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionalLight::FillLightData(void* data)
|
void DirectionalLight::FillLightData(void* data) const
|
||||||
{
|
{
|
||||||
auto lightOffset = PredefinedLightData::GetOffsets();
|
auto lightOffset = PredefinedLightData::GetOffsets();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@ namespace Nz
|
||||||
BoundingVolumef boundingVolume(renderable->GetAABB());
|
BoundingVolumef boundingVolume(renderable->GetAABB());
|
||||||
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
||||||
|
|
||||||
if (!frustum.Contains(boundingVolume.aabb))
|
if (!frustum.Contains(boundingVolume))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto& visibleRenderable = m_visibleRenderables.emplace_back();
|
auto& visibleRenderable = m_visibleRenderables.emplace_back();
|
||||||
|
|
@ -259,6 +259,20 @@ namespace Nz
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(worldInstance.get()));
|
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(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<const void*>()(light));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (viewerData.visibilityHash != visibilityHash)
|
if (viewerData.visibilityHash != visibilityHash)
|
||||||
{
|
{
|
||||||
viewerData.rebuildDepthPrepass = true;
|
viewerData.rebuildDepthPrepass = true;
|
||||||
|
|
@ -317,26 +331,26 @@ namespace Nz
|
||||||
renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix());
|
renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix());
|
||||||
|
|
||||||
// Select lights (TODO: Cull lights in frustum)
|
// Select lights (TODO: Cull lights in frustum)
|
||||||
m_visibleLights.clear();
|
m_renderableLights.clear();
|
||||||
for (auto&& [light, lightData] : m_lights)
|
for (const Light* light : m_visibleLights)
|
||||||
{
|
{
|
||||||
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
|
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
|
||||||
if ((renderMask & lightData.renderMask) && boundingVolume.Intersect(renderableBoundingVolume.aabb))
|
if (boundingVolume.Intersect(renderableBoundingVolume.aabb))
|
||||||
m_visibleLights.push_back(light);
|
m_renderableLights.push_back(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort lights
|
// 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);
|
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 lightKey;
|
||||||
lightKey.fill(nullptr);
|
lightKey.fill(nullptr);
|
||||||
for (std::size_t i = 0; i < lightCount; ++i)
|
for (std::size_t i = 0; i < lightCount; ++i)
|
||||||
lightKey[i] = m_visibleLights[i];
|
lightKey[i] = m_renderableLights[i];
|
||||||
|
|
||||||
RenderBufferView lightUboView;
|
RenderBufferView lightUboView;
|
||||||
|
|
||||||
|
|
@ -383,7 +397,7 @@ namespace Nz
|
||||||
UInt8* lightPtr = static_cast<UInt8*>(lightDataPtr) + lightOffsets.lightsOffset;
|
UInt8* lightPtr = static_cast<UInt8*>(lightDataPtr) + lightOffsets.lightsOffset;
|
||||||
for (std::size_t i = 0; i < lightCount; ++i)
|
for (std::size_t i = 0; i < lightCount; ++i)
|
||||||
{
|
{
|
||||||
m_visibleLights[i]->FillLightData(lightPtr);
|
m_renderableLights[i]->FillLightData(lightPtr);
|
||||||
lightPtr += lightOffsets.lightSize;
|
lightPtr += lightOffsets.lightSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Nz
|
||||||
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
|
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointLight::FillLightData(void* data)
|
void PointLight::FillLightData(void* data) const
|
||||||
{
|
{
|
||||||
auto lightOffset = PredefinedLightData::GetOffsets();
|
auto lightOffset = PredefinedLightData::GetOffsets();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Nz
|
||||||
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
|
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotLight::FillLightData(void* data)
|
void SpotLight::FillLightData(void* data) const
|
||||||
{
|
{
|
||||||
auto lightOffset = PredefinedLightData::GetOffsets();
|
auto lightOffset = PredefinedLightData::GetOffsets();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue