From f8238a6e6c23a66b86e1f2ec72c60d7bb4f6bada Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sat, 3 Dec 2022 17:16:30 +0100 Subject: [PATCH] Graphics: Implement point-light shadow-mapping --- examples/Showcase/main.cpp | 21 +-- include/Nazara/Graphics/FrameGraph.hpp | 1 + include/Nazara/Graphics/FramePass.hpp | 3 + include/Nazara/Graphics/FramePass.inl | 6 + include/Nazara/Graphics/PointLight.inl | 1 + .../Nazara/Graphics/PointLightShadowData.hpp | 64 ++++++++ .../Nazara/Graphics/PointLightShadowData.inl | 12 ++ include/Nazara/Graphics/ShadowViewer.hpp | 2 +- include/Nazara/Graphics/ShadowViewer.inl | 6 - .../OpenGLRenderer/Wrapper/DeviceObject.inl | 2 +- src/Nazara/Graphics/FrameGraph.cpp | 52 +++--- src/Nazara/Graphics/PointLight.cpp | 8 +- src/Nazara/Graphics/PointLightShadowData.cpp | 150 ++++++++++++++++++ .../Resources/Shaders/PhongMaterial.nzsl | 59 +++++-- src/Nazara/Graphics/SpotLightShadowData.cpp | 4 +- src/Nazara/Graphics/SubmeshRenderer.cpp | 2 +- .../OpenGLRenderer/OpenGLShaderBinding.cpp | 2 +- 17 files changed, 333 insertions(+), 62 deletions(-) create mode 100644 include/Nazara/Graphics/PointLightShadowData.hpp create mode 100644 include/Nazara/Graphics/PointLightShadowData.inl create mode 100644 src/Nazara/Graphics/PointLightShadowData.cpp diff --git a/examples/Showcase/main.cpp b/examples/Showcase/main.cpp index ccf85acae..1a577533e 100644 --- a/examples/Showcase/main.cpp +++ b/examples/Showcase/main.cpp @@ -250,17 +250,18 @@ int main() { auto& lightNode = registry.emplace(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(lightEntity3); - auto& spotLight = cameraLight.AddLight(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(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(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);*/ diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp index 74946b4e6..6c1914b5f 100644 --- a/include/Nazara/Graphics/FrameGraph.hpp +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -123,6 +123,7 @@ namespace Nz bool HasAttachment(const std::vector& 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); diff --git a/include/Nazara/Graphics/FramePass.hpp b/include/Nazara/Graphics/FramePass.hpp index 7e9db3101..9f494971b 100644 --- a/include/Nazara/Graphics/FramePass.hpp +++ b/include/Nazara/Graphics/FramePass.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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 assumedLayout; bool doesRead = true; }; diff --git a/include/Nazara/Graphics/FramePass.inl b/include/Nazara/Graphics/FramePass.inl index f36d36691..e4c5e98e8 100644 --- a/include/Nazara/Graphics/FramePass.inl +++ b/include/Nazara/Graphics/FramePass.inl @@ -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()); diff --git a/include/Nazara/Graphics/PointLight.inl b/include/Nazara/Graphics/PointLight.inl index 240a7edc6..07f64e9d9 100644 --- a/include/Nazara/Graphics/PointLight.inl +++ b/include/Nazara/Graphics/PointLight.inl @@ -70,6 +70,7 @@ namespace Nz m_position = position; UpdateBoundingVolume(); + OnLightTransformInvalided(this); } inline void PointLight::UpdateRadius(float radius) diff --git a/include/Nazara/Graphics/PointLightShadowData.hpp b/include/Nazara/Graphics/PointLightShadowData.hpp new file mode 100644 index 000000000..313bd730f --- /dev/null +++ b/include/Nazara/Graphics/PointLightShadowData.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +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 depthPass; + std::size_t attachmentIndex; + ShadowViewer viewer; + }; + + std::array m_directions; + std::size_t m_cubeAttachmentIndex; + FramePipeline& m_pipeline; + const PointLight& m_light; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP diff --git a/include/Nazara/Graphics/PointLightShadowData.inl b/include/Nazara/Graphics/PointLightShadowData.inl new file mode 100644 index 000000000..e55cad13a --- /dev/null +++ b/include/Nazara/Graphics/PointLightShadowData.inl @@ -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 +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Graphics/ShadowViewer.hpp b/include/Nazara/Graphics/ShadowViewer.hpp index 2562fb1bb..87174eaa3 100644 --- a/include/Nazara/Graphics/ShadowViewer.hpp +++ b/include/Nazara/Graphics/ShadowViewer.hpp @@ -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; diff --git a/include/Nazara/Graphics/ShadowViewer.inl b/include/Nazara/Graphics/ShadowViewer.inl index d7dcddfd3..c9dd06790 100644 --- a/include/Nazara/Graphics/ShadowViewer.inl +++ b/include/Nazara/Graphics/ShadowViewer.inl @@ -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; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl index 2cb9c214b..0f6447852 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl @@ -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(name.size()), name.data()); } } diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp index cdbfacf7f..acfce4688 100644 --- a/src/Nazara/Graphics/FrameGraph.cpp +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -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); } } diff --git a/src/Nazara/Graphics/PointLight.cpp b/src/Nazara/Graphics/PointLight.cpp index 6f2af89e4..952da82bb 100644 --- a/src/Nazara/Graphics/PointLight.cpp +++ b/src/Nazara/Graphics/PointLight.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -26,13 +27,14 @@ namespace Nz AccessByOffset(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point); AccessByOffset(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r, m_color.g, m_color.b, m_color.a); AccessByOffset(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor); - AccessByOffset(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius); - AccessByOffset(data, lightOffset.lightMemberOffsets.shadowMapSize) = Vector2f(-1.f, -1.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, 0.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_radius, m_invRadius, 0.f, 0.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.shadowMapSize) = (IsShadowCaster()) ? Vector2f(1.f / GetShadowMapSize()) : Vector2f(-1.f, -1.f); } std::unique_ptr PointLight::InstanciateShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry) const { - return nullptr; //< TODO + return std::make_unique(pipeline, elementRegistry, *this); } void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/) diff --git a/src/Nazara/Graphics/PointLightShadowData.cpp b/src/Nazara/Graphics/PointLightShadowData.cpp new file mode 100644 index 000000000..6bcd91962 --- /dev/null +++ b/src/Nazara/Graphics/PointLightShadowData.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 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(newSize), SafeCast(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(shadowMapSize), SafeCast(shadowMapSize))); + + ViewerInstance& viewerInstance = viewer.GetViewerInstance(); + viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(RadianAnglef(HalfPi), 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(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); + } +} diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl b/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl index 31eb6ac5a..c4d1b7a7e 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl @@ -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 { diff --git a/src/Nazara/Graphics/SpotLightShadowData.cpp b/src/Nazara/Graphics/SpotLightShadowData.cpp index d112ca669..68d69bc39 100644 --- a/src/Nazara/Graphics/SpotLightShadowData.cpp +++ b/src/Nazara/Graphics/SpotLightShadowData.cpp @@ -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(shadowMapSize), SafeCast(shadowMapSize))); ViewerInstance& viewerInstance = m_viewer.GetViewerInstance(); diff --git a/src/Nazara/Graphics/SubmeshRenderer.cpp b/src/Nazara/Graphics/SubmeshRenderer.cpp index 97878439a..74179e89e 100644 --- a/src/Nazara/Graphics/SubmeshRenderer.cpp +++ b/src/Nazara/Graphics/SubmeshRenderer.cpp @@ -198,7 +198,7 @@ namespace Nz auto& bindingEntry = m_bindingCache.emplace_back(); bindingEntry.bindingIndex = bindingIndex; bindingEntry.content = ShaderBinding::TextureBindings { - SafeCast(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex] + SafeCast(renderState.shadowMapsCube.size()), &m_textureBindingCache[textureBindingBaseIndex] }; } diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp index e3f014d3d..ee19f5c81 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp @@ -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 }