Graphics: Implement point-light shadow-mapping

This commit is contained in:
SirLynix 2022-12-03 17:16:30 +01:00 committed by Jérôme Leclercq
parent 6731e07b54
commit f8238a6e6c
17 changed files with 333 additions and 62 deletions

View File

@ -250,17 +250,18 @@ int main()
{
auto& lightNode = registry.emplace<Nz::NodeComponent>(lightEntity3);
lightNode.SetPosition(Nz::Vector3f::Backward() * 2.f);
lightNode.SetRotation(Nz::EulerAnglesf(-45.f, 180.f, 0.f));
//lightNode.SetPosition(Nz::Vector3f::Up() * 4.f);
lightNode.SetPosition(Nz::Vector3f::Down() * 7.5f + Nz::Vector3f::Backward() * 2.5f);
//lightNode.SetRotation(Nz::EulerAnglesf(-45.f, 180.f, 0.f));
lightNode.SetParentJoint(bobEntity, "Spine2");
auto& cameraLight = registry.emplace<Nz::LightComponent>(lightEntity3);
auto& spotLight = cameraLight.AddLight<Nz::SpotLight>(0xFFFFFFFF);
spotLight.UpdateColor(Nz::Color::Blue);
spotLight.UpdateInnerAngle(Nz::DegreeAnglef(15.f));
spotLight.UpdateOuterAngle(Nz::DegreeAnglef(20.f));
spotLight.EnableShadowCasting(true);
auto& pointLight = cameraLight.AddLight<Nz::PointLight>(0xFFFFFFFF);
pointLight.UpdateColor(Nz::Color::Blue);
pointLight.UpdateRadius(3.f);
pointLight.EnableShadowCasting(true);
pointLight.UpdateShadowMapSize(2048);
}
}
@ -521,9 +522,9 @@ int main()
Nz::DebugDrawer& debugDrawer = renderSystem.GetFramePipeline().GetDebugDrawer();
auto& lightNode = registry.get<Nz::NodeComponent>(lightEntity3);
//debugDrawer.DrawLine(lightNode.GetPosition(Nz::CoordSys::Global), lightNode.GetForward() * 10.f, Nz::Color::Blue);
/*Nz::Boxf test = spotLight->GetBoundingVolume().aabb;
debugDrawer.DrawBox(test, Nz::Color::Blue);
debugDrawer.DrawBox(floorBox, Nz::Color::Red);
Nz::Vector3f pos = lightNode.GetPosition(Nz::CoordSys::Global);
debugDrawer.DrawBox(Nz::Boxf(pos.x - 0.05f, pos.y - 0.05f, pos.z - 0.05f, 0.1f, 0.1f, 0.1f), Nz::Color::Blue);
/*debugDrawer.DrawBox(floorBox, Nz::Color::Red);
Nz::Boxf intersection;
if (floorBox.Intersect(test, &intersection))
debugDrawer.DrawBox(intersection, Nz::Color::Green);*/

View File

@ -123,6 +123,7 @@ namespace Nz
bool HasAttachment(const std::vector<FramePass::Input>& inputs, std::size_t attachmentIndex) const;
void RemoveDuplicatePasses();
std::size_t ResolveAttachmentIndex(std::size_t attachmentIndex) const;
void RegisterPassInput(std::size_t passIndex, std::size_t attachmentIndex);
std::size_t RegisterTexture(std::size_t attachmentIndex);
void ReorderPasses();
void TraverseGraph(std::size_t passIndex);

View File

@ -12,6 +12,7 @@
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/FramePassAttachment.hpp>
#include <Nazara/Math/Rect.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <functional>
#include <limits>
#include <optional>
@ -73,6 +74,7 @@ namespace Nz
inline void SetDepthStencilInput(std::size_t attachmentId);
inline void SetDepthStencilOutput(std::size_t attachmentId);
inline void SetExecutionCallback(ExecutionCallback callback);
inline void SetInputLayout(std::size_t inputIndex, TextureLayout layout);
inline void SetReadInput(std::size_t inputIndex, bool doesRead);
FramePass& operator=(const FramePass&) = delete;
@ -89,6 +91,7 @@ namespace Nz
struct Input
{
std::size_t attachmentId;
std::optional<TextureLayout> assumedLayout;
bool doesRead = true;
};

View File

@ -128,6 +128,12 @@ namespace Nz
m_executionCallback = std::move(callback);
}
inline void FramePass::SetInputLayout(std::size_t inputIndex, TextureLayout layout)
{
assert(inputIndex < m_inputs.size());
m_inputs[inputIndex].assumedLayout = layout;
}
inline void FramePass::SetReadInput(std::size_t inputIndex, bool doesRead)
{
assert(inputIndex < m_inputs.size());

View File

@ -70,6 +70,7 @@ namespace Nz
m_position = position;
UpdateBoundingVolume();
OnLightTransformInvalided(this);
}
inline void PointLight::UpdateRadius(float radius)

View File

@ -0,0 +1,64 @@
// 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
#pragma once
#ifndef NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP
#define NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/DepthPipelinePass.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/LightShadowData.hpp>
#include <Nazara/Graphics/ShadowViewer.hpp>
#include <array>
namespace Nz
{
class FramePipeline;
class PointLight;
class NAZARA_GRAPHICS_API PointLightShadowData : public LightShadowData
{
public:
PointLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const PointLight& light);
PointLightShadowData(const PointLightShadowData&) = delete;
PointLightShadowData(PointLightShadowData&&) = delete;
~PointLightShadowData() = default;
void PrepareRendering(RenderFrame& renderFrame) override;
void RegisterMaterialInstance(const MaterialInstance& matInstance) override;
void RegisterPassInputs(FramePass& pass) override;
void RegisterToFrameGraph(FrameGraph& frameGraph) override;
const Texture* RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph) const override;
void UnregisterMaterialInstance(const MaterialInstance& matInstance) override;
PointLightShadowData& operator=(const PointLightShadowData&) = delete;
PointLightShadowData& operator=(PointLightShadowData&&) = delete;
private:
NazaraSlot(Light, OnLightShadowMapSettingChange, m_onLightShadowMapSettingChange);
NazaraSlot(Light, OnLightTransformInvalided, m_onLightTransformInvalidated);
struct DirectionData
{
std::optional<DepthPipelinePass> depthPass;
std::size_t attachmentIndex;
ShadowViewer viewer;
};
std::array<DirectionData, 6> m_directions;
std::size_t m_cubeAttachmentIndex;
FramePipeline& m_pipeline;
const PointLight& m_light;
};
}
#include <Nazara/Graphics/PointLightShadowData.inl>
#endif // NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP

View File

@ -0,0 +1,12 @@
// 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/PointLightShadowData.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -16,7 +16,7 @@ namespace Nz
class NAZARA_GRAPHICS_API ShadowViewer : public AbstractViewer
{
public:
inline ShadowViewer(const Recti& viewport, UInt32 renderMask);
ShadowViewer() = default;
ShadowViewer(const ShadowViewer&) = delete;
ShadowViewer(ShadowViewer&&) = delete;
~ShadowViewer() = default;

View File

@ -7,12 +7,6 @@
namespace Nz
{
inline ShadowViewer::ShadowViewer(const Recti& viewport, UInt32 renderMask) :
m_renderMask(renderMask)
{
UpdateViewport(viewport);
}
inline void ShadowViewer::UpdateRenderMask(UInt32 renderMask)
{
m_renderMask = renderMask;

View File

@ -97,7 +97,7 @@ namespace Nz::GL
const Context& context = EnsureDeviceContext();
if (context.glObjectLabel)
context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
context.glObjectLabel(ObjectType, m_objectId, SafeCast<GLsizei>(name.size()), name.data());
}
}

View File

@ -712,9 +712,13 @@ namespace Nz
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId);
TextureLayout& textureLayout = textureLayouts[textureId];
assert(textureLayouts[textureId] != TextureLayout::Undefined);
textureLayout = TextureLayout::ColorInput;
if (!input.assumedLayout)
{
assert(textureLayouts[textureId] != TextureLayout::Undefined);
textureLayout = TextureLayout::ColorInput;
}
else
textureLayout = *input.assumedLayout;
};
auto RegisterColorOutput = [&](const FramePass::Output& output, bool shouldLoad)
@ -949,7 +953,21 @@ namespace Nz
return false;
}
void FrameGraph::RegisterPassInput(std::size_t passIndex, std::size_t attachmentIndex)
{
auto it = m_pending.attachmentWriteList.find(attachmentIndex);
if (it != m_pending.attachmentWriteList.end())
{
const PassList& dependencyPassList = it->second;
for (std::size_t dependencyPass : dependencyPassList)
{
if (dependencyPass != passIndex)
TraverseGraph(dependencyPass);
}
}
}
std::size_t FrameGraph::RegisterTexture(std::size_t attachmentIndex)
{
if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it != m_pending.attachmentToTextures.end())
@ -1126,31 +1144,9 @@ namespace Nz
const FramePass& framePass = m_framePasses[passIndex];
for (const auto& input : framePass.GetInputs())
{
auto it = m_pending.attachmentWriteList.find(input.attachmentId);
if (it != m_pending.attachmentWriteList.end())
{
const PassList& dependencyPassList = it->second;
for (std::size_t dependencyPass : dependencyPassList)
{
if (dependencyPass != passIndex)
TraverseGraph(dependencyPass);
}
}
}
RegisterPassInput(passIndex, input.attachmentId);
if (std::size_t dsInput = framePass.GetDepthStencilInput(); dsInput != FramePass::InvalidAttachmentId)
{
auto it = m_pending.attachmentWriteList.find(dsInput);
if (it != m_pending.attachmentWriteList.end())
{
const PassList& dependencyPassList = it->second;
for (std::size_t dependencyPass : dependencyPassList)
{
if (dependencyPass != passIndex)
TraverseGraph(dependencyPass);
}
}
}
RegisterPassInput(passIndex, dsInput);
}
}

View File

@ -5,6 +5,7 @@
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/PointLightShadowData.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
@ -26,13 +27,14 @@ namespace Nz
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r, m_color.g, m_color.b, m_color.a);
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<Vector2f&>(data, lightOffset.lightMemberOffsets.shadowMapSize) = Vector2f(-1.f, -1.f);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, 0.f);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_radius, m_invRadius, 0.f, 0.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.shadowMapSize) = (IsShadowCaster()) ? Vector2f(1.f / GetShadowMapSize()) : Vector2f(-1.f, -1.f);
}
std::unique_ptr<LightShadowData> PointLight::InstanciateShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry) const
{
return nullptr; //< TODO
return std::make_unique<PointLightShadowData>(pipeline, elementRegistry, *this);
}
void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/)

View File

@ -0,0 +1,150 @@
// 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/PointLightShadowData.hpp>
#include <Nazara/Graphics/BakedFrameGraph.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
namespace
{
// TODO: Make it constexpr
std::array s_dirRotations = {
Quaternionf::RotationBetween(Vector3f::Forward(), Vector3f::UnitX()),
Quaternionf::RotationBetween(Vector3f::Forward(), -Vector3f::UnitX()),
Quaternionf::RotationBetween(Vector3f::Forward(), Vector3f::UnitY()),
Quaternionf::RotationBetween(Vector3f::Forward(), -Vector3f::UnitY()),
Quaternionf::Identity(),
Quaternionf(0.f, 0.f, 1.f, 0.f)
};
constexpr std::array<std::string_view, 6> s_dirNames = {
"Point-light shadow mapping +X",
"Point-light shadow mapping -X",
"Point-light shadow mapping +Y",
"Point-light shadow mapping -Y",
"Point-light shadow mapping +Z",
"Point-light shadow mapping -Z"
};
}
PointLightShadowData::PointLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const PointLight& light) :
m_pipeline(pipeline),
m_light(light)
{
m_onLightShadowMapSettingChange.Connect(m_light.OnLightShadowMapSettingChange, [this](Light* /*light*/, PixelFormat /*newPixelFormat*/, UInt32 newSize)
{
for (DirectionData& direction : m_directions)
direction.viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(newSize), SafeCast<int>(newSize)));
});
m_onLightTransformInvalidated.Connect(m_light.OnLightTransformInvalided, [this]([[maybe_unused]] Light* light)
{
assert(&m_light == light);
for (std::size_t i = 0; i < m_directions.size(); ++i)
{
DirectionData& direction = m_directions[i];
ViewerInstance& viewerInstance = direction.viewer.GetViewerInstance();
viewerInstance.UpdateEyePosition(m_light.GetPosition());
viewerInstance.UpdateViewMatrix(Matrix4f::TransformInverse(m_light.GetPosition(), s_dirRotations[i]));
m_pipeline.QueueTransfer(&viewerInstance);
}
});
std::size_t shadowPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("ShadowPass");
UInt32 shadowMapSize = light.GetShadowMapSize();
for (std::size_t i = 0; i < m_directions.size(); ++i)
{
ShadowViewer& viewer = m_directions[i].viewer;
viewer.UpdateRenderMask(0xFFFFFFFF);
viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
ViewerInstance& viewerInstance = viewer.GetViewerInstance();
viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(RadianAnglef(HalfPi<float>), 1.f, 0.01f, m_light.GetRadius()));
viewerInstance.UpdateEyePosition(m_light.GetPosition());
viewerInstance.UpdateViewMatrix(Matrix4f::TransformInverse(m_light.GetPosition(), s_dirRotations[i]));
m_pipeline.QueueTransfer(&viewerInstance);
m_directions[i].depthPass.emplace(m_pipeline, elementRegistry, &viewer, shadowPassIndex, std::string(s_dirNames[i]));
}
m_pipeline.ForEachRegisteredMaterialInstance([this](const MaterialInstance& matInstance)
{
for (DirectionData& direction : m_directions)
direction.depthPass->RegisterMaterialInstance(matInstance);
});
}
void PointLightShadowData::PrepareRendering(RenderFrame& renderFrame)
{
for (DirectionData& direction : m_directions)
{
const Matrix4f& viewProjMatrix = direction.viewer.GetViewerInstance().GetViewProjMatrix();
Frustumf frustum = Frustumf::Extract(viewProjMatrix);
std::size_t visibilityHash = 5U;
const auto& visibleRenderables = m_pipeline.FrustumCull(frustum, 0xFFFFFFFF, visibilityHash);
direction.depthPass->Prepare(renderFrame, frustum, visibleRenderables, visibilityHash);
}
}
void PointLightShadowData::RegisterMaterialInstance(const MaterialInstance& matInstance)
{
for (DirectionData& direction : m_directions)
direction.depthPass->RegisterMaterialInstance(matInstance);
}
void PointLightShadowData::RegisterPassInputs(FramePass& pass)
{
std::size_t cubeInputIndex = pass.AddInput(m_cubeAttachmentIndex);
pass.SetInputLayout(cubeInputIndex, TextureLayout::ColorInput);
for (DirectionData& direction : m_directions)
pass.AddInput(direction.attachmentIndex);
}
void PointLightShadowData::RegisterToFrameGraph(FrameGraph& frameGraph)
{
UInt32 shadowMapSize = m_light.GetShadowMapSize();
m_cubeAttachmentIndex = frameGraph.AddAttachmentCube({
"Point-light shadowmap",
m_light.GetShadowMapFormat(),
FramePassAttachmentSize::Fixed,
shadowMapSize, shadowMapSize,
});
for (std::size_t i = 0; i < m_directions.size(); ++i)
{
DirectionData& direction = m_directions[i];
direction.attachmentIndex = frameGraph.AddAttachmentCubeFace(m_cubeAttachmentIndex, static_cast<CubemapFace>(i));
direction.depthPass->RegisterToFrameGraph(frameGraph, direction.attachmentIndex);
}
}
const Texture* PointLightShadowData::RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph) const
{
return bakedGraph.GetAttachmentTexture(m_cubeAttachmentIndex).get();
}
void PointLightShadowData::UnregisterMaterialInstance(const MaterialInstance& matInstance)
{
for (DirectionData& direction : m_directions)
direction.depthPass->UnregisterMaterialInstance(matInstance);
}
}

View File

@ -98,7 +98,7 @@ external
[tag("SkeletalData")] skeletalData: uniform[SkeletalData],
[tag("LightData")] lightData: uniform[LightData],
[tag("ShadowMaps2D")] shadowMaps2D: array[depth_sampler2D[f32], MaxLightCount],
[tag("ShadowMapsCube")] shadowMapsCube: array[depth_sampler_cube[f32], MaxLightCount]
[tag("ShadowMapsCube")] shadowMapsCube: array[sampler_cube[f32], MaxLightCount]
}
struct VertToFrag
@ -118,6 +118,11 @@ struct FragOut
[location(0)] RenderTarget0: vec4[f32]
}
fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32
{
return zNear * zFar / (zFar + depth * (zNear - zFar));
}
[entry(frag), cond(!DepthPass || AlphaTest)]
fn main(input: VertToFrag) -> FragOut
{
@ -189,25 +194,60 @@ fn main(input: VertToFrag) -> FragOut
else if (light.type == PointLight)
{
let lightPos = light.parameter1.xyz;
let lightInvRadius = light.parameter1.w;
let lightRadius = light.parameter2.x;
let lightInvRadius = light.parameter2.y;
let lightToPos = input.worldPos - lightPos;
let dist = length(lightToPos);
let lightToPosNorm = lightToPos / max(dist, 0.0001);
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
let reflection = reflect(lightToPosNorm, normal);
let specFactor = max(dot(reflection, eyeVec), 0.0);
specFactor = pow(specFactor, settings.Shininess);
lightSpecular += attenuationFactor * specFactor * light.color.rgb;
let shadowFactor = 1.0;
if (light.invShadowMapSize.x > 0.0)
{
shadowFactor = 0.0;
let sampleDir = vec3[f32](lightToPosNorm.x, lightToPosNorm.y, -lightToPosNorm.z);
const sampleCount = 4;
const offset = 0.005;
const bias = 0.05;
const invSampleCount = 1.0 / f32(sampleCount);
const start = vec3[f32](offset * 0.5, offset * 0.5, offset * 0.5);
const shadowContribution = 1.0 / f32(sampleCount * sampleCount * sampleCount);
[unroll]
for x in 0 -> sampleCount
{
[unroll]
for y in 0 -> sampleCount
{
[unroll]
for z in 0 -> sampleCount
{
let dirOffset = vec3[f32](f32(x), f32(y), f32(z)) * invSampleCount * offset - start;
let sampleDir = sampleDir + dirOffset;
let depth = shadowMapsCube[i].Sample(sampleDir).r;
depth = LinearizeDepth(depth, 0.01, lightRadius);
if (depth > dist - bias)
shadowFactor += shadowContribution;
}
}
}
}
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb;
}
else if (light.type == SpotLight)
{
@ -233,10 +273,11 @@ fn main(input: VertToFrag) -> FragOut
let specFactor = max(dot(reflection, eyeVec), 0.0);
specFactor = pow(specFactor, settings.Shininess);
let shadowFactor = 0.0;
let shadowFactor = 1.0;
if (light.invShadowMapSize.x > 0.0)
{
let shadowCoords = input.lightProjPos[i].xyz / input.lightProjPos[i].w;
shadowFactor = 0.0;
[unroll]
for x in -1 -> 2
{

View File

@ -14,10 +14,10 @@ namespace Nz
{
SpotLightShadowData::SpotLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const SpotLight& light) :
m_pipeline(pipeline),
m_light(light),
m_viewer(Recti(0, 0, 1, 1), 0xFFFFFFFF)
m_light(light)
{
UInt32 shadowMapSize = light.GetShadowMapSize();
m_viewer.UpdateRenderMask(0xFFFFFFFF);
m_viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
ViewerInstance& viewerInstance = m_viewer.GetViewerInstance();

View File

@ -198,7 +198,7 @@ namespace Nz
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBindings {
SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex]
SafeCast<UInt32>(renderState.shadowMapsCube.size()), &m_textureBindingCache[textureBindingBaseIndex]
};
}

View File

@ -128,7 +128,7 @@ namespace Nz
}
}
void OpenGLShaderBinding::UpdateDebugName(std::string_view name)
void OpenGLShaderBinding::UpdateDebugName(std::string_view /*name*/)
{
// No OpenGL object to name
}