Add light support (WIP)

This commit is contained in:
Jérôme Leclercq
2022-02-02 12:55:39 +01:00
parent e6951d54a5
commit 8a3a8547dc
44 changed files with 1700 additions and 253 deletions

View File

@@ -224,7 +224,7 @@ namespace Nz
UInt32 channelCount = 0;
UInt64 frameCount = 0;
UInt64 sampleCount = 0;
UInt64 sampleRate = 0;
UInt32 sampleRate = 0;
ud.metadataCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__StreamMetadata* meta)
{

View File

@@ -0,0 +1,10 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Components/LightComponent.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <limits>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float DirectionalLight::ComputeContributionScore(const BoundingVolumef& /*boundingVolume*/) const
{
return -std::numeric_limits<float>::infinity();
}
void DirectionalLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Directional);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void DirectionalLight::UpdateTransform(const Vector3f& /*position*/, const Quaternionf& rotation, const Vector3f& /*scale*/)
{
UpdateRotation(rotation);
}
}

View File

@@ -9,7 +9,11 @@ namespace Nz
{
ElementRenderer::~ElementRenderer() = default;
void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const RenderStates& /*renderStates*/, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, std::size_t /*elementCount*/, const Pointer<const RenderElement>* /*elements*/, const RenderStates* /*renderStates*/)
{
}
void ElementRenderer::PrepareEnd(RenderFrame& /*currentFrame*/, ElementRendererData& /*rendererData*/)
{
}

View File

@@ -9,6 +9,7 @@
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
@@ -37,37 +38,6 @@ namespace Nz
m_elementRenderers.resize(BasicRenderElementCount);
m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique<SpriteChainRenderer>(*Graphics::Instance()->GetRenderDevice());
m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique<SubmeshRenderer>();
auto lightOffset = PredefinedLightData::GetOffsets();
m_lightDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, lightOffset.totalSize, BufferUsage::DeviceLocal | BufferUsage::Write);
std::vector<UInt8> staticLightData(lightOffset.totalSize);
/*AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightCountOffset) = 1;
AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 0;
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f);
AccessByOffset<Vector2f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f);
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, -1.f, 1.f);
AccessByOffset<UInt8&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/
AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightCountOffset) = 1;
AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 1;
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f);
AccessByOffset<Vector2f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f);
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f);
AccessByOffset<UInt8&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
/*AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightCountOffset) = 1;
AccessByOffset<UInt32&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 2;
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f);
AccessByOffset<Vector2f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f);
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f);
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter2) = Vector4f(0.f, 0.f, -1.f, 0.f);
AccessByOffset<Vector4f&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter3) = Vector4f(DegreeAnglef(15.f).GetCos(), DegreeAnglef(20.f).GetCos(), 0.f, 0.f);
AccessByOffset<UInt8&>(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/
if (!m_lightDataBuffer->Fill(staticLightData.data(), 0, staticLightData.size()))
throw std::runtime_error("failed to fill light data buffer");
}
void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance)
@@ -159,6 +129,21 @@ namespace Nz
}
}
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, [this](Light*)
{
for (auto&& [viewer, viewerData] : m_viewers)
{
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
});
}
void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
{
auto& viewerData = m_viewers.emplace(viewerInstance, ViewerData{}).first->second;
@@ -226,6 +211,9 @@ namespace Nz
return currentHash * 23 + newHash;
};
PredefinedLightData lightOffsets = PredefinedLightData::GetOffsets();
std::size_t lightUboAlignedSize = Align(lightOffsets.totalSize, graphics->GetRenderDevice()->GetDeviceInfo().limits.minUniformBufferOffsetAlignment);
// Render queues handling
for (auto&& [viewer, data] : m_viewers)
{
@@ -307,12 +295,104 @@ namespace Nz
{
renderFrame.PushForRelease(std::move(viewerData.forwardRenderElements));
viewerData.forwardRenderElements.clear();
for (const auto& renderableData : m_visibleRenderables)
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements);
viewerData.forwardRegistry.Clear();
viewerData.forwardRenderQueue.Clear();
viewerData.lightBufferPerLights.clear();
viewerData.lightPerRenderElement.clear();
for (auto& lightDataUbo : m_lightDataBuffers)
{
lightDataUbo.allocation = nullptr;
lightDataUbo.offset = 0;
}
for (const auto& renderableData : m_visibleRenderables)
{
BoundingVolumef renderableBoundingVolume(renderableData.instancedRenderable->GetAABB());
renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix());
// Select lights (TODO: Cull lights in frustum)
m_visibleLights.clear();
for (auto&& [light, lightData] : m_lights)
{
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
if ((renderMask & lightData.renderMask) && boundingVolume.Intersect(renderableBoundingVolume.aabb))
m_visibleLights.push_back(light);
}
// Sort lights
std::sort(m_visibleLights.begin(), m_visibleLights.end(), [&](Light* lhs, Light* rhs)
{
return lhs->ComputeContributionScore(renderableBoundingVolume) < rhs->ComputeContributionScore(renderableBoundingVolume);
});
std::size_t lightCount = std::min(m_visibleLights.size(), MaxLightCountPerDraw);
LightKey lightKey;
lightKey.fill(nullptr);
for (std::size_t i = 0; i < lightCount; ++i)
lightKey[i] = m_visibleLights[i];
RenderBufferView lightUboView;
auto it = viewerData.lightBufferPerLights.find(lightKey);
if (it == viewerData.lightBufferPerLights.end())
{
// Prepare light ubo upload
// Find light ubo
LightDataUbo* targetLightData = nullptr;
for (auto& lightUboData : m_lightDataBuffers)
{
if (lightUboData.offset + lightUboAlignedSize <= lightUboData.renderBuffer->GetSize())
{
targetLightData = &lightUboData;
break;
}
}
if (!targetLightData)
{
// Allocate a new light UBO
auto& lightUboData = m_lightDataBuffers.emplace_back();
lightUboData.renderBuffer = graphics->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, 256 * lightUboAlignedSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
targetLightData = &lightUboData;
}
assert(targetLightData);
if (!targetLightData->allocation)
targetLightData->allocation = &uploadPool.Allocate(targetLightData->renderBuffer->GetSize());
void* lightDataPtr = static_cast<UInt8*>(targetLightData->allocation->mappedPtr) + targetLightData->offset;
AccessByOffset<UInt32&>(lightDataPtr, lightOffsets.lightCountOffset) = SafeCast<UInt32>(lightCount);
UInt8* lightPtr = static_cast<UInt8*>(lightDataPtr) + lightOffsets.lightsOffset;
for (std::size_t i = 0; i < lightCount; ++i)
{
m_visibleLights[i]->FillLightData(lightPtr);
lightPtr += lightOffsets.lightSize;
}
// Associate render element with light ubo
lightUboView = RenderBufferView(targetLightData->renderBuffer.get(), targetLightData->offset, lightUboAlignedSize);
targetLightData->offset += lightUboAlignedSize;
viewerData.lightBufferPerLights.emplace(lightKey, lightUboView);
}
else
lightUboView = it->second;
std::size_t previousCount = viewerData.forwardRenderElements.size();
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements);
for (std::size_t i = previousCount; i < viewerData.forwardRenderElements.size(); ++i)
{
const RenderElement* element = viewerData.forwardRenderElements[i].get();
viewerData.lightPerRenderElement.emplace(element, lightUboView);
}
}
for (const auto& renderElement : viewerData.forwardRenderElements)
{
renderElement->Register(viewerData.forwardRegistry);
@@ -320,6 +400,25 @@ namespace Nz
}
viewerData.forwardRegistry.Finalize();
renderFrame.Execute([&](CommandBufferBuilder& builder)
{
builder.BeginDebugRegion("Light UBO Update", Color::Yellow);
{
builder.PreTransferBarrier();
for (auto& lightUboData : m_lightDataBuffers)
{
if (!lightUboData.allocation)
continue;
builder.CopyBuffer(*lightUboData.allocation, RenderBufferView(lightUboData.renderBuffer.get(), 0, lightUboData.offset));
}
builder.PostTransferBarrier();
}
builder.EndDebugRegion();
}, QueueType::Transfer);
}
viewerData.forwardRenderQueue.Sort([&](const RenderElement* element)
@@ -353,20 +452,41 @@ namespace Nz
const auto& viewerInstance = viewer->GetViewerInstance();
ElementRenderer::RenderStates renderStates;
renderStates.lightData = m_lightDataBuffer;
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount);
m_renderStates.clear();
m_renderStates.resize(elementCount);
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
for (std::size_t i = 0; i < m_elementRenderers.size(); ++i)
m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]);
auto& lightPerRenderElement = viewerData.lightPerRenderElement;
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount);
m_renderStates.clear();
m_renderStates.reserve(elementCount);
for (std::size_t i = 0; i < elementCount; ++i)
{
auto it = lightPerRenderElement.find(elements[i]);
assert(it != lightPerRenderElement.end());
auto& renderStates = m_renderStates.emplace_back();
renderStates.lightData = it->second;
}
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
for (std::size_t i = 0; i < m_elementRenderers.size(); ++i)
m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]);
}
if (m_bakedFrameGraph.Resize(renderFrame))
@@ -493,6 +613,17 @@ namespace Nz
}
}
void ForwardFramePipeline::UnregisterLight(Light* light)
{
m_lights.erase(light);
for (auto&& [viewer, viewerData] : m_viewers)
{
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
}
void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance)
{
m_viewers.erase(viewerInstance);
@@ -544,7 +675,7 @@ namespace Nz
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elements, elementCount);
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements);
});
});
@@ -576,7 +707,7 @@ namespace Nz
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Render(viewerInstance , *viewerData.elementRendererData[elementType], builder, elements, elementCount);
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements);
});
});
}

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
Light::~Light() = default;
}

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float PointLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const
{
// TODO: take luminosity/radius into account
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
}
void PointLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/)
{
UpdatePosition(position);
}
}

View File

@@ -72,7 +72,7 @@ struct Light
struct LightData
{
lights: array[Light, MaxLightCount],
lightCount: u32
lightCount: u32,
}
[layout(std140)]
@@ -250,7 +250,7 @@ fn main(input: VertToFrag) -> FragOut
else
{
let output: FragOut;
output.RenderTarget0 = diffuseColor.w;
output.RenderTarget0 = diffuseColor;
return output;
}
}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float SpotLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const
{
// TODO: take luminosity/radius/direction into account
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
}
void SpotLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Spot);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter3) = Vector4f(m_innerAngleCos, m_outerAngleCos, 0.f, 0.f);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void SpotLight::UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& /*scale*/)
{
UpdatePosition(position);
UpdateRotation(rotation);
}
}

View File

@@ -9,6 +9,7 @@
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <iostream>
#include <utility>
#include <Nazara/Graphics/Debug.hpp>
@@ -49,7 +50,7 @@ namespace Nz
return std::make_unique<SpriteChainRendererData>();
}
void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer<const RenderElement>* elements, std::size_t elementCount)
void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates)
{
Graphics* graphics = Graphics::Instance();
@@ -57,103 +58,65 @@ namespace Nz
Recti invalidScissorBox(-1, -1, -1, -1);
std::size_t firstQuadIndex = 0;
SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
UploadPool::Allocation* currentAllocation = nullptr;
UInt8* currentAllocationMemPtr = nullptr;
const VertexDeclaration* currentVertexDeclaration = nullptr;
RenderBuffer* currentVertexBuffer = nullptr;
const MaterialPass* currentMaterialPass = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentShaderBinding = nullptr;
const Texture* currentTextureOverlay = nullptr;
const WorldInstance* currentWorldInstance = nullptr;
Recti currentScissorBox = invalidScissorBox;
auto FlushDrawCall = [&]()
{
currentDrawCall = nullptr;
};
auto FlushDrawData = [&]()
{
FlushDrawCall();
currentShaderBinding = nullptr;
};
auto Flush = [&]()
{
// changing vertex buffer always mean we have to switch draw calls
FlushDrawCall();
if (currentAllocation)
{
std::size_t size = currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr);
m_pendingCopies.emplace_back(BufferCopy{
currentVertexBuffer,
currentAllocation,
size
});
firstQuadIndex = 0;
currentAllocation = nullptr;
currentVertexBuffer = nullptr;
}
};
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
std::size_t oldDrawCallCount = data.drawCalls.size();
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
for (std::size_t i = 0; i < elementCount; ++i)
{
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain));
const RenderSpriteChain& spriteChain = static_cast<const RenderSpriteChain&>(*elements[i]);
const RenderStates& renderState = renderStates[i];
const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration();
std::size_t stride = vertexDeclaration->GetStride();
if (currentVertexDeclaration != vertexDeclaration)
if (m_pendingData.currentVertexDeclaration != vertexDeclaration)
{
// TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated
// Wait until buffer rewrite
Flush();
currentVertexDeclaration = vertexDeclaration;
m_pendingData.currentVertexDeclaration = vertexDeclaration;
}
if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); currentPipeline != pipeline)
if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); m_pendingData.currentPipeline != pipeline)
{
FlushDrawCall();
currentPipeline = pipeline;
m_pendingData.currentPipeline = pipeline;
}
if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); currentMaterialPass != materialPass)
if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); m_pendingData.currentMaterialPass != materialPass)
{
FlushDrawData();
currentMaterialPass = materialPass;
m_pendingData.currentMaterialPass = materialPass;
}
if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); currentWorldInstance != worldInstance)
if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); m_pendingData.currentWorldInstance != worldInstance)
{
// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
// which is far from being efficient, using some bindless could help (or at least instancing?)
FlushDrawData();
currentWorldInstance = worldInstance;
m_pendingData.currentWorldInstance = worldInstance;
}
if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); currentTextureOverlay != textureOverlay)
if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); m_pendingData.currentTextureOverlay != textureOverlay)
{
FlushDrawData();
currentTextureOverlay = textureOverlay;
m_pendingData.currentTextureOverlay = textureOverlay;
}
if (m_pendingData.currentLightData != renderState.lightData)
{
FlushDrawData();
m_pendingData.currentLightData = renderState.lightData;
}
const Recti& scissorBox = spriteChain.GetScissorBox();
const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox;
if (currentScissorBox != targetScissorBox)
if (m_pendingData.currentScissorBox != targetScissorBox)
{
FlushDrawData();
currentScissorBox = targetScissorBox;
FlushDrawCall();
m_pendingData.currentScissorBox = targetScissorBox;
}
std::size_t remainingQuads = spriteChain.GetSpriteCount();
@@ -161,10 +124,10 @@ namespace Nz
while (remainingQuads > 0)
{
if (!currentAllocation)
if (!m_pendingData.currentAllocation)
{
currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);
m_pendingData.currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
m_pendingData.currentAllocationMemPtr = static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr);
std::shared_ptr<RenderBuffer> vertexBuffer;
@@ -177,12 +140,12 @@ namespace Nz
else
vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex, m_maxVertexBufferSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
currentVertexBuffer = vertexBuffer.get();
m_pendingData.currentVertexBuffer = vertexBuffer.get();
data.vertexBuffers.emplace_back(std::move(vertexBuffer));
}
if (!currentShaderBinding)
if (!m_pendingData.currentShaderBinding)
{
m_bindingCache.clear();
@@ -193,7 +156,7 @@ namespace Nz
const auto& matSettings = materialPass.GetSettings();
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
{
const auto& instanceBuffer = currentWorldInstance->GetInstanceBuffer();
const auto& instanceBuffer = m_pendingData.currentWorldInstance->GetInstanceBuffer();
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
@@ -203,13 +166,13 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && m_pendingData.currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::UniformBufferBinding{
renderStates.lightData.get(),
0, renderStates.lightData->GetSize()
m_pendingData.currentLightData.GetBuffer(),
m_pendingData.currentLightData.GetOffset(), m_pendingData.currentLightData.GetSize()
};
}
@@ -230,33 +193,33 @@ namespace Nz
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBinding{
currentTextureOverlay, defaultSampler.get()
m_pendingData.currentTextureOverlay, defaultSampler.get()
};
}
ShaderBindingPtr drawDataBinding = currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0);
ShaderBindingPtr drawDataBinding = m_pendingData.currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0);
drawDataBinding->Update(m_bindingCache.data(), m_bindingCache.size());
currentShaderBinding = drawDataBinding.get();
m_pendingData.currentShaderBinding = drawDataBinding.get();
data.shaderBindings.emplace_back(std::move(drawDataBinding));
}
if (!currentDrawCall)
if (!m_pendingData.currentDrawCall)
{
data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
currentVertexBuffer,
currentPipeline,
currentShaderBinding,
6 * firstQuadIndex,
m_pendingData.currentVertexBuffer,
m_pendingData.currentPipeline,
m_pendingData.currentShaderBinding,
6 * m_pendingData.firstQuadIndex,
0,
currentScissorBox
m_pendingData.currentScissorBox
});
currentDrawCall = &data.drawCalls.back();
m_pendingData.currentDrawCall = &data.drawCalls.back();
}
std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr));
std::size_t remainingSpace = m_maxVertexBufferSize - (m_pendingData.currentAllocationMemPtr - static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr));
std::size_t maxQuads = remainingSpace / (4 * stride);
if (maxQuads == 0)
{
@@ -267,12 +230,12 @@ namespace Nz
std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads);
std::size_t copiedSize = 4 * copiedQuadCount * stride;
std::memcpy(currentAllocationMemPtr, spriteData, copiedSize);
currentAllocationMemPtr += copiedSize;
std::memcpy(m_pendingData.currentAllocationMemPtr, spriteData, copiedSize);
m_pendingData.currentAllocationMemPtr += copiedSize;
spriteData += copiedSize;
firstQuadIndex += copiedQuadCount;
currentDrawCall->quadCount += copiedQuadCount;
m_pendingData.firstQuadIndex += copiedQuadCount;
m_pendingData.currentDrawCall->quadCount += copiedQuadCount;
remainingQuads -= copiedQuadCount;
// If there's still data to copy, it means buffer is full, flush it
@@ -281,12 +244,16 @@ namespace Nz
}
}
//TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls
Flush();
FlushDrawCall();
const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };
}
void SpriteChainRenderer::PrepareEnd(RenderFrame& currentFrame, ElementRendererData& /*rendererData*/)
{
Flush();
if (!m_pendingCopies.empty())
{
@@ -300,9 +267,11 @@ namespace Nz
m_pendingCopies.clear();
}
m_pendingData = PendingData{};
}
void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t /*elementCount*/)
void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer<const RenderElement>* elements)
{
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
@@ -374,4 +343,37 @@ namespace Nz
data.drawCalls.clear();
}
void SpriteChainRenderer::Flush()
{
// changing vertex buffer always mean we have to switch draw calls
FlushDrawCall();
if (m_pendingData.currentAllocation)
{
std::size_t size = m_pendingData.currentAllocationMemPtr - static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr);
m_pendingCopies.emplace_back(BufferCopy{
m_pendingData.currentVertexBuffer,
m_pendingData.currentAllocation,
size
});
m_pendingData.firstQuadIndex = 0;
m_pendingData.currentAllocation = nullptr;
m_pendingData.currentVertexBuffer = nullptr;
}
}
void SpriteChainRenderer::FlushDrawCall()
{
m_pendingData.currentDrawCall = nullptr;
}
void SpriteChainRenderer::FlushDrawData()
{
FlushDrawCall();
m_pendingData.currentShaderBinding = nullptr;
}
}

View File

@@ -17,7 +17,7 @@ namespace Nz
return std::make_unique<SubmeshRendererData>();
}
void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const RenderStates& renderStates, const Pointer<const RenderElement>* elements, std::size_t elementCount)
void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates)
{
Graphics* graphics = Graphics::Instance();
@@ -32,6 +32,7 @@ namespace Nz
const ShaderBinding* currentShaderBinding = nullptr;
const WorldInstance* currentWorldInstance = nullptr;
Recti currentScissorBox = invalidScissorBox;
RenderBufferView currentLightData;
auto FlushDrawCall = [&]()
{
@@ -48,10 +49,13 @@ namespace Nz
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
std::size_t oldDrawCallCount = data.drawCalls.size();
for (std::size_t i = 0; i < elementCount; ++i)
{
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::Submesh));
const RenderSubmesh& submesh = static_cast<const RenderSubmesh&>(*elements[i]);
const RenderStates& renderState = renderStates[i];
if (const RenderPipeline* pipeline = submesh.GetRenderPipeline(); currentPipeline != pipeline)
{
@@ -85,6 +89,12 @@ namespace Nz
currentWorldInstance = worldInstance;
}
if (currentLightData != renderState.lightData)
{
FlushDrawData();
currentLightData = renderState.lightData;
}
const Recti& scissorBox = submesh.GetScissorBox();
const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox;
if (currentScissorBox != targetScissorBox)
@@ -114,13 +124,13 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::UniformBufferBinding{
renderStates.lightData.get(),
0, renderStates.lightData->GetSize()
currentLightData.GetBuffer(),
currentLightData.GetOffset(), currentLightData.GetSize()
};
}
@@ -154,6 +164,7 @@ namespace Nz
}
auto& drawCall = data.drawCalls.emplace_back();
drawCall.firstIndex = 0;
drawCall.indexBuffer = currentIndexBuffer;
drawCall.indexCount = submesh.GetIndexCount();
drawCall.renderPipeline = currentPipeline;
@@ -161,9 +172,13 @@ namespace Nz
drawCall.shaderBinding = currentShaderBinding;
drawCall.vertexBuffer = currentVertexBuffer;
}
const RenderSubmesh* firstSubmesh = static_cast<const RenderSubmesh*>(elements[0]);
std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
data.drawCallPerElement[firstSubmesh] = SubmeshRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };
}
void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer<const RenderElement>* elements)
{
auto& data = static_cast<SubmeshRendererData&>(rendererData);
@@ -176,8 +191,16 @@ namespace Nz
const ShaderBinding* currentShaderBinding = nullptr;
Recti currentScissorBox(-1, -1, -1, -1);
for (const auto& drawData : data.drawCalls)
const RenderSubmesh* firstSubmesh = static_cast<const RenderSubmesh*>(elements[0]);
auto it = data.drawCallPerElement.find(firstSubmesh);
assert(it != data.drawCallPerElement.end());
const auto& indices = it->second;
for (std::size_t i = 0; i < indices.count; ++i)
{
const auto& drawData = data.drawCalls[indices.start + i];
if (currentPipeline != drawData.renderPipeline)
{
commandBuffer.BindPipeline(*drawData.renderPipeline);
@@ -210,9 +233,9 @@ namespace Nz
}
if (currentIndexBuffer)
commandBuffer.DrawIndexed(SafeCast<UInt32>(drawData.indexCount));
commandBuffer.DrawIndexed(SafeCast<UInt32>(drawData.indexCount), 1U, SafeCast<UInt32>(drawData.firstIndex));
else
commandBuffer.Draw(SafeCast<UInt32>(drawData.indexCount));
commandBuffer.Draw(SafeCast<UInt32>(drawData.indexCount), 1U, SafeCast<UInt32>(drawData.firstIndex));
}
}

View File

@@ -18,10 +18,12 @@ namespace Nz
{
RenderSystem::RenderSystem(entt::registry& registry) :
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_cameraDestroyConnection = registry.on_destroy<CameraComponent>().connect<&RenderSystem::OnCameraDestroy>(this);
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
m_lightDestroyConnection = registry.on_destroy<LightComponent>().connect<&RenderSystem::OnLightDestroy>(this);
m_nodeDestroyConnection = registry.on_destroy<NodeComponent>().connect<&RenderSystem::OnNodeDestroy>(this);
m_pipeline = std::make_unique<ForwardFramePipeline>();
@@ -31,8 +33,10 @@ namespace Nz
{
m_cameraConstructObserver.disconnect();
m_graphicsConstructObserver.disconnect();
m_lightConstructObserver.disconnect();
m_cameraDestroyConnection.release();
m_graphicsDestroyConnection.release();
m_lightDestroyConnection.release();
m_nodeDestroyConnection.release();
}
@@ -67,13 +71,13 @@ namespace Nz
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_invalidatedWorldNode.insert(entity);
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_invalidatedWorldNode.insert(entity);
m_invalidatedGfxWorldNode.insert(entity);
});
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
@@ -98,13 +102,64 @@ namespace Nz
{
if (isVisible)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.insert(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.insert(entity);
}
else
{
m_newlyHiddenEntities.insert(entity);
m_newlyVisibleEntities.erase(entity);
m_newlyHiddenGfxEntities.insert(entity);
m_newlyVisibleGfxEntities.erase(entity);
}
});
});
m_lightConstructObserver.each([&](entt::entity entity)
{
LightComponent& entityLight = registry.get<LightComponent>(entity);
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
if (entityLight.IsVisible())
{
for (const auto& lightEntry : entityLight.GetLights())
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)
{
if (!light->IsVisible())
return;
m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
});
lightEntity.onLightDetach.Connect(entityLight.OnLightDetach, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry)
{
if (!light->IsVisible())
return;
m_pipeline->UnregisterLight(lightEntry.light.get());
});
lightEntity.onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, entity](LightComponent* /*light*/, bool isVisible)
{
if (isVisible)
{
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.insert(entity);
}
else
{
m_newlyHiddenLightEntities.insert(entity);
m_newlyVisibleLightEntities.erase(entity);
}
});
});
@@ -127,9 +182,22 @@ namespace Nz
void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity)
{
m_graphicsEntities.erase(entity);
m_invalidatedWorldNode.erase(entity);
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
m_invalidatedGfxWorldNode.erase(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}
void RenderSystem::OnLightDestroy(entt::registry& registry, entt::entity entity)
{
m_lightEntities.erase(entity);
m_invalidatedLightWorldNode.erase(entity);
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
@@ -139,14 +207,19 @@ namespace Nz
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.erase(entity);
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.erase(entity);
if (registry.try_get<CameraComponent>(entity))
OnCameraDestroy(registry, entity);
if (registry.try_get<GraphicsComponent>(entity))
OnGraphicsDestroy(registry, entity);
if (registry.try_get<LightComponent>(entity))
OnLightDestroy(registry, entity);
}
void RenderSystem::UpdateInstances(entt::registry& registry)
@@ -166,7 +239,7 @@ namespace Nz
}
m_invalidatedCameraNode.clear();
for (entt::entity entity : m_invalidatedWorldNode)
for (entt::entity entity : m_invalidatedGfxWorldNode)
{
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
GraphicsComponent& entityGraphics = registry.get<GraphicsComponent>(entity);
@@ -176,13 +249,27 @@ namespace Nz
m_pipeline->InvalidateWorldInstance(worldInstance.get());
}
m_invalidatedWorldNode.clear();
m_invalidatedGfxWorldNode.clear();
for (entt::entity entity : m_invalidatedLightWorldNode)
{
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
LightComponent& entityLight = registry.get<LightComponent>(entity);
const Vector3f& position = entityNode.GetPosition(CoordSys::Global);
const Quaternionf& rotation = entityNode.GetRotation(CoordSys::Global);
const Vector3f& scale = entityNode.GetScale(CoordSys::Global);
for (const auto& lightEntry : entityLight.GetLights())
lightEntry.light->UpdateTransform(position, rotation, scale);
}
m_invalidatedLightWorldNode.clear();
}
void RenderSystem::UpdateVisibility(entt::registry& registry)
{
// Unregister drawables for hidden entities
for (entt::entity entity : m_newlyHiddenEntities)
// Unregister drawable for hidden entities
for (entt::entity entity : m_newlyHiddenGfxEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
@@ -190,10 +277,10 @@ namespace Nz
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}
m_newlyHiddenEntities.clear();
m_newlyHiddenGfxEntities.clear();
// Register drawables for newly visible entities
for (entt::entity entity : m_newlyVisibleEntities)
// Register drawable for newly visible entities
for (entt::entity entity : m_newlyVisibleGfxEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
@@ -201,6 +288,6 @@ namespace Nz
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_newlyVisibleEntities.clear();
m_newlyVisibleGfxEntities.clear();
}
}

View File

@@ -42,7 +42,7 @@ namespace Nz
NazaraAssert(handle != InvalidHandle, "Invalid handle");
IpAddressImpl::SockAddrBuffer nameBuffer;
std::fill(nameBuffer.begin(), nameBuffer.end(), 0);
nameBuffer.fill(0);
int bufferLength = static_cast<int>(nameBuffer.size());

View File

@@ -665,7 +665,7 @@ namespace Nz
*vertexCount = xVertexCount*2 + yVertexCount*2 + zVertexCount*2;
}
UInt64 ComputeCacheMissCount(IndexIterator indices, std::size_t indexCount)
UInt64 ComputeCacheMissCount(IndexIterator indices, UInt32 indexCount)
{
VertexCache cache(indices, indexCount);
return cache.GetMissCount();