Graphics/FramePipeline: Replace maps with memory pools and indices
This commit is contained in:
parent
a1b6f51398
commit
20a86312ff
|
|
@ -844,13 +844,10 @@ int main()
|
||||||
{
|
{
|
||||||
builder.SetViewport(renderArea);
|
builder.SetViewport(renderArea);
|
||||||
|
|
||||||
spaceshipModel.UpdateScissorBox(renderArea);
|
|
||||||
planeModel.UpdateScissorBox(renderArea);
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements);
|
spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements, renderArea);
|
||||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements);
|
spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements, renderArea);
|
||||||
planeModel.BuildElement(forwardPassIndex, planeInstance, elements);
|
planeModel.BuildElement(forwardPassIndex, planeInstance, elements, renderArea);
|
||||||
|
|
||||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||||
|
|
@ -905,8 +902,6 @@ int main()
|
||||||
builder.SetScissor(renderArea);
|
builder.SetScissor(renderArea);
|
||||||
builder.SetViewport(renderArea);
|
builder.SetViewport(renderArea);
|
||||||
|
|
||||||
flareSprite.UpdateScissorBox(renderArea);
|
|
||||||
|
|
||||||
builder.BindShaderBinding(0, *skyboxShaderBinding);
|
builder.BindShaderBinding(0, *skyboxShaderBinding);
|
||||||
|
|
||||||
builder.BindIndexBuffer(*cubeMeshGfx->GetIndexBuffer(0));
|
builder.BindIndexBuffer(*cubeMeshGfx->GetIndexBuffer(0));
|
||||||
|
|
@ -916,7 +911,7 @@ int main()
|
||||||
builder.DrawIndexed(Nz::SafeCast<Nz::UInt32>(cubeMeshGfx->GetIndexCount(0)));
|
builder.DrawIndexed(Nz::SafeCast<Nz::UInt32>(cubeMeshGfx->GetIndexCount(0)));
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements);
|
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements, renderArea);
|
||||||
|
|
||||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||||
|
|
@ -942,11 +937,10 @@ int main()
|
||||||
Nz::FramePass& occluderPass = graph.AddPass("Occluder pass");
|
Nz::FramePass& occluderPass = graph.AddPass("Occluder pass");
|
||||||
occluderPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea)
|
occluderPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea)
|
||||||
{
|
{
|
||||||
builder.SetScissor(renderArea);
|
|
||||||
builder.SetViewport(renderArea);
|
builder.SetViewport(renderArea);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements);
|
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements, renderArea);
|
||||||
|
|
||||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||||
|
|
|
||||||
|
|
@ -63,22 +63,21 @@ int main()
|
||||||
|
|
||||||
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>();
|
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>();
|
||||||
|
|
||||||
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::PhongLightingMaterial::GetSettings());
|
std::shared_ptr<Nz::MaterialPass> forwardPass = std::make_shared<Nz::MaterialPass>(Nz::PhongLightingMaterial::GetSettings());
|
||||||
materialPass->EnableDepthBuffer(true);
|
forwardPass->EnableDepthBuffer(true);
|
||||||
materialPass->EnableFaceCulling(true);
|
forwardPass->EnableFaceCulling(true);
|
||||||
|
|
||||||
material->AddPass("ForwardPass", materialPass);
|
material->AddPass("ForwardPass", forwardPass);
|
||||||
|
|
||||||
std::shared_ptr<Nz::Texture> normalMap = Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams);
|
std::shared_ptr<Nz::Texture> normalMap = Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams);
|
||||||
|
|
||||||
Nz::PhongLightingMaterial phongMat(*materialPass);
|
Nz::PhongLightingMaterial phongMat(*forwardPass);
|
||||||
phongMat.EnableAlphaTest(false);
|
phongMat.EnableAlphaTest(false);
|
||||||
phongMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
|
phongMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
|
||||||
phongMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
|
phongMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
|
||||||
phongMat.SetNormalMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams));
|
phongMat.SetNormalMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams));
|
||||||
|
|
||||||
Nz::Model model(std::move(gfxMesh), spaceshipMesh->GetAABB());
|
Nz::Model model(std::move(gfxMesh), spaceshipMesh->GetAABB());
|
||||||
model.UpdateScissorBox(Nz::Recti(0, 0, 1920, 1080));
|
|
||||||
for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i)
|
for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i)
|
||||||
model.SetMaterial(i, material);
|
model.SetMaterial(i, material);
|
||||||
|
|
||||||
|
|
@ -97,12 +96,14 @@ int main()
|
||||||
Nz::WorldInstancePtr modelInstance2 = std::make_shared<Nz::WorldInstance>();
|
Nz::WorldInstancePtr modelInstance2 = std::make_shared<Nz::WorldInstance>();
|
||||||
modelInstance2->UpdateWorldMatrix(Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()));
|
modelInstance2->UpdateWorldMatrix(Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()));
|
||||||
|
|
||||||
model.UpdateScissorBox(Nz::Recti(Nz::Vector2i(window.GetSize())));
|
Nz::Recti scissorBox(Nz::Vector2i(window.GetSize()));
|
||||||
|
|
||||||
Nz::ForwardFramePipeline framePipeline;
|
Nz::ForwardFramePipeline framePipeline;
|
||||||
framePipeline.RegisterViewer(&camera, 0);
|
std::size_t cameraIndex = framePipeline.RegisterViewer(&camera, 0);
|
||||||
framePipeline.RegisterInstancedDrawable(modelInstance, &model, 0xFFFFFFFF);
|
std::size_t worldInstanceIndex1 = framePipeline.RegisterWorldInstance(modelInstance);
|
||||||
framePipeline.RegisterInstancedDrawable(modelInstance2, &model, 0xFFFFFFFF);
|
std::size_t worldInstanceIndex2 = framePipeline.RegisterWorldInstance(modelInstance2);
|
||||||
|
framePipeline.RegisterRenderable(worldInstanceIndex1, &model, 0xFFFFFFFF, scissorBox);
|
||||||
|
framePipeline.RegisterRenderable(worldInstanceIndex2, &model, 0xFFFFFFFF, scissorBox);
|
||||||
|
|
||||||
std::shared_ptr<Nz::PointLight> light = std::make_shared<Nz::PointLight>();
|
std::shared_ptr<Nz::PointLight> light = std::make_shared<Nz::PointLight>();
|
||||||
light->UpdateColor(Nz::Color::Green);
|
light->UpdateColor(Nz::Color::Green);
|
||||||
|
|
@ -146,7 +147,7 @@ int main()
|
||||||
else if (event.key.virtualKey == Nz::Keyboard::VKey::Space)
|
else if (event.key.virtualKey == Nz::Keyboard::VKey::Space)
|
||||||
{
|
{
|
||||||
modelInstance->UpdateWorldMatrix(Nz::Matrix4f::Translate(viewerPos));
|
modelInstance->UpdateWorldMatrix(Nz::Matrix4f::Translate(viewerPos));
|
||||||
framePipeline.InvalidateWorldInstance(modelInstance.get());
|
framePipeline.InvalidateWorldInstance(worldInstanceIndex1);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -218,7 +219,7 @@ int main()
|
||||||
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(viewerPos, camAngles));
|
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(viewerPos, camAngles));
|
||||||
viewerInstance.UpdateEyePosition(viewerPos);
|
viewerInstance.UpdateEyePosition(viewerPos);
|
||||||
|
|
||||||
framePipeline.InvalidateViewer(&camera);
|
framePipeline.InvalidateViewer(cameraIndex);
|
||||||
|
|
||||||
framePipeline.Render(frame);
|
framePipeline.Render(frame);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ int main()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Nz::Vector3f spaceshipPos = node.GetPosition(Nz::CoordSys::Global);
|
Nz::Vector3f spaceshipPos = node.GetPosition(Nz::CoordSys::Global);
|
||||||
if (spaceshipPos.GetSquaredLength() > Nz::IntegralPow(200.f, 2))
|
if (spaceshipPos.GetSquaredLength() > Nz::IntegralPow(20.f, 2))
|
||||||
registry.destroy(entity);
|
registry.destroy(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||||
|
#include <Nazara/Math/Rect.hpp>
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -20,6 +21,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Renderable;
|
struct Renderable;
|
||||||
|
static constexpr std::size_t MaxRenderableCount = 8;
|
||||||
|
|
||||||
inline GraphicsComponent(bool initialyVisible = true);
|
inline GraphicsComponent(bool initialyVisible = true);
|
||||||
GraphicsComponent(const GraphicsComponent&) = default;
|
GraphicsComponent(const GraphicsComponent&) = default;
|
||||||
|
|
@ -32,7 +34,8 @@ namespace Nz
|
||||||
|
|
||||||
inline void DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable);
|
inline void DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable);
|
||||||
|
|
||||||
inline const std::vector<Renderable>& GetRenderables() const;
|
inline const Renderable& GetRenderableEntry(std::size_t renderableIndex) const;
|
||||||
|
inline const std::array<Renderable, MaxRenderableCount>& GetRenderables() const;
|
||||||
inline const Recti& GetScissorBox() const;
|
inline const Recti& GetScissorBox() const;
|
||||||
inline const WorldInstancePtr& GetWorldInstance() const;
|
inline const WorldInstancePtr& GetWorldInstance() const;
|
||||||
|
|
||||||
|
|
@ -47,8 +50,9 @@ namespace Nz
|
||||||
GraphicsComponent& operator=(const GraphicsComponent&) = default;
|
GraphicsComponent& operator=(const GraphicsComponent&) = default;
|
||||||
GraphicsComponent& operator=(GraphicsComponent&&) = default;
|
GraphicsComponent& operator=(GraphicsComponent&&) = default;
|
||||||
|
|
||||||
NazaraSignal(OnRenderableAttached, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/);
|
NazaraSignal(OnRenderableAttached, GraphicsComponent* /*graphicsComponent*/, std::size_t /*renderableIndex*/);
|
||||||
NazaraSignal(OnRenderableDetach, GraphicsComponent* /*graphicsComponent*/, const Renderable& /*renderable*/);
|
NazaraSignal(OnRenderableDetach, GraphicsComponent* /*graphicsComponent*/, std::size_t /*renderableIndex*/);
|
||||||
|
NazaraSignal(OnScissorBoxUpdate, GraphicsComponent* /*graphicsComponent*/, const Recti& /*newScissorBox*/);
|
||||||
NazaraSignal(OnVisibilityUpdate, GraphicsComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
|
NazaraSignal(OnVisibilityUpdate, GraphicsComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
|
||||||
|
|
||||||
struct Renderable
|
struct Renderable
|
||||||
|
|
@ -58,7 +62,7 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Renderable> m_renderables;
|
std::array<Renderable, MaxRenderableCount> m_renderables;
|
||||||
Recti m_scissorBox;
|
Recti m_scissorBox;
|
||||||
WorldInstancePtr m_worldInstance;
|
WorldInstancePtr m_worldInstance;
|
||||||
bool m_isVisible;
|
bool m_isVisible;
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,31 @@ namespace Nz
|
||||||
|
|
||||||
inline void GraphicsComponent::AttachRenderable(std::shared_ptr<InstancedRenderable> renderable, UInt32 renderMask)
|
inline void GraphicsComponent::AttachRenderable(std::shared_ptr<InstancedRenderable> renderable, UInt32 renderMask)
|
||||||
{
|
{
|
||||||
auto& entry = m_renderables.emplace_back();
|
for (std::size_t i = 0; i < m_renderables.size(); ++i)
|
||||||
entry.renderable = std::move(renderable);
|
{
|
||||||
entry.renderMask = renderMask;
|
auto& entry = m_renderables[i];
|
||||||
|
if (entry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
OnRenderableAttached(this, m_renderables.back());
|
entry.renderable = std::move(renderable);
|
||||||
|
entry.renderMask = renderMask;
|
||||||
|
|
||||||
|
OnRenderableAttached(this, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GraphicsComponent::Clear()
|
inline void GraphicsComponent::Clear()
|
||||||
{
|
{
|
||||||
for (const auto& renderable : m_renderables)
|
for (std::size_t i = 0; i < m_renderables.size(); ++i)
|
||||||
OnRenderableDetach(this, renderable);
|
{
|
||||||
|
auto& entry = m_renderables[i];
|
||||||
|
if (entry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
m_renderables.clear();
|
OnRenderableDetach(this, i);
|
||||||
|
entry.renderable.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GraphicsComponent::DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable)
|
inline void GraphicsComponent::DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable)
|
||||||
|
|
@ -36,13 +48,19 @@ namespace Nz
|
||||||
auto it = std::find_if(m_renderables.begin(), m_renderables.end(), [&](const auto& renderableEntry) { return renderableEntry.renderable == renderable; });
|
auto it = std::find_if(m_renderables.begin(), m_renderables.end(), [&](const auto& renderableEntry) { return renderableEntry.renderable == renderable; });
|
||||||
if (it != m_renderables.end())
|
if (it != m_renderables.end())
|
||||||
{
|
{
|
||||||
OnRenderableDetach(this, *it);
|
OnRenderableDetach(this, std::distance(m_renderables.begin(), it));
|
||||||
|
|
||||||
m_renderables.erase(it);
|
it->renderable.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto GraphicsComponent::GetRenderables() const -> const std::vector<Renderable>&
|
inline auto GraphicsComponent::GetRenderableEntry(std::size_t renderableIndex) const -> const Renderable&
|
||||||
|
{
|
||||||
|
assert(renderableIndex < m_renderables.size());
|
||||||
|
return m_renderables[renderableIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto GraphicsComponent::GetRenderables() const -> const std::array<Renderable, MaxRenderableCount>&
|
||||||
{
|
{
|
||||||
return m_renderables;
|
return m_renderables;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <Nazara/Graphics/Light.hpp>
|
#include <Nazara/Graphics/Light.hpp>
|
||||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct LightEntry;
|
struct LightEntry;
|
||||||
|
static constexpr std::size_t MaxLightCount = 8;
|
||||||
|
|
||||||
inline LightComponent(bool initialyVisible = true);
|
inline LightComponent(bool initialyVisible = true);
|
||||||
LightComponent(const LightComponent&) = default;
|
LightComponent(const LightComponent&) = default;
|
||||||
|
|
@ -32,7 +34,8 @@ namespace Nz
|
||||||
|
|
||||||
inline void DetachLight(const std::shared_ptr<Light>& renderable);
|
inline void DetachLight(const std::shared_ptr<Light>& renderable);
|
||||||
|
|
||||||
inline const std::vector<LightEntry>& GetLights() const;
|
inline const LightEntry& GetLightEntry(std::size_t lightIndex) const;
|
||||||
|
inline const std::array<LightEntry, MaxLightCount>& GetLights() const;
|
||||||
|
|
||||||
inline void Hide();
|
inline void Hide();
|
||||||
|
|
||||||
|
|
@ -43,8 +46,8 @@ namespace Nz
|
||||||
LightComponent& operator=(const LightComponent&) = default;
|
LightComponent& operator=(const LightComponent&) = default;
|
||||||
LightComponent& operator=(LightComponent&&) = default;
|
LightComponent& operator=(LightComponent&&) = default;
|
||||||
|
|
||||||
NazaraSignal(OnLightAttached, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/);
|
NazaraSignal(OnLightAttached, LightComponent* /*graphicsComponent*/, std::size_t /*lightIndex*/);
|
||||||
NazaraSignal(OnLightDetach, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/);
|
NazaraSignal(OnLightDetach, LightComponent* /*graphicsComponent*/, std::size_t /*lightIndex*/);
|
||||||
NazaraSignal(OnVisibilityUpdate, LightComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
|
NazaraSignal(OnVisibilityUpdate, LightComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
|
||||||
|
|
||||||
struct LightEntry
|
struct LightEntry
|
||||||
|
|
@ -54,7 +57,7 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<LightEntry> m_lightEntries;
|
std::array<LightEntry, MaxLightCount> m_lightEntries;
|
||||||
bool m_isVisible;
|
bool m_isVisible;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,31 @@ namespace Nz
|
||||||
|
|
||||||
inline void LightComponent::AttachLight(std::shared_ptr<Light> light, UInt32 renderMask)
|
inline void LightComponent::AttachLight(std::shared_ptr<Light> light, UInt32 renderMask)
|
||||||
{
|
{
|
||||||
auto& entry = m_lightEntries.emplace_back();
|
for (std::size_t i = 0; i < m_lightEntries.size(); ++i)
|
||||||
entry.light = std::move(light);
|
{
|
||||||
entry.renderMask = renderMask;
|
auto& entry = m_lightEntries[i];
|
||||||
|
if (entry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
OnLightAttached(this, m_lightEntries.back());
|
entry.light = std::move(light);
|
||||||
|
entry.renderMask = renderMask;
|
||||||
|
|
||||||
|
OnLightAttached(this, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void LightComponent::Clear()
|
inline void LightComponent::Clear()
|
||||||
{
|
{
|
||||||
for (const auto& lightEntry : m_lightEntries)
|
for (std::size_t i = 0; i < m_lightEntries.size(); ++i)
|
||||||
OnLightDetach(this, lightEntry);
|
{
|
||||||
|
auto& entry = m_lightEntries[i];
|
||||||
|
if (entry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
m_lightEntries.clear();
|
OnLightDetach(this, i);
|
||||||
|
entry.light.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void LightComponent::DetachLight(const std::shared_ptr<Light>& light)
|
inline void LightComponent::DetachLight(const std::shared_ptr<Light>& light)
|
||||||
|
|
@ -34,13 +46,19 @@ namespace Nz
|
||||||
auto it = std::find_if(m_lightEntries.begin(), m_lightEntries.end(), [&](const auto& lightEntry) { return lightEntry.light == light; });
|
auto it = std::find_if(m_lightEntries.begin(), m_lightEntries.end(), [&](const auto& lightEntry) { return lightEntry.light == light; });
|
||||||
if (it != m_lightEntries.end())
|
if (it != m_lightEntries.end())
|
||||||
{
|
{
|
||||||
OnLightDetach(this, *it);
|
OnLightDetach(this, std::distance(m_lightEntries.begin(), it));
|
||||||
|
|
||||||
m_lightEntries.erase(it);
|
it->light.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto LightComponent::GetLights() const -> const std::vector<LightEntry>&
|
inline auto LightComponent::GetLightEntry(std::size_t lightIndex) const -> const LightEntry&
|
||||||
|
{
|
||||||
|
assert(lightIndex < m_lightEntries.size());
|
||||||
|
return m_lightEntries[lightIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto LightComponent::GetLights() const -> const std::array<LightEntry, MaxLightCount>&
|
||||||
{
|
{
|
||||||
return m_lightEntries;
|
return m_lightEntries;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define NAZARA_GRAPHICS_FORWARDFRAMEPIPELINE_HPP
|
#define NAZARA_GRAPHICS_FORWARDFRAMEPIPELINE_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Core/MemoryPool.hpp>
|
||||||
#include <Nazara/Graphics/BakedFrameGraph.hpp>
|
#include <Nazara/Graphics/BakedFrameGraph.hpp>
|
||||||
#include <Nazara/Graphics/Config.hpp>
|
#include <Nazara/Graphics/Config.hpp>
|
||||||
#include <Nazara/Graphics/DepthPipelinePass.hpp>
|
#include <Nazara/Graphics/DepthPipelinePass.hpp>
|
||||||
|
|
@ -41,20 +42,27 @@ namespace Nz
|
||||||
ForwardFramePipeline(ForwardFramePipeline&&) = delete;
|
ForwardFramePipeline(ForwardFramePipeline&&) = delete;
|
||||||
~ForwardFramePipeline();
|
~ForwardFramePipeline();
|
||||||
|
|
||||||
void InvalidateViewer(AbstractViewer* viewerInstance) override;
|
void InvalidateViewer(std::size_t viewerIndex) override;
|
||||||
void InvalidateWorldInstance(WorldInstance* worldInstance) override;
|
void InvalidateWorldInstance(std::size_t renderableIndex) override;
|
||||||
|
|
||||||
void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) override;
|
std::size_t RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) override;
|
||||||
void RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) override;
|
|
||||||
void RegisterMaterialPass(MaterialPass* materialPass) override;
|
void RegisterMaterialPass(MaterialPass* materialPass) override;
|
||||||
void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override;
|
std::size_t RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) override;
|
||||||
|
std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override;
|
||||||
|
std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) override;
|
||||||
|
|
||||||
void Render(RenderFrame& renderFrame) override;
|
void Render(RenderFrame& renderFrame) override;
|
||||||
|
|
||||||
void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) override;
|
void UnregisterLight(std::size_t lightIndex) override;
|
||||||
void UnregisterLight(Light* light) override;
|
|
||||||
void UnregisterMaterialPass(MaterialPass* material) override;
|
void UnregisterMaterialPass(MaterialPass* material) override;
|
||||||
void UnregisterViewer(AbstractViewer* viewerInstance) override;
|
void UnregisterRenderable(std::size_t renderableIndex) override;
|
||||||
|
void UnregisterViewer(std::size_t viewerIndex) override;
|
||||||
|
void UnregisterWorldInstance(std::size_t worldInstance) override;
|
||||||
|
|
||||||
|
void UpdateLightRenderMask(std::size_t lightIndex, UInt32 renderMask);
|
||||||
|
void UpdateRenderableRenderMask(std::size_t renderableIndex, UInt32 renderMask);
|
||||||
|
void UpdateRenderableScissorBox(std::size_t renderableIndex, const Recti& scissorBox);
|
||||||
|
void UpdateViewerRenderMask(std::size_t viewerIndex, Int32 renderOrder);
|
||||||
|
|
||||||
ForwardFramePipeline& operator=(const ForwardFramePipeline&) = delete;
|
ForwardFramePipeline& operator=(const ForwardFramePipeline&) = delete;
|
||||||
ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete;
|
ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete;
|
||||||
|
|
@ -81,6 +89,9 @@ namespace Nz
|
||||||
|
|
||||||
struct RenderableData
|
struct RenderableData
|
||||||
{
|
{
|
||||||
|
std::size_t worldInstanceIndex;
|
||||||
|
const InstancedRenderable* renderable;
|
||||||
|
Recti scissorBox;
|
||||||
UInt32 renderMask = 0;
|
UInt32 renderMask = 0;
|
||||||
|
|
||||||
NazaraSlot(InstancedRenderable, OnElementInvalidated, onElementInvalidated);
|
NazaraSlot(InstancedRenderable, OnElementInvalidated, onElementInvalidated);
|
||||||
|
|
@ -100,26 +111,27 @@ namespace Nz
|
||||||
std::size_t depthStencilAttachment;
|
std::size_t depthStencilAttachment;
|
||||||
std::unique_ptr<DepthPipelinePass> depthPrepass;
|
std::unique_ptr<DepthPipelinePass> depthPrepass;
|
||||||
std::unique_ptr<ForwardPipelinePass> forwardPass;
|
std::unique_ptr<ForwardPipelinePass> forwardPass;
|
||||||
|
AbstractViewer* viewer;
|
||||||
Int32 renderOrder = 0;
|
Int32 renderOrder = 0;
|
||||||
RenderQueueRegistry forwardRegistry;
|
RenderQueueRegistry forwardRegistry;
|
||||||
RenderQueue<RenderElement*> forwardRenderQueue;
|
RenderQueue<RenderElement*> forwardRenderQueue;
|
||||||
ShaderBindingPtr blitShaderBinding;
|
ShaderBindingPtr blitShaderBinding;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t m_forwardPassIndex;
|
|
||||||
std::unordered_map<AbstractViewer*, ViewerData> m_viewers;
|
|
||||||
std::unordered_map<Light*, LightData> m_lights;
|
|
||||||
std::unordered_map<MaterialPass*, MaterialPassData> m_activeMaterialPasses;
|
std::unordered_map<MaterialPass*, MaterialPassData> m_activeMaterialPasses;
|
||||||
std::unordered_map<WorldInstancePtr, std::unordered_map<const InstancedRenderable*, RenderableData>> m_renderables;
|
|
||||||
std::unordered_map<const RenderTarget*, RenderTargetData> m_renderTargets;
|
std::unordered_map<const RenderTarget*, RenderTargetData> m_renderTargets;
|
||||||
std::unordered_set<AbstractViewer*> m_invalidatedViewerInstances;
|
|
||||||
std::unordered_set<MaterialPass*> m_invalidatedMaterialPasses;
|
std::unordered_set<MaterialPass*> m_invalidatedMaterialPasses;
|
||||||
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
|
||||||
std::unordered_set<WorldInstancePtr> m_removedWorldInstances;
|
|
||||||
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
||||||
std::vector<FramePipelinePass::VisibleRenderable> m_visibleRenderables;
|
std::vector<FramePipelinePass::VisibleRenderable> m_visibleRenderables;
|
||||||
std::vector<const Light*> m_visibleLights;
|
std::vector<const Light*> m_visibleLights;
|
||||||
BakedFrameGraph m_bakedFrameGraph;
|
BakedFrameGraph m_bakedFrameGraph;
|
||||||
|
Bitset<UInt64> m_invalidatedViewerInstances;
|
||||||
|
Bitset<UInt64> m_invalidatedWorldInstances;
|
||||||
|
Bitset<UInt64> m_removedWorldInstances;
|
||||||
|
MemoryPool<RenderableData> m_renderablePool;
|
||||||
|
MemoryPool<LightData> m_lightPool;
|
||||||
|
MemoryPool<ViewerData> m_viewerPool;
|
||||||
|
MemoryPool<WorldInstancePtr> m_worldInstances;
|
||||||
RenderFrame* m_currentRenderFrame;
|
RenderFrame* m_currentRenderFrame;
|
||||||
bool m_rebuildFrameGraph;
|
bool m_rebuildFrameGraph;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Nz
|
||||||
void Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<const Light*>& visibleLights, std::size_t visibilityHash);
|
void Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<const Light*>& visibleLights, std::size_t visibilityHash);
|
||||||
|
|
||||||
void RegisterMaterial(const Material& material);
|
void RegisterMaterial(const Material& material);
|
||||||
void RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex);
|
void RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex, bool hasDepthPrepass);
|
||||||
|
|
||||||
void UnregisterMaterial(const Material& material);
|
void UnregisterMaterial(const Material& material);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,22 +37,29 @@ namespace Nz
|
||||||
inline ElementRenderer& GetElementRenderer(std::size_t elementIndex);
|
inline ElementRenderer& GetElementRenderer(std::size_t elementIndex);
|
||||||
inline std::size_t GetElementRendererCount() const;
|
inline std::size_t GetElementRendererCount() const;
|
||||||
|
|
||||||
virtual void InvalidateViewer(AbstractViewer* viewerInstance) = 0;
|
virtual void InvalidateViewer(std::size_t viewerIndex) = 0;
|
||||||
virtual void InvalidateWorldInstance(WorldInstance* worldInstance) = 0;
|
virtual void InvalidateWorldInstance(std::size_t) = 0;
|
||||||
|
|
||||||
template<typename F> void ProcessRenderQueue(const RenderQueue<RenderElement*>& renderQueue, F&& callback);
|
template<typename F> void ProcessRenderQueue(const RenderQueue<RenderElement*>& renderQueue, F&& callback);
|
||||||
|
|
||||||
virtual void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) = 0;
|
virtual std::size_t RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) = 0;
|
||||||
virtual void RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) = 0;
|
|
||||||
virtual void RegisterMaterialPass(MaterialPass* materialPass) = 0;
|
virtual void RegisterMaterialPass(MaterialPass* materialPass) = 0;
|
||||||
virtual void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0;
|
virtual std::size_t RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) = 0;
|
||||||
|
virtual std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0;
|
||||||
|
virtual std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) = 0;
|
||||||
|
|
||||||
virtual void Render(RenderFrame& renderFrame) = 0;
|
virtual void Render(RenderFrame& renderFrame) = 0;
|
||||||
|
|
||||||
virtual void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) = 0;
|
virtual void UnregisterLight(std::size_t lightIndex) = 0;
|
||||||
virtual void UnregisterLight(Light* light) = 0;
|
|
||||||
virtual void UnregisterMaterialPass(MaterialPass* materialPass) = 0;
|
virtual void UnregisterMaterialPass(MaterialPass* materialPass) = 0;
|
||||||
virtual void UnregisterViewer(AbstractViewer* viewerInstance) = 0;
|
virtual void UnregisterRenderable(std::size_t renderableIndex) = 0;
|
||||||
|
virtual void UnregisterViewer(std::size_t viewerIndex) = 0;
|
||||||
|
virtual void UnregisterWorldInstance(std::size_t worldInstance) = 0;
|
||||||
|
|
||||||
|
virtual void UpdateLightRenderMask(std::size_t lightIndex, UInt32 renderMask) = 0;
|
||||||
|
virtual void UpdateRenderableRenderMask(std::size_t renderableIndex, UInt32 renderMask) = 0;
|
||||||
|
virtual void UpdateRenderableScissorBox(std::size_t renderableIndex, const Recti& scissorBox) = 0;
|
||||||
|
virtual void UpdateViewerRenderMask(std::size_t viewerIndex, Int32 renderOrder) = 0;
|
||||||
|
|
||||||
FramePipeline& operator=(const FramePipeline&) = delete;
|
FramePipeline& operator=(const FramePipeline&) = delete;
|
||||||
FramePipeline& operator=(FramePipeline&&) noexcept = default;
|
FramePipeline& operator=(FramePipeline&&) noexcept = default;
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,13 @@
|
||||||
#define NAZARA_GRAPHICS_SYSTEMS_RENDERSYSTEM_HPP
|
#define NAZARA_GRAPHICS_SYSTEMS_RENDERSYSTEM_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Core/MemoryPool.hpp>
|
||||||
#include <Nazara/Graphics/Graphics.hpp>
|
#include <Nazara/Graphics/Graphics.hpp>
|
||||||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||||
#include <Nazara/Graphics/Components/LightComponent.hpp>
|
#include <Nazara/Graphics/Components/LightComponent.hpp>
|
||||||
#include <Nazara/Utility/Node.hpp>
|
#include <Nazara/Utility/Node.hpp>
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
@ -47,19 +49,33 @@ namespace Nz
|
||||||
|
|
||||||
struct CameraEntity
|
struct CameraEntity
|
||||||
{
|
{
|
||||||
|
entt::entity entity;
|
||||||
|
std::size_t poolIndex;
|
||||||
|
std::size_t viewerIndex;
|
||||||
|
|
||||||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsEntity
|
struct GraphicsEntity
|
||||||
{
|
{
|
||||||
|
entt::entity entity;
|
||||||
|
std::array<std::size_t, GraphicsComponent::MaxRenderableCount> renderableIndices;
|
||||||
|
std::size_t poolIndex;
|
||||||
|
std::size_t worldInstanceIndex;
|
||||||
|
|
||||||
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
|
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
|
||||||
NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach);
|
NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach);
|
||||||
|
NazaraSlot(GraphicsComponent, OnScissorBoxUpdate, onScissorBoxUpdate);
|
||||||
NazaraSlot(GraphicsComponent, OnVisibilityUpdate, onVisibilityUpdate);
|
NazaraSlot(GraphicsComponent, OnVisibilityUpdate, onVisibilityUpdate);
|
||||||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LightEntity
|
struct LightEntity
|
||||||
{
|
{
|
||||||
|
entt::entity entity;
|
||||||
|
std::array<std::size_t, LightComponent::MaxLightCount> lightIndices;
|
||||||
|
std::size_t poolIndex;
|
||||||
|
|
||||||
NazaraSlot(LightComponent, OnLightAttached, onLightAttached);
|
NazaraSlot(LightComponent, OnLightAttached, onLightAttached);
|
||||||
NazaraSlot(LightComponent, OnLightDetach, onLightDetach);
|
NazaraSlot(LightComponent, OnLightDetach, onLightDetach);
|
||||||
NazaraSlot(LightComponent, OnVisibilityUpdate, onVisibilityUpdate);
|
NazaraSlot(LightComponent, OnVisibilityUpdate, onVisibilityUpdate);
|
||||||
|
|
@ -73,17 +89,20 @@ namespace Nz
|
||||||
entt::observer m_cameraConstructObserver;
|
entt::observer m_cameraConstructObserver;
|
||||||
entt::observer m_graphicsConstructObserver;
|
entt::observer m_graphicsConstructObserver;
|
||||||
entt::observer m_lightConstructObserver;
|
entt::observer m_lightConstructObserver;
|
||||||
std::set<entt::entity> m_invalidatedCameraNode;
|
std::set<CameraEntity*> m_invalidatedCameraNode;
|
||||||
std::set<entt::entity> m_invalidatedGfxWorldNode;
|
std::set<GraphicsEntity*> m_invalidatedGfxWorldNode;
|
||||||
std::set<entt::entity> m_invalidatedLightWorldNode;
|
std::set<LightEntity*> m_invalidatedLightWorldNode;
|
||||||
std::unique_ptr<FramePipeline> m_pipeline;
|
std::unique_ptr<FramePipeline> m_pipeline;
|
||||||
std::unordered_map<entt::entity, CameraEntity> m_cameraEntities;
|
std::unordered_map<entt::entity, CameraEntity*> m_cameraEntities;
|
||||||
std::unordered_map<entt::entity, GraphicsEntity> m_graphicsEntities;
|
std::unordered_map<entt::entity, GraphicsEntity*> m_graphicsEntities;
|
||||||
std::unordered_map<entt::entity, LightEntity> m_lightEntities;
|
std::unordered_map<entt::entity, LightEntity*> m_lightEntities;
|
||||||
std::unordered_set<entt::entity> m_newlyHiddenGfxEntities;
|
std::unordered_set<GraphicsEntity*> m_newlyHiddenGfxEntities;
|
||||||
std::unordered_set<entt::entity> m_newlyVisibleGfxEntities;
|
std::unordered_set<GraphicsEntity*> m_newlyVisibleGfxEntities;
|
||||||
std::unordered_set<entt::entity> m_newlyHiddenLightEntities;
|
std::unordered_set<LightEntity*> m_newlyHiddenLightEntities;
|
||||||
std::unordered_set<entt::entity> m_newlyVisibleLightEntities;
|
std::unordered_set<LightEntity*> m_newlyVisibleLightEntities;
|
||||||
|
MemoryPool<CameraEntity> m_cameraEntityPool;
|
||||||
|
MemoryPool<GraphicsEntity> m_graphicsEntityPool;
|
||||||
|
MemoryPool<LightEntity> m_lightEntityPool;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,117 +27,49 @@
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
ForwardFramePipeline::ForwardFramePipeline() :
|
ForwardFramePipeline::ForwardFramePipeline() :
|
||||||
|
m_renderablePool(4096),
|
||||||
|
m_lightPool(64),
|
||||||
|
m_viewerPool(8),
|
||||||
|
m_worldInstances(2048),
|
||||||
m_rebuildFrameGraph(true)
|
m_rebuildFrameGraph(true)
|
||||||
{
|
{
|
||||||
auto& passRegistry = Graphics::Instance()->GetMaterialPassRegistry();
|
|
||||||
m_forwardPassIndex = passRegistry.GetPassIndex("ForwardPass");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ForwardFramePipeline::~ForwardFramePipeline()
|
ForwardFramePipeline::~ForwardFramePipeline()
|
||||||
{
|
{
|
||||||
// Force viewer passes to unregister their materials
|
// Force viewer passes to unregister their materials
|
||||||
m_viewers.clear();
|
m_viewerPool.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance)
|
void ForwardFramePipeline::InvalidateViewer(std::size_t viewerIndex)
|
||||||
{
|
{
|
||||||
m_invalidatedViewerInstances.insert(viewerInstance);
|
m_invalidatedViewerInstances.Set(viewerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::InvalidateWorldInstance(WorldInstance* worldInstance)
|
void ForwardFramePipeline::InvalidateWorldInstance(std::size_t worldInstanceIndex)
|
||||||
{
|
{
|
||||||
m_invalidatedWorldInstances.insert(worldInstance);
|
m_invalidatedWorldInstances.Set(worldInstanceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask)
|
std::size_t ForwardFramePipeline::RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask)
|
||||||
{
|
{
|
||||||
m_removedWorldInstances.erase(worldInstance);
|
std::size_t lightIndex;
|
||||||
|
LightData* lightData = m_lightPool.Allocate(lightIndex);
|
||||||
auto& renderableMap = m_renderables[worldInstance];
|
lightData->light = std::move(light);
|
||||||
if (renderableMap.empty())
|
lightData->renderMask = renderMask;
|
||||||
InvalidateWorldInstance(worldInstance.get());
|
lightData->onLightInvalidated.Connect(lightData->light->OnLightDataInvalided, [=](Light*)
|
||||||
|
|
||||||
if (auto it = renderableMap.find(instancedRenderable); it == renderableMap.end())
|
|
||||||
{
|
|
||||||
auto& renderableData = renderableMap.emplace(instancedRenderable, RenderableData{}).first->second;
|
|
||||||
renderableData.renderMask = renderMask;
|
|
||||||
|
|
||||||
renderableData.onElementInvalidated.Connect(instancedRenderable->OnElementInvalidated, [=](InstancedRenderable* /*instancedRenderable*/)
|
|
||||||
{
|
|
||||||
// TODO: Invalidate only relevant viewers and passes
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
|
||||||
{
|
|
||||||
UInt32 viewerRenderMask = viewer->GetRenderMask();
|
|
||||||
|
|
||||||
if (viewerRenderMask & renderMask)
|
|
||||||
{
|
|
||||||
if (viewerData.depthPrepass)
|
|
||||||
viewerData.depthPrepass->ForceInvalidation();
|
|
||||||
|
|
||||||
viewerData.forwardPass->ForceInvalidation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
renderableData.onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr<Material>& newMaterial)
|
|
||||||
{
|
|
||||||
if (newMaterial)
|
|
||||||
{
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
|
||||||
{
|
|
||||||
if (viewerData.depthPrepass)
|
|
||||||
viewerData.depthPrepass->RegisterMaterial(*newMaterial);
|
|
||||||
|
|
||||||
viewerData.forwardPass->RegisterMaterial(*newMaterial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex);
|
|
||||||
if (prevMaterial)
|
|
||||||
{
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
|
||||||
{
|
|
||||||
if (viewerData.depthPrepass)
|
|
||||||
viewerData.depthPrepass->UnregisterMaterial(*prevMaterial);
|
|
||||||
|
|
||||||
viewerData.forwardPass->UnregisterMaterial(*prevMaterial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
std::size_t matCount = instancedRenderable->GetMaterialCount();
|
|
||||||
for (std::size_t i = 0; i < matCount; ++i)
|
|
||||||
{
|
|
||||||
if (Material* mat = instancedRenderable->GetMaterial(i).get())
|
|
||||||
{
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
|
||||||
{
|
|
||||||
if (viewerData.depthPrepass)
|
|
||||||
viewerData.depthPrepass->RegisterMaterial(*mat);
|
|
||||||
|
|
||||||
viewerData.forwardPass->RegisterMaterial(*mat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForwardFramePipeline::RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask)
|
|
||||||
{
|
|
||||||
auto& lightData = m_lights[light.get()];
|
|
||||||
lightData.light = std::move(light);
|
|
||||||
lightData.renderMask = renderMask;
|
|
||||||
lightData.onLightInvalidated.Connect(lightData.light->OnLightDataInvalided, [=](Light*)
|
|
||||||
{
|
{
|
||||||
//TODO: Switch lights to storage buffers so they can all be part of GPU memory
|
//TODO: Switch lights to storage buffers so they can all be part of GPU memory
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
for (auto& viewerData : m_viewerPool)
|
||||||
{
|
{
|
||||||
UInt32 viewerRenderMask = viewer->GetRenderMask();
|
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
|
||||||
|
|
||||||
if (viewerRenderMask & renderMask)
|
if (viewerRenderMask & renderMask)
|
||||||
viewerData.forwardPass->ForceInvalidation();
|
viewerData.forwardPass->ForceInvalidation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return lightIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* materialPass)
|
void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* materialPass)
|
||||||
|
|
@ -156,16 +88,100 @@ namespace Nz
|
||||||
|
|
||||||
it->second.usedCount++;
|
it->second.usedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
|
std::size_t ForwardFramePipeline::RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox)
|
||||||
{
|
{
|
||||||
auto& viewerData = m_viewers.emplace(viewerInstance, ViewerData{}).first->second;
|
std::size_t renderableIndex;
|
||||||
|
RenderableData* renderableData = m_renderablePool.Allocate(renderableIndex);
|
||||||
|
renderableData->renderable = instancedRenderable;
|
||||||
|
renderableData->renderMask = renderMask;
|
||||||
|
renderableData->scissorBox = scissorBox;
|
||||||
|
renderableData->worldInstanceIndex = worldInstanceIndex;
|
||||||
|
|
||||||
|
renderableData->onElementInvalidated.Connect(instancedRenderable->OnElementInvalidated, [=](InstancedRenderable* /*instancedRenderable*/)
|
||||||
|
{
|
||||||
|
// TODO: Invalidate only relevant viewers and passes
|
||||||
|
for (auto& viewerData : m_viewerPool)
|
||||||
|
{
|
||||||
|
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
|
||||||
|
|
||||||
|
if (viewerRenderMask & renderMask)
|
||||||
|
{
|
||||||
|
if (viewerData.depthPrepass)
|
||||||
|
viewerData.depthPrepass->ForceInvalidation();
|
||||||
|
|
||||||
|
viewerData.forwardPass->ForceInvalidation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
renderableData->onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr<Material>& newMaterial)
|
||||||
|
{
|
||||||
|
if (newMaterial)
|
||||||
|
{
|
||||||
|
for (auto& viewerData : m_viewerPool)
|
||||||
|
{
|
||||||
|
if (viewerData.depthPrepass)
|
||||||
|
viewerData.depthPrepass->RegisterMaterial(*newMaterial);
|
||||||
|
|
||||||
|
viewerData.forwardPass->RegisterMaterial(*newMaterial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex);
|
||||||
|
if (prevMaterial)
|
||||||
|
{
|
||||||
|
for (auto& viewerData : m_viewerPool)
|
||||||
|
{
|
||||||
|
if (viewerData.depthPrepass)
|
||||||
|
viewerData.depthPrepass->UnregisterMaterial(*prevMaterial);
|
||||||
|
|
||||||
|
viewerData.forwardPass->UnregisterMaterial(*prevMaterial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::size_t matCount = instancedRenderable->GetMaterialCount();
|
||||||
|
for (std::size_t i = 0; i < matCount; ++i)
|
||||||
|
{
|
||||||
|
if (Material* mat = instancedRenderable->GetMaterial(i).get())
|
||||||
|
{
|
||||||
|
for (auto& viewerData : m_viewerPool)
|
||||||
|
{
|
||||||
|
if (viewerData.depthPrepass)
|
||||||
|
viewerData.depthPrepass->RegisterMaterial(*mat);
|
||||||
|
|
||||||
|
viewerData.forwardPass->RegisterMaterial(*mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
|
||||||
|
{
|
||||||
|
std::size_t viewerIndex;
|
||||||
|
auto& viewerData = *m_viewerPool.Allocate(viewerIndex);
|
||||||
viewerData.renderOrder = renderOrder;
|
viewerData.renderOrder = renderOrder;
|
||||||
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, viewerInstance);
|
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, viewerInstance);
|
||||||
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, viewerInstance);
|
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, viewerInstance);
|
||||||
|
viewerData.viewer = viewerInstance;
|
||||||
|
|
||||||
m_invalidatedViewerInstances.insert(viewerInstance);
|
m_invalidatedViewerInstances.UnboundedSet(viewerIndex);
|
||||||
m_rebuildFrameGraph = true;
|
m_rebuildFrameGraph = true;
|
||||||
|
|
||||||
|
return viewerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ForwardFramePipeline::RegisterWorldInstance(WorldInstancePtr worldInstance)
|
||||||
|
{
|
||||||
|
std::size_t worldInstanceIndex;
|
||||||
|
m_worldInstances.Allocate(worldInstanceIndex, std::move(worldInstance));
|
||||||
|
|
||||||
|
m_invalidatedWorldInstances.UnboundedSet(worldInstanceIndex);
|
||||||
|
|
||||||
|
return worldInstanceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
||||||
|
|
@ -174,8 +190,13 @@ namespace Nz
|
||||||
|
|
||||||
Graphics* graphics = Graphics::Instance();
|
Graphics* graphics = Graphics::Instance();
|
||||||
|
|
||||||
renderFrame.PushForRelease(std::move(m_removedWorldInstances));
|
// Destroy world instances at the end of the frame
|
||||||
m_removedWorldInstances.clear();
|
for (std::size_t worldInstanceIndex = m_removedWorldInstances.FindFirst(); worldInstanceIndex != m_removedWorldInstances.npos; worldInstanceIndex = m_removedWorldInstances.FindNext(worldInstanceIndex))
|
||||||
|
{
|
||||||
|
renderFrame.PushForRelease(*m_worldInstances.RetrieveFromIndex(worldInstanceIndex));
|
||||||
|
m_worldInstances.Free(worldInstanceIndex);
|
||||||
|
}
|
||||||
|
m_removedWorldInstances.Clear();
|
||||||
|
|
||||||
if (m_rebuildFrameGraph)
|
if (m_rebuildFrameGraph)
|
||||||
{
|
{
|
||||||
|
|
@ -192,15 +213,19 @@ namespace Nz
|
||||||
{
|
{
|
||||||
builder.PreTransferBarrier();
|
builder.PreTransferBarrier();
|
||||||
|
|
||||||
for (AbstractViewer* viewer : m_invalidatedViewerInstances)
|
for (std::size_t viewerIndex = m_invalidatedViewerInstances.FindFirst(); viewerIndex != m_invalidatedViewerInstances.npos; viewerIndex = m_invalidatedViewerInstances.FindNext(viewerIndex))
|
||||||
viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder);
|
{
|
||||||
|
ViewerData* viewerData = m_viewerPool.RetrieveFromIndex(viewerIndex);
|
||||||
|
viewerData->viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder);
|
||||||
|
}
|
||||||
|
m_invalidatedViewerInstances.Reset();
|
||||||
|
|
||||||
m_invalidatedViewerInstances.clear();
|
for (std::size_t worldInstanceIndex = m_invalidatedWorldInstances.FindFirst(); worldInstanceIndex != m_invalidatedWorldInstances.npos; worldInstanceIndex = m_invalidatedWorldInstances.FindNext(worldInstanceIndex))
|
||||||
|
{
|
||||||
for (WorldInstance* worldInstance : m_invalidatedWorldInstances)
|
WorldInstancePtr& worldInstance = *m_worldInstances.RetrieveFromIndex(worldInstanceIndex);
|
||||||
worldInstance->UpdateBuffers(uploadPool, builder);
|
worldInstance->UpdateBuffers(uploadPool, builder);
|
||||||
|
}
|
||||||
m_invalidatedWorldInstances.clear();
|
m_invalidatedWorldInstances.Reset();
|
||||||
|
|
||||||
for (MaterialPass* materialPass : m_invalidatedMaterialPasses)
|
for (MaterialPass* materialPass : m_invalidatedMaterialPasses)
|
||||||
materialPass->Update(renderFrame, builder);
|
materialPass->Update(renderFrame, builder);
|
||||||
|
|
@ -218,61 +243,53 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render queues handling
|
// Render queues handling
|
||||||
for (auto&& [viewer, data] : m_viewers)
|
for (auto& viewerData : m_viewerPool)
|
||||||
{
|
{
|
||||||
auto& viewerData = data;
|
UInt32 renderMask = viewerData.viewer->GetRenderMask();
|
||||||
|
|
||||||
UInt32 renderMask = viewer->GetRenderMask();
|
|
||||||
|
|
||||||
// Frustum culling
|
// Frustum culling
|
||||||
const Matrix4f& viewProjMatrix = viewer->GetViewerInstance().GetViewProjMatrix();
|
const Matrix4f& viewProjMatrix = viewerData.viewer->GetViewerInstance().GetViewProjMatrix();
|
||||||
|
|
||||||
Frustumf frustum = Frustumf::Extract(viewProjMatrix);
|
Frustumf frustum = Frustumf::Extract(viewProjMatrix);
|
||||||
|
|
||||||
std::size_t visibilityHash = 5U;
|
std::size_t visibilityHash = 5U;
|
||||||
|
|
||||||
m_visibleRenderables.clear();
|
m_visibleRenderables.clear();
|
||||||
for (const auto& [worldInstance, renderables] : m_renderables)
|
for (const RenderableData& renderableData : m_renderablePool)
|
||||||
{
|
{
|
||||||
bool isInstanceVisible = false;
|
if ((renderMask & renderableData.renderMask) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (const auto& [renderable, renderableData] : renderables)
|
WorldInstancePtr& worldInstance = *m_worldInstances.RetrieveFromIndex(renderableData.worldInstanceIndex);
|
||||||
{
|
|
||||||
if ((renderMask & renderableData.renderMask) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Get global AABB
|
// Get global AABB
|
||||||
BoundingVolumef boundingVolume(renderable->GetAABB());
|
BoundingVolumef boundingVolume(renderableData.renderable->GetAABB());
|
||||||
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
boundingVolume.Update(worldInstance->GetWorldMatrix());
|
||||||
|
|
||||||
if (!frustum.Contains(boundingVolume))
|
if (!frustum.Contains(boundingVolume))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto& visibleRenderable = m_visibleRenderables.emplace_back();
|
auto& visibleRenderable = m_visibleRenderables.emplace_back();
|
||||||
visibleRenderable.instancedRenderable = renderable;
|
visibleRenderable.instancedRenderable = renderableData.renderable;
|
||||||
visibleRenderable.worldInstance = worldInstance.get();
|
visibleRenderable.scissorBox = renderableData.scissorBox;
|
||||||
|
visibleRenderable.worldInstance = worldInstance.get();
|
||||||
|
|
||||||
isInstanceVisible = true;
|
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(&renderableData));
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(renderable));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInstanceVisible)
|
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(worldInstance.get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lights update don't trigger a rebuild of the depth pre-pass
|
// Lights update don't trigger a rebuild of the depth pre-pass
|
||||||
std::size_t depthVisibilityHash = visibilityHash;
|
std::size_t depthVisibilityHash = visibilityHash;
|
||||||
|
|
||||||
m_visibleLights.clear();
|
m_visibleLights.clear();
|
||||||
for (auto&& [light, lightData] : m_lights)
|
for (const LightData& lightData : m_lightPool)
|
||||||
{
|
{
|
||||||
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
|
const BoundingVolumef& boundingVolume = lightData.light->GetBoundingVolume();
|
||||||
|
|
||||||
// TODO: Use more precise tests for point lights (frustum/sphere is cheap)
|
// TODO: Use more precise tests for point lights (frustum/sphere is cheap)
|
||||||
if (renderMask & lightData.renderMask && frustum.Contains(boundingVolume))
|
if (renderMask & lightData.renderMask && frustum.Contains(boundingVolume))
|
||||||
{
|
{
|
||||||
m_visibleLights.push_back(light);
|
m_visibleLights.push_back(lightData.light.get());
|
||||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(light));
|
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(lightData.light.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,7 +302,7 @@ namespace Nz
|
||||||
if (m_bakedFrameGraph.Resize(renderFrame))
|
if (m_bakedFrameGraph.Resize(renderFrame))
|
||||||
{
|
{
|
||||||
const std::shared_ptr<TextureSampler>& sampler = graphics->GetSamplerCache().Get({});
|
const std::shared_ptr<TextureSampler>& sampler = graphics->GetSamplerCache().Get({});
|
||||||
for (auto&& [_, viewerData] : m_viewers)
|
for (auto& viewerData : m_viewerPool)
|
||||||
{
|
{
|
||||||
if (viewerData.blitShaderBinding)
|
if (viewerData.blitShaderBinding)
|
||||||
renderFrame.PushForRelease(std::move(viewerData.blitShaderBinding));
|
renderFrame.PushForRelease(std::move(viewerData.blitShaderBinding));
|
||||||
|
|
@ -362,43 +379,9 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable)
|
void ForwardFramePipeline::UnregisterLight(std::size_t lightIndex)
|
||||||
{
|
{
|
||||||
auto instanceIt = m_renderables.find(worldInstance);
|
m_lightPool.Free(lightIndex);
|
||||||
if (instanceIt == m_renderables.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto& instancedRenderables = instanceIt->second;
|
|
||||||
|
|
||||||
auto renderableIt = instancedRenderables.find(instancedRenderable);
|
|
||||||
if (renderableIt == instancedRenderables.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (instancedRenderables.size() > 1)
|
|
||||||
instancedRenderables.erase(renderableIt);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_removedWorldInstances.insert(worldInstance);
|
|
||||||
m_renderables.erase(instanceIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t matCount = instancedRenderable->GetMaterialCount();
|
|
||||||
for (std::size_t i = 0; i < matCount; ++i)
|
|
||||||
{
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
|
||||||
{
|
|
||||||
const auto& material = instancedRenderable->GetMaterial(i);
|
|
||||||
if (viewerData.depthPrepass)
|
|
||||||
viewerData.depthPrepass->UnregisterMaterial(*material);
|
|
||||||
|
|
||||||
viewerData.forwardPass->UnregisterMaterial(*material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForwardFramePipeline::UnregisterLight(Light* light)
|
|
||||||
{
|
|
||||||
m_lights.erase(light);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* materialPass)
|
void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* materialPass)
|
||||||
|
|
@ -412,17 +395,72 @@ namespace Nz
|
||||||
m_activeMaterialPasses.erase(materialPass);
|
m_activeMaterialPasses.erase(materialPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance)
|
void ForwardFramePipeline::UnregisterRenderable(std::size_t renderableIndex)
|
||||||
{
|
{
|
||||||
m_viewers.erase(viewerInstance);
|
RenderableData& renderable = *m_renderablePool.RetrieveFromIndex(renderableIndex);
|
||||||
|
|
||||||
|
std::size_t matCount = renderable.renderable->GetMaterialCount();
|
||||||
|
for (std::size_t i = 0; i < matCount; ++i)
|
||||||
|
{
|
||||||
|
for (auto& viewerData : m_viewerPool)
|
||||||
|
{
|
||||||
|
const auto& material = renderable.renderable->GetMaterial(i);
|
||||||
|
if (viewerData.depthPrepass)
|
||||||
|
viewerData.depthPrepass->UnregisterMaterial(*material);
|
||||||
|
|
||||||
|
viewerData.forwardPass->UnregisterMaterial(*material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderablePool.Free(renderableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UnregisterViewer(std::size_t viewerIndex)
|
||||||
|
{
|
||||||
|
m_viewerPool.Free(viewerIndex);
|
||||||
|
m_invalidatedViewerInstances.Reset(viewerIndex);
|
||||||
m_rebuildFrameGraph = true;
|
m_rebuildFrameGraph = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UnregisterWorldInstance(std::size_t worldInstance)
|
||||||
|
{
|
||||||
|
// Defer world instance release
|
||||||
|
m_removedWorldInstances.UnboundedSet(worldInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UpdateLightRenderMask(std::size_t lightIndex, UInt32 renderMask)
|
||||||
|
{
|
||||||
|
LightData* lightData = m_lightPool.RetrieveFromIndex(lightIndex);
|
||||||
|
lightData->renderMask = renderMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UpdateRenderableRenderMask(std::size_t renderableIndex, UInt32 renderMask)
|
||||||
|
{
|
||||||
|
RenderableData* renderableData = m_renderablePool.RetrieveFromIndex(renderableIndex);
|
||||||
|
renderableData->renderMask = renderMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UpdateRenderableScissorBox(std::size_t renderableIndex, const Recti& scissorBox)
|
||||||
|
{
|
||||||
|
RenderableData* renderableData = m_renderablePool.RetrieveFromIndex(renderableIndex);
|
||||||
|
renderableData->scissorBox = scissorBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardFramePipeline::UpdateViewerRenderMask(std::size_t viewerIndex, Int32 renderOrder)
|
||||||
|
{
|
||||||
|
ViewerData* viewerData = m_viewerPool.RetrieveFromIndex(viewerIndex);
|
||||||
|
if (viewerData->renderOrder != renderOrder)
|
||||||
|
{
|
||||||
|
viewerData->renderOrder = renderOrder;
|
||||||
|
m_rebuildFrameGraph = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BakedFrameGraph ForwardFramePipeline::BuildFrameGraph()
|
BakedFrameGraph ForwardFramePipeline::BuildFrameGraph()
|
||||||
{
|
{
|
||||||
FrameGraph frameGraph;
|
FrameGraph frameGraph;
|
||||||
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
for (auto& viewerData : m_viewerPool)
|
||||||
{
|
{
|
||||||
viewerData.colorAttachment = frameGraph.AddAttachment({
|
viewerData.colorAttachment = frameGraph.AddAttachment({
|
||||||
"Color",
|
"Color",
|
||||||
|
|
@ -433,26 +471,21 @@ namespace Nz
|
||||||
"Depth-stencil buffer",
|
"Depth-stencil buffer",
|
||||||
Graphics::Instance()->GetPreferredDepthStencilFormat()
|
Graphics::Instance()->GetPreferredDepthStencilFormat()
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
for (auto&& [viewer, data] : m_viewers)
|
|
||||||
{
|
|
||||||
auto& viewerData = data;
|
|
||||||
|
|
||||||
if (viewerData.depthPrepass)
|
if (viewerData.depthPrepass)
|
||||||
viewerData.depthPrepass->RegisterToFrameGraph(frameGraph, viewerData.depthStencilAttachment);
|
viewerData.depthPrepass->RegisterToFrameGraph(frameGraph, viewerData.depthStencilAttachment);
|
||||||
|
|
||||||
viewerData.forwardPass->RegisterToFrameGraph(frameGraph, viewerData.colorAttachment, viewerData.depthStencilAttachment);
|
viewerData.forwardPass->RegisterToFrameGraph(frameGraph, viewerData.colorAttachment, viewerData.depthStencilAttachment, viewerData.depthPrepass != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
using ViewerPair = std::pair<const RenderTarget*, const ViewerData*>;
|
using ViewerPair = std::pair<const RenderTarget*, const ViewerData*>;
|
||||||
|
|
||||||
StackArray<ViewerPair> viewers = NazaraStackArray(ViewerPair, m_viewers.size());
|
StackArray<ViewerPair> viewers = NazaraStackArray(ViewerPair, m_viewerPool.size());
|
||||||
auto viewerIt = viewers.begin();
|
auto viewerIt = viewers.begin();
|
||||||
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
for (auto& viewerData : m_viewerPool)
|
||||||
{
|
{
|
||||||
const RenderTarget& renderTarget = viewer->GetRenderTarget();
|
const RenderTarget& renderTarget = viewerData.viewer->GetRenderTarget();
|
||||||
*viewerIt++ = std::make_pair(&renderTarget, &viewerData);
|
*viewerIt++ = std::make_pair(&renderTarget, &viewerData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -265,11 +265,14 @@ namespace Nz
|
||||||
it->second.usedCount++;
|
it->second.usedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex)
|
void ForwardPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex, bool hasDepthPrepass)
|
||||||
{
|
{
|
||||||
FramePass& forwardPass = frameGraph.AddPass("Forward pass");
|
FramePass& forwardPass = frameGraph.AddPass("Forward pass");
|
||||||
forwardPass.AddOutput(colorBufferIndex);
|
forwardPass.AddOutput(colorBufferIndex);
|
||||||
forwardPass.SetDepthStencilInput(depthBufferIndex);
|
if (hasDepthPrepass)
|
||||||
|
forwardPass.SetDepthStencilInput(depthBufferIndex);
|
||||||
|
else
|
||||||
|
forwardPass.SetDepthStencilOutput(depthBufferIndex);
|
||||||
|
|
||||||
forwardPass.SetClearColor(0, m_viewer->GetClearColor());
|
forwardPass.SetClearColor(0, m_viewer->GetClearColor());
|
||||||
forwardPass.SetDepthStencilClear(1.f, 0);
|
forwardPass.SetDepthStencilClear(1.f, 0);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,10 @@ namespace Nz
|
||||||
RenderSystem::RenderSystem(entt::registry& registry) :
|
RenderSystem::RenderSystem(entt::registry& registry) :
|
||||||
m_cameraConstructObserver(registry, entt::collector.group<CameraComponent, NodeComponent>()),
|
m_cameraConstructObserver(registry, entt::collector.group<CameraComponent, NodeComponent>()),
|
||||||
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>()),
|
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>()),
|
||||||
m_lightConstructObserver(registry, entt::collector.group<LightComponent, NodeComponent>())
|
m_lightConstructObserver(registry, entt::collector.group<LightComponent, NodeComponent>()),
|
||||||
|
m_cameraEntityPool(8),
|
||||||
|
m_graphicsEntityPool(1024),
|
||||||
|
m_lightEntityPool(32)
|
||||||
{
|
{
|
||||||
m_cameraDestroyConnection = registry.on_destroy<CameraComponent>().connect<&RenderSystem::OnCameraDestroy>(this);
|
m_cameraDestroyConnection = registry.on_destroy<CameraComponent>().connect<&RenderSystem::OnCameraDestroy>(this);
|
||||||
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
|
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
|
||||||
|
|
@ -47,16 +50,20 @@ namespace Nz
|
||||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
||||||
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
||||||
|
|
||||||
m_pipeline->RegisterViewer(&entityCamera, entityCamera.GetRenderOrder());
|
std::size_t poolIndex;
|
||||||
|
CameraEntity* cameraEntity = m_cameraEntityPool.Allocate(poolIndex);
|
||||||
|
cameraEntity->poolIndex = poolIndex;
|
||||||
|
cameraEntity->entity = entity;
|
||||||
|
cameraEntity->viewerIndex = m_pipeline->RegisterViewer(&entityCamera, entityCamera.GetRenderOrder());
|
||||||
|
cameraEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, cameraEntity](const Node* /*node*/)
|
||||||
|
{
|
||||||
|
m_invalidatedCameraNode.insert(cameraEntity);
|
||||||
|
});
|
||||||
|
|
||||||
m_invalidatedCameraNode.insert(entity);
|
m_invalidatedCameraNode.insert(cameraEntity);
|
||||||
|
|
||||||
assert(m_cameraEntities.find(entity) == m_cameraEntities.end());
|
assert(m_cameraEntities.find(entity) == m_cameraEntities.end());
|
||||||
auto& cameraEntity = m_cameraEntities[entity];
|
m_cameraEntities.emplace(entity, cameraEntity);
|
||||||
cameraEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/)
|
|
||||||
{
|
|
||||||
m_invalidatedCameraNode.insert(entity);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_graphicsConstructObserver.each([&](entt::entity entity)
|
m_graphicsConstructObserver.each([&](entt::entity entity)
|
||||||
|
|
@ -64,53 +71,77 @@ namespace Nz
|
||||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
||||||
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
||||||
|
|
||||||
if (entityGfx.IsVisible())
|
std::size_t poolIndex;
|
||||||
|
GraphicsEntity* graphicsEntity = m_graphicsEntityPool.Allocate(poolIndex);
|
||||||
|
graphicsEntity->entity = entity;
|
||||||
|
graphicsEntity->poolIndex = poolIndex;
|
||||||
|
graphicsEntity->worldInstanceIndex = m_pipeline->RegisterWorldInstance(entityGfx.GetWorldInstance());
|
||||||
|
graphicsEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, graphicsEntity](const Node* /*node*/)
|
||||||
{
|
{
|
||||||
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
|
m_invalidatedGfxWorldNode.insert(graphicsEntity);
|
||||||
for (const auto& renderableEntry : entityGfx.GetRenderables())
|
|
||||||
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_invalidatedGfxWorldNode.insert(entity);
|
|
||||||
|
|
||||||
assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end());
|
|
||||||
auto& graphicsEntity = m_graphicsEntities[entity];
|
|
||||||
graphicsEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/)
|
|
||||||
{
|
|
||||||
m_invalidatedGfxWorldNode.insert(entity);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
|
graphicsEntity->onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this, graphicsEntity](GraphicsComponent* gfx, std::size_t renderableIndex)
|
||||||
{
|
{
|
||||||
if (!gfx->IsVisible())
|
if (!gfx->IsVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
|
const auto& renderableEntry = gfx->GetRenderableEntry(renderableIndex);
|
||||||
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
|
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, gfx->GetScissorBox());
|
||||||
});
|
});
|
||||||
|
|
||||||
graphicsEntity.onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
|
graphicsEntity->onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this, graphicsEntity](GraphicsComponent* gfx, std::size_t renderableIndex)
|
||||||
{
|
{
|
||||||
if (!gfx->IsVisible())
|
if (!gfx->IsVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const WorldInstancePtr& worldInstance = gfx->GetWorldInstance();
|
m_pipeline->UnregisterRenderable(graphicsEntity->renderableIndices[renderableIndex]);
|
||||||
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
graphicsEntity.onVisibilityUpdate.Connect(entityGfx.OnVisibilityUpdate, [this, entity](GraphicsComponent* /*gfx*/, bool isVisible)
|
graphicsEntity->onScissorBoxUpdate.Connect(entityGfx.OnScissorBoxUpdate, [this, graphicsEntity](GraphicsComponent* gfx, const Recti& scissorBox)
|
||||||
|
{
|
||||||
|
if (!gfx->IsVisible())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex)
|
||||||
|
{
|
||||||
|
const auto& renderableEntry = gfx->GetRenderableEntry(renderableIndex);
|
||||||
|
if (!renderableEntry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pipeline->UpdateRenderableScissorBox(graphicsEntity->renderableIndices[renderableIndex], scissorBox);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
graphicsEntity->onVisibilityUpdate.Connect(entityGfx.OnVisibilityUpdate, [this, graphicsEntity](GraphicsComponent* /*gfx*/, bool isVisible)
|
||||||
{
|
{
|
||||||
if (isVisible)
|
if (isVisible)
|
||||||
{
|
{
|
||||||
m_newlyHiddenGfxEntities.erase(entity);
|
m_newlyHiddenGfxEntities.erase(graphicsEntity);
|
||||||
m_newlyVisibleGfxEntities.insert(entity);
|
m_newlyVisibleGfxEntities.insert(graphicsEntity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_newlyHiddenGfxEntities.insert(entity);
|
m_newlyHiddenGfxEntities.insert(graphicsEntity);
|
||||||
m_newlyVisibleGfxEntities.erase(entity);
|
m_newlyVisibleGfxEntities.erase(graphicsEntity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
m_invalidatedGfxWorldNode.insert(graphicsEntity);
|
||||||
|
|
||||||
|
if (entityGfx.IsVisible())
|
||||||
|
{
|
||||||
|
for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex)
|
||||||
|
{
|
||||||
|
const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex);
|
||||||
|
if (!renderableEntry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end());
|
||||||
|
m_graphicsEntities.emplace(entity, graphicsEntity);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_lightConstructObserver.each([&](entt::entity entity)
|
m_lightConstructObserver.each([&](entt::entity entity)
|
||||||
|
|
@ -118,50 +149,67 @@ namespace Nz
|
||||||
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
||||||
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
||||||
|
|
||||||
if (entityLight.IsVisible())
|
std::size_t poolIndex;
|
||||||
|
LightEntity* lightEntity = m_lightEntityPool.Allocate(poolIndex);
|
||||||
|
lightEntity->entity = entity;
|
||||||
|
lightEntity->poolIndex = poolIndex;
|
||||||
|
lightEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, lightEntity](const Node* /*node*/)
|
||||||
{
|
{
|
||||||
for (const auto& lightEntry : entityLight.GetLights())
|
m_invalidatedLightWorldNode.insert(lightEntity);
|
||||||
m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_invalidatedLightWorldNode.insert(entity);
|
|
||||||
|
|
||||||
assert(m_lightEntities.find(entity) == m_lightEntities.end());
|
|
||||||
auto& lightEntity = m_lightEntities[entity];
|
|
||||||
lightEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/)
|
|
||||||
{
|
|
||||||
m_invalidatedLightWorldNode.insert(entity);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
lightEntity.onLightAttached.Connect(entityLight.OnLightAttached, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry)
|
lightEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, lightEntity](const Node* /*node*/)
|
||||||
|
{
|
||||||
|
m_invalidatedLightWorldNode.insert(lightEntity);
|
||||||
|
});
|
||||||
|
|
||||||
|
lightEntity->onLightAttached.Connect(entityLight.OnLightAttached, [this, lightEntity](LightComponent* light, std::size_t lightIndex)
|
||||||
{
|
{
|
||||||
if (!light->IsVisible())
|
if (!light->IsVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
|
const auto& lightEntry = light->GetLightEntry(lightIndex);
|
||||||
|
lightEntity->lightIndices[lightIndex] = m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
|
||||||
});
|
});
|
||||||
|
|
||||||
lightEntity.onLightDetach.Connect(entityLight.OnLightDetach, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry)
|
lightEntity->onLightDetach.Connect(entityLight.OnLightDetach, [this, lightEntity](LightComponent* light, std::size_t lightIndex)
|
||||||
{
|
{
|
||||||
if (!light->IsVisible())
|
if (!light->IsVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_pipeline->UnregisterLight(lightEntry.light.get());
|
m_pipeline->UnregisterLight(lightEntity->lightIndices[lightIndex]);
|
||||||
});
|
});
|
||||||
|
|
||||||
lightEntity.onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, entity](LightComponent* /*light*/, bool isVisible)
|
lightEntity->onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, lightEntity](LightComponent* /*light*/, bool isVisible)
|
||||||
{
|
{
|
||||||
if (isVisible)
|
if (isVisible)
|
||||||
{
|
{
|
||||||
m_newlyHiddenLightEntities.erase(entity);
|
m_newlyHiddenLightEntities.erase(lightEntity);
|
||||||
m_newlyVisibleLightEntities.insert(entity);
|
m_newlyVisibleLightEntities.insert(lightEntity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_newlyHiddenLightEntities.insert(entity);
|
m_newlyHiddenLightEntities.insert(lightEntity);
|
||||||
m_newlyVisibleLightEntities.erase(entity);
|
m_newlyVisibleLightEntities.erase(lightEntity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_invalidatedLightWorldNode.insert(lightEntity);
|
||||||
|
|
||||||
|
if (entityLight.IsVisible())
|
||||||
|
{
|
||||||
|
for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex)
|
||||||
|
{
|
||||||
|
const auto& lightEntry = entityLight.GetLightEntry(lightIndex);
|
||||||
|
if (!lightEntry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lightEntity->lightIndices[lightIndex] = m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_lightEntities.find(entity) == m_lightEntities.end());
|
||||||
|
m_lightEntities.emplace(entity, lightEntity);
|
||||||
});
|
});
|
||||||
|
|
||||||
UpdateVisibility(registry);
|
UpdateVisibility(registry);
|
||||||
|
|
@ -172,45 +220,74 @@ namespace Nz
|
||||||
|
|
||||||
void RenderSystem::OnCameraDestroy(entt::registry& registry, entt::entity entity)
|
void RenderSystem::OnCameraDestroy(entt::registry& registry, entt::entity entity)
|
||||||
{
|
{
|
||||||
m_cameraEntities.erase(entity);
|
auto it = m_cameraEntities.find(entity);
|
||||||
m_invalidatedCameraNode.erase(entity);
|
if (it == m_cameraEntities.end())
|
||||||
|
return;
|
||||||
|
|
||||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
CameraEntity* cameraEntity = it->second;
|
||||||
m_pipeline->UnregisterViewer(&entityCamera);
|
|
||||||
|
m_cameraEntities.erase(it);
|
||||||
|
m_invalidatedCameraNode.erase(cameraEntity);
|
||||||
|
m_pipeline->UnregisterViewer(cameraEntity->viewerIndex);
|
||||||
|
|
||||||
|
m_cameraEntityPool.Free(cameraEntity->poolIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity)
|
void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity)
|
||||||
{
|
{
|
||||||
|
auto it = m_graphicsEntities.find(entity);
|
||||||
|
if (it == m_graphicsEntities.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
GraphicsEntity* graphicsEntity = it->second;
|
||||||
|
|
||||||
m_graphicsEntities.erase(entity);
|
m_graphicsEntities.erase(entity);
|
||||||
m_invalidatedGfxWorldNode.erase(entity);
|
m_invalidatedGfxWorldNode.erase(graphicsEntity);
|
||||||
m_newlyHiddenGfxEntities.erase(entity);
|
m_newlyHiddenGfxEntities.erase(graphicsEntity);
|
||||||
m_newlyVisibleGfxEntities.erase(entity);
|
m_newlyVisibleGfxEntities.erase(graphicsEntity);
|
||||||
|
|
||||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
||||||
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
|
for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex)
|
||||||
for (const auto& renderableEntry : entityGfx.GetRenderables())
|
{
|
||||||
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
|
const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex);
|
||||||
|
if (!renderableEntry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pipeline->UnregisterRenderable(graphicsEntity->renderableIndices[renderableIndex]);
|
||||||
|
}
|
||||||
|
m_pipeline->UnregisterWorldInstance(graphicsEntity->worldInstanceIndex);
|
||||||
|
|
||||||
|
m_graphicsEntityPool.Free(graphicsEntity->poolIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSystem::OnLightDestroy(entt::registry& registry, entt::entity entity)
|
void RenderSystem::OnLightDestroy(entt::registry& registry, entt::entity entity)
|
||||||
{
|
{
|
||||||
|
auto it = m_lightEntities.find(entity);
|
||||||
|
if (it == m_lightEntities.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
LightEntity* lightEntity = it->second;
|
||||||
|
|
||||||
m_lightEntities.erase(entity);
|
m_lightEntities.erase(entity);
|
||||||
m_invalidatedLightWorldNode.erase(entity);
|
m_invalidatedLightWorldNode.erase(lightEntity);
|
||||||
m_newlyHiddenLightEntities.erase(entity);
|
m_newlyHiddenLightEntities.erase(lightEntity);
|
||||||
m_newlyVisibleLightEntities.erase(entity);
|
m_newlyVisibleLightEntities.erase(lightEntity);
|
||||||
|
|
||||||
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
||||||
for (const auto& lightEntry : entityLight.GetLights())
|
for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex)
|
||||||
m_pipeline->UnregisterLight(lightEntry.light.get());
|
{
|
||||||
|
const auto& lightEntry = entityLight.GetLightEntry(lightIndex);
|
||||||
|
if (!lightEntry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pipeline->UnregisterLight(lightEntity->lightIndices[lightIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lightEntityPool.Free(lightEntity->poolIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
|
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
|
||||||
{
|
{
|
||||||
m_newlyHiddenGfxEntities.erase(entity);
|
|
||||||
m_newlyVisibleGfxEntities.erase(entity);
|
|
||||||
m_newlyHiddenLightEntities.erase(entity);
|
|
||||||
m_newlyVisibleLightEntities.erase(entity);
|
|
||||||
|
|
||||||
if (registry.try_get<CameraComponent>(entity))
|
if (registry.try_get<CameraComponent>(entity))
|
||||||
OnCameraDestroy(registry, entity);
|
OnCameraDestroy(registry, entity);
|
||||||
|
|
||||||
|
|
@ -223,8 +300,10 @@ namespace Nz
|
||||||
|
|
||||||
void RenderSystem::UpdateInstances(entt::registry& registry)
|
void RenderSystem::UpdateInstances(entt::registry& registry)
|
||||||
{
|
{
|
||||||
for (entt::entity entity : m_invalidatedCameraNode)
|
for (CameraEntity* cameraEntity : m_invalidatedCameraNode)
|
||||||
{
|
{
|
||||||
|
entt::entity entity = cameraEntity->entity;
|
||||||
|
|
||||||
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
||||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
||||||
|
|
||||||
|
|
@ -234,24 +313,28 @@ namespace Nz
|
||||||
viewerInstance.UpdateEyePosition(cameraPosition);
|
viewerInstance.UpdateEyePosition(cameraPosition);
|
||||||
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(cameraPosition, entityNode.GetRotation(CoordSys::Global)));
|
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(cameraPosition, entityNode.GetRotation(CoordSys::Global)));
|
||||||
|
|
||||||
m_pipeline->InvalidateViewer(&entityCamera);
|
m_pipeline->InvalidateViewer(cameraEntity->viewerIndex);
|
||||||
}
|
}
|
||||||
m_invalidatedCameraNode.clear();
|
m_invalidatedCameraNode.clear();
|
||||||
|
|
||||||
for (entt::entity entity : m_invalidatedGfxWorldNode)
|
for (GraphicsEntity* graphicsEntity : m_invalidatedGfxWorldNode)
|
||||||
{
|
{
|
||||||
|
entt::entity entity = graphicsEntity->entity;
|
||||||
|
|
||||||
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
||||||
GraphicsComponent& entityGraphics = registry.get<GraphicsComponent>(entity);
|
GraphicsComponent& entityGraphics = registry.get<GraphicsComponent>(entity);
|
||||||
|
|
||||||
const WorldInstancePtr& worldInstance = entityGraphics.GetWorldInstance();
|
const WorldInstancePtr& worldInstance = entityGraphics.GetWorldInstance();
|
||||||
worldInstance->UpdateWorldMatrix(entityNode.GetTransformMatrix());
|
worldInstance->UpdateWorldMatrix(entityNode.GetTransformMatrix());
|
||||||
|
|
||||||
m_pipeline->InvalidateWorldInstance(worldInstance.get());
|
m_pipeline->InvalidateWorldInstance(graphicsEntity->worldInstanceIndex);
|
||||||
}
|
}
|
||||||
m_invalidatedGfxWorldNode.clear();
|
m_invalidatedGfxWorldNode.clear();
|
||||||
|
|
||||||
for (entt::entity entity : m_invalidatedLightWorldNode)
|
for (LightEntity* lightEntity : m_invalidatedLightWorldNode)
|
||||||
{
|
{
|
||||||
|
entt::entity entity = lightEntity->entity;
|
||||||
|
|
||||||
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
||||||
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
LightComponent& entityLight = registry.get<LightComponent>(entity);
|
||||||
|
|
||||||
|
|
@ -260,7 +343,12 @@ namespace Nz
|
||||||
const Vector3f& scale = entityNode.GetScale(CoordSys::Global);
|
const Vector3f& scale = entityNode.GetScale(CoordSys::Global);
|
||||||
|
|
||||||
for (const auto& lightEntry : entityLight.GetLights())
|
for (const auto& lightEntry : entityLight.GetLights())
|
||||||
|
{
|
||||||
|
if (!lightEntry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
lightEntry.light->UpdateTransform(position, rotation, scale);
|
lightEntry.light->UpdateTransform(position, rotation, scale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_invalidatedLightWorldNode.clear();
|
m_invalidatedLightWorldNode.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -268,25 +356,69 @@ namespace Nz
|
||||||
void RenderSystem::UpdateVisibility(entt::registry& registry)
|
void RenderSystem::UpdateVisibility(entt::registry& registry)
|
||||||
{
|
{
|
||||||
// Unregister drawable for hidden entities
|
// Unregister drawable for hidden entities
|
||||||
for (entt::entity entity : m_newlyHiddenGfxEntities)
|
for (GraphicsEntity* graphicsEntity : m_newlyHiddenGfxEntities)
|
||||||
{
|
{
|
||||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(graphicsEntity->entity);
|
||||||
|
|
||||||
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
|
for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex)
|
||||||
for (const auto& renderableEntry : entityGfx.GetRenderables())
|
{
|
||||||
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
|
const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex);
|
||||||
|
if (!renderableEntry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pipeline->UnregisterRenderable(graphicsEntity->renderableIndices[renderableIndex]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_newlyHiddenGfxEntities.clear();
|
m_newlyHiddenGfxEntities.clear();
|
||||||
|
|
||||||
// Register drawable for newly visible entities
|
// Register drawable for newly visible entities
|
||||||
for (entt::entity entity : m_newlyVisibleGfxEntities)
|
for (GraphicsEntity* graphicsEntity : m_newlyVisibleGfxEntities)
|
||||||
{
|
{
|
||||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(graphicsEntity->entity);
|
||||||
|
|
||||||
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
|
for (std::size_t renderableIndex = 0; renderableIndex < GraphicsComponent::MaxRenderableCount; ++renderableIndex)
|
||||||
for (const auto& renderableEntry : entityGfx.GetRenderables())
|
{
|
||||||
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
|
const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex);
|
||||||
|
if (!renderableEntry.renderable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_newlyVisibleGfxEntities.clear();
|
m_newlyVisibleGfxEntities.clear();
|
||||||
|
|
||||||
|
// Unregister lights for hidden entities
|
||||||
|
for (LightEntity* lightEntity : m_newlyHiddenLightEntities)
|
||||||
|
{
|
||||||
|
LightComponent& entityLights = registry.get<LightComponent>(lightEntity->entity);
|
||||||
|
|
||||||
|
for (std::size_t lightIndex = 0; lightIndex < LightComponent::MaxLightCount; ++lightIndex)
|
||||||
|
{
|
||||||
|
const auto& lightEntry = entityLights.GetLightEntry(lightIndex);
|
||||||
|
if (!lightEntry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pipeline->UnregisterLight(lightEntity->lightIndices[lightIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_newlyHiddenGfxEntities.clear();
|
||||||
|
|
||||||
|
// Register lights for newly visible entities
|
||||||
|
for (LightEntity* lightEntity : m_newlyVisibleLightEntities)
|
||||||
|
{
|
||||||
|
LightComponent& entityLights = registry.get<LightComponent>(lightEntity->entity);
|
||||||
|
|
||||||
|
for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex)
|
||||||
|
{
|
||||||
|
const auto& lightEntry = entityLights.GetLightEntry(renderableIndex);
|
||||||
|
if (!lightEntry.light)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lightEntity->lightIndices[renderableIndex] = m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_newlyVisibleGfxEntities.clear();
|
||||||
|
|
||||||
|
//FIXME: Handle light visibility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue