Graphics: Improve frustum culling (do it once per viewer)
This commit is contained in:
parent
8546631f62
commit
0179ef4d65
|
|
@ -54,12 +54,6 @@ namespace Nz
|
||||||
void ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue<RenderElement*>& renderQueue);
|
void ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue<RenderElement*>& renderQueue);
|
||||||
void UnregisterMaterialPass(MaterialPass* material);
|
void UnregisterMaterialPass(MaterialPass* material);
|
||||||
|
|
||||||
struct ElementAABB
|
|
||||||
{
|
|
||||||
Boxf aabb;
|
|
||||||
std::size_t count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MaterialData
|
struct MaterialData
|
||||||
{
|
{
|
||||||
std::size_t usedCount = 0;
|
std::size_t usedCount = 0;
|
||||||
|
|
@ -72,14 +66,17 @@ namespace Nz
|
||||||
NazaraSlot(InstancedRenderable, OnMaterialInvalidated, onMaterialInvalidated);
|
NazaraSlot(InstancedRenderable, OnMaterialInvalidated, onMaterialInvalidated);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VisibleRenderable
|
||||||
|
{
|
||||||
|
const InstancedRenderable* instancedRenderable;
|
||||||
|
const WorldInstance* worldInstance;
|
||||||
|
};
|
||||||
|
|
||||||
struct ViewerData
|
struct ViewerData
|
||||||
{
|
{
|
||||||
std::size_t colorAttachment;
|
std::size_t colorAttachment;
|
||||||
std::size_t depthStencilAttachment;
|
std::size_t depthStencilAttachment;
|
||||||
std::size_t depthPrepassVisibilityHash = 0;
|
std::size_t visibilityHash = 0;
|
||||||
std::size_t forwardVisibilityHash = 0;
|
|
||||||
std::vector<ElementAABB> depthPrepassAABB;
|
|
||||||
std::vector<ElementAABB> forwardAABB;
|
|
||||||
std::vector<std::unique_ptr<RenderElement>> depthPrepassRenderElements;
|
std::vector<std::unique_ptr<RenderElement>> depthPrepassRenderElements;
|
||||||
std::vector<std::unique_ptr<RenderElement>> forwardRenderElements;
|
std::vector<std::unique_ptr<RenderElement>> forwardRenderElements;
|
||||||
RenderQueueRegistry depthPrepassRegistry;
|
RenderQueueRegistry depthPrepassRegistry;
|
||||||
|
|
@ -101,6 +98,7 @@ namespace Nz
|
||||||
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
||||||
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<VisibleRenderable> m_visibleRenderables;
|
||||||
BakedFrameGraph m_bakedFrameGraph;
|
BakedFrameGraph m_bakedFrameGraph;
|
||||||
bool m_rebuildFrameGraph;
|
bool m_rebuildFrameGraph;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Nz
|
||||||
InstancedRenderable(InstancedRenderable&&) noexcept = default;
|
InstancedRenderable(InstancedRenderable&&) noexcept = default;
|
||||||
~InstancedRenderable();
|
~InstancedRenderable();
|
||||||
|
|
||||||
virtual void BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const = 0;
|
virtual void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const = 0;
|
||||||
|
|
||||||
inline const Boxf& GetAABB() const;
|
inline const Boxf& GetAABB() const;
|
||||||
virtual const std::shared_ptr<Material>& GetMaterial(std::size_t i) const = 0;
|
virtual const std::shared_ptr<Material>& GetMaterial(std::size_t i) const = 0;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Nz
|
||||||
Model(Model&&) noexcept = default;
|
Model(Model&&) noexcept = default;
|
||||||
~Model() = default;
|
~Model() = default;
|
||||||
|
|
||||||
void BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const override;
|
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const override;
|
||||||
|
|
||||||
const std::shared_ptr<AbstractBuffer>& GetIndexBuffer(std::size_t subMeshIndex) const;
|
const std::shared_ptr<AbstractBuffer>& GetIndexBuffer(std::size_t subMeshIndex) const;
|
||||||
std::size_t GetIndexCount(std::size_t subMeshIndex) const;
|
std::size_t GetIndexCount(std::size_t subMeshIndex) const;
|
||||||
|
|
|
||||||
|
|
@ -171,134 +171,90 @@ namespace Nz
|
||||||
{
|
{
|
||||||
auto& viewerData = data;
|
auto& viewerData = data;
|
||||||
|
|
||||||
//if (viewerData.rebuildDepthPrepass)
|
// Frustum culling
|
||||||
{
|
|
||||||
viewerData.depthPrepassAABB.clear();
|
|
||||||
viewerData.depthPrepassRenderElements.clear();
|
|
||||||
|
|
||||||
for (const auto& [worldInstance, renderables] : m_renderables)
|
|
||||||
{
|
|
||||||
for (const auto& [renderable, renderableData] : renderables)
|
|
||||||
{
|
|
||||||
std::size_t prevCount = viewerData.depthPrepassRenderElements.size();
|
|
||||||
renderable->BuildElement(m_depthPassIndex, *worldInstance, viewerData.depthPrepassRenderElements);
|
|
||||||
std::size_t currentCount = viewerData.depthPrepassRenderElements.size();
|
|
||||||
|
|
||||||
if (currentCount > prevCount)
|
|
||||||
{
|
|
||||||
BoundingVolumef boundingVolume(renderable->GetAABB());
|
|
||||||
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
|
||||||
|
|
||||||
auto& aabbData = viewerData.depthPrepassAABB.emplace_back();
|
|
||||||
aabbData.aabb = boundingVolume.aabb;
|
|
||||||
aabbData.count = currentCount - prevCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (viewerData.rebuildForwardPass)
|
|
||||||
{
|
|
||||||
viewerData.forwardAABB.clear();
|
|
||||||
viewerData.forwardRenderElements.clear();
|
|
||||||
|
|
||||||
for (const auto& [worldInstance, renderables] : m_renderables)
|
|
||||||
{
|
|
||||||
for (const auto& [renderable, renderableData] : renderables)
|
|
||||||
{
|
|
||||||
std::size_t prevCount = viewerData.forwardRenderElements.size();
|
|
||||||
renderable->BuildElement(m_forwardPassIndex, *worldInstance, viewerData.forwardRenderElements);
|
|
||||||
std::size_t currentCount = viewerData.forwardRenderElements.size();
|
|
||||||
|
|
||||||
if (currentCount > prevCount)
|
|
||||||
{
|
|
||||||
BoundingVolumef boundingVolume(renderable->GetAABB());
|
|
||||||
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
|
||||||
|
|
||||||
auto& aabbData = viewerData.forwardAABB.emplace_back();
|
|
||||||
aabbData.aabb = boundingVolume.aabb;
|
|
||||||
aabbData.count = currentCount - prevCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Matrix4f& viewProjMatrix = viewer->GetViewerInstance().GetViewProjMatrix();
|
const Matrix4f& viewProjMatrix = viewer->GetViewerInstance().GetViewProjMatrix();
|
||||||
|
|
||||||
Frustumf frustum;
|
Frustumf frustum;
|
||||||
frustum.Extract(viewProjMatrix);
|
frustum.Extract(viewProjMatrix);
|
||||||
|
|
||||||
viewerData.depthPrepassRegistry.Clear();
|
std::size_t visibilityHash = 5U;
|
||||||
viewerData.depthPrepassRenderQueue.Clear();
|
|
||||||
|
m_visibleRenderables.clear();
|
||||||
|
for (const auto& [worldInstance, renderables] : m_renderables)
|
||||||
{
|
{
|
||||||
std::size_t visibilityHash = 5U;
|
bool isInstanceVisible = false;
|
||||||
|
|
||||||
auto elementIt = viewerData.depthPrepassRenderElements.begin();
|
for (const auto& [renderable, renderableData] : renderables)
|
||||||
for (auto&& [aabb, elementCount] : viewerData.depthPrepassAABB)
|
|
||||||
{
|
{
|
||||||
if (!frustum.Contains(aabb))
|
// Get global AABB
|
||||||
{
|
BoundingVolumef boundingVolume(renderable->GetAABB());
|
||||||
std::advance(elementIt, elementCount);
|
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
||||||
|
|
||||||
|
if (!frustum.Contains(boundingVolume.aabb))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < elementCount; ++i)
|
auto& renderableData = m_visibleRenderables.emplace_back();
|
||||||
{
|
renderableData.instancedRenderable = renderable;
|
||||||
auto& renderElement = *elementIt++;
|
renderableData.worldInstance = worldInstance.get();
|
||||||
renderElement->Register(viewerData.depthPrepassRegistry);
|
|
||||||
viewerData.depthPrepassRenderQueue.Insert(renderElement.get());
|
|
||||||
|
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const RenderElement*>()(renderElement.get()));
|
isInstanceVisible = true;
|
||||||
}
|
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(renderable));
|
||||||
}
|
}
|
||||||
|
|
||||||
viewerData.depthPrepassRenderQueue.Sort([&](const RenderElement* element)
|
if (isInstanceVisible)
|
||||||
{
|
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(worldInstance.get()));
|
||||||
return element->ComputeSortingScore(viewerData.depthPrepassRegistry);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (viewerData.depthPrepassVisibilityHash != visibilityHash)
|
if (viewerData.visibilityHash != visibilityHash)
|
||||||
|
{
|
||||||
|
viewerData.rebuildDepthPrepass = true;
|
||||||
|
viewerData.rebuildForwardPass = true;
|
||||||
|
|
||||||
|
viewerData.visibilityHash = visibilityHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewerData.rebuildDepthPrepass)
|
||||||
|
{
|
||||||
|
viewerData.depthPrepassRenderElements.clear();
|
||||||
|
|
||||||
|
for (const auto& renderableData : m_visibleRenderables)
|
||||||
|
renderableData.instancedRenderable->BuildElement(m_depthPassIndex, *renderableData.worldInstance, viewerData.depthPrepassRenderElements);
|
||||||
|
|
||||||
|
viewerData.depthPrepassRegistry.Clear();
|
||||||
|
viewerData.depthPrepassRenderQueue.Clear();
|
||||||
|
|
||||||
|
for (const auto& renderElement : viewerData.depthPrepassRenderElements)
|
||||||
{
|
{
|
||||||
viewerData.rebuildDepthPrepass = true;
|
renderElement->Register(viewerData.depthPrepassRegistry);
|
||||||
viewerData.depthPrepassVisibilityHash = visibilityHash;
|
viewerData.depthPrepassRenderQueue.Insert(renderElement.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewerData.forwardRegistry.Clear();
|
viewerData.depthPrepassRenderQueue.Sort([&](const RenderElement* element)
|
||||||
viewerData.forwardRenderQueue.Clear();
|
|
||||||
{
|
{
|
||||||
std::size_t visibilityHash = 5U;
|
return element->ComputeSortingScore(viewerData.depthPrepassRegistry);
|
||||||
|
});
|
||||||
|
|
||||||
auto elementIt = viewerData.forwardRenderElements.begin();
|
if (viewerData.rebuildForwardPass)
|
||||||
for (auto&& [aabb, elementCount] : viewerData.forwardAABB)
|
{
|
||||||
|
viewerData.forwardRenderElements.clear();
|
||||||
|
|
||||||
|
for (const auto& renderableData : m_visibleRenderables)
|
||||||
|
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements);
|
||||||
|
|
||||||
|
viewerData.forwardRegistry.Clear();
|
||||||
|
viewerData.forwardRenderQueue.Clear();
|
||||||
|
for (const auto& renderElement : viewerData.forwardRenderElements)
|
||||||
{
|
{
|
||||||
if (!frustum.Contains(aabb))
|
renderElement->Register(viewerData.forwardRegistry);
|
||||||
{
|
viewerData.forwardRenderQueue.Insert(renderElement.get());
|
||||||
std::advance(elementIt, elementCount);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < elementCount; ++i)
|
|
||||||
{
|
|
||||||
auto& renderElement = *elementIt++;
|
|
||||||
renderElement->Register(viewerData.forwardRegistry);
|
|
||||||
viewerData.forwardRenderQueue.Insert(renderElement.get());
|
|
||||||
|
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const RenderElement*>()(renderElement.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewerData.forwardRenderQueue.Sort([&](const RenderElement* element)
|
|
||||||
{
|
|
||||||
return element->ComputeSortingScore(viewerData.forwardRegistry);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (viewerData.forwardVisibilityHash != visibilityHash)
|
|
||||||
{
|
|
||||||
viewerData.rebuildForwardPass = true;
|
|
||||||
viewerData.forwardVisibilityHash = visibilityHash;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewerData.forwardRenderQueue.Sort([&](const RenderElement* element)
|
||||||
|
{
|
||||||
|
return element->ComputeSortingScore(viewerData.forwardRegistry);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_bakedFrameGraph.Resize(renderFrame))
|
if (m_bakedFrameGraph.Resize(renderFrame))
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const
|
void Model::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < m_submeshes.size(); ++i)
|
for (std::size_t i = 0; i < m_submeshes.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue