From f508c4a4b5d79a8da6459a4eaf744c6afc6f2b4a Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Sat, 24 Apr 2021 00:28:43 -0700 Subject: [PATCH 01/17] Initial pointlight shadow work --- .../CoreLights/ViewSrg.azsli | 2 + .../RayTracingSceneSrg.azsli | 2 + .../Shaders/LightCulling/LightCulling.azsl | 2 + .../PointLightFeatureProcessorInterface.h | 3 + .../CoreLights/DiskLightFeatureProcessor.h | 2 +- .../CoreLights/PointLightFeatureProcessor.cpp | 87 +++++++++++++++++++ .../CoreLights/PointLightFeatureProcessor.h | 10 +++ 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 5404cf8b69..c236730cc1 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,6 +73,8 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; + uint m_shadowIndex; + uint m_padding[3]; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli index 0aeb43bcf2..b306ae7e61 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli @@ -63,6 +63,8 @@ partial ShaderResourceGroup RayTracingSceneSrg float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; + uint m_shadowIndex; + uint m_padding[3]; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 367720d13b..8672350d35 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -59,6 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; + uint m_shadowIndex; + uint m_padding[3]; }; struct DiskLight diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 68e1a01e56..d55e50f012 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -14,6 +14,7 @@ #include #include +#include namespace AZ { @@ -48,6 +49,8 @@ namespace AZ virtual void SetAttenuationRadius(LightHandle handle, float attenuationRadius) = 0; //! Sets the bulb radius for the provided LightHandle. Values greater than zero effectively make it a spherical light. virtual void SetBulbRadius(LightHandle handle, float bulbRadius) = 0; + //! Sets if shadows are enabled + virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 446b008921..483f3cb711 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -84,7 +84,7 @@ namespace AZ template void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); - ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor; + ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_diskLightData; GpuBufferHandler m_lightBufferHandler; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 661a7d4bf4..21d01c642b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -54,6 +54,7 @@ namespace AZ desc.m_elementCountSrgName = "m_pointLightCount"; desc.m_elementSize = sizeof(PointLightData); desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgAsset()->GetLayout(); + m_shadowFeatureProcessor = GetParentScene()->GetFeatureProcessor(); m_lightBufferHandler = GpuBufferHandler(desc); } @@ -83,6 +84,11 @@ namespace AZ { if (handle.IsValid()) { + ShadowId shadowId = ShadowId(m_pointLightData.GetData(handle.GetIndex()).m_shadowIndex); + if (shadowId.IsValid()) + { + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + } m_pointLightData.RemoveIndex(handle.GetIndex()); m_deviceBufferNeedsUpdate = true; handle.Reset(); @@ -177,5 +183,86 @@ namespace AZ return m_lightBufferHandler.GetElementCount(); } + void PointLightFeatureProcessor::SetShadowsEnabled(LightHandle handle, bool enabled) + { + auto& light = m_pointLightData.GetData(handle.GetIndex()); + ShadowId shadowId = ShadowId(light.m_shadowIndex); + if (shadowId.IsValid() && enabled == false) + { + // Disable shadows + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + shadowId.Reset(); + light.m_shadowIndex = shadowId.GetIndex(); + m_deviceBufferNeedsUpdate = true; + } + else if (shadowId.IsNull() && enabled == true) + { + // Enable shadows + light.m_shadowIndex = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); + + UpdateShadow(handle); + m_deviceBufferNeedsUpdate = true; + } + } + + void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) + { + const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); + ShadowId shadowId = ShadowId(pointLight.m_shadowIndex); + if (shadowId.IsNull()) + { + // Early out if shadows are disabled. + return; + } + + ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = + m_shadowFeatureProcessor->GetShadowProperties(shadowId); + + Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data()); + + constexpr float SmallAngle = 0.01f; + desc.m_fieldOfViewYRadians = 1.57f; + + // To handle bulb radius, set the position of the shadow caster behind the actual light depending on the radius of the bulb + // + // \ / + // \ / + // \_____/ <-- position of light itself (and forward plane of shadow casting view) + // . . + // . . + // * <-- position of shadow casting view + // + desc.m_transform = Transform::CreateLookAt(position, AZ::Vector3::CreateZero()); + + desc.m_aspectRatio = 1.0f; + desc.m_nearPlaneDistance = 0.1f; + + const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; + if (invRadiusSquared <= 0.f) + { + AZ_Assert(false, "Attenuation radius have to be set before use the light."); + return; + } + const float attenuationRadius = sqrtf(1.f / invRadiusSquared); + desc.m_farPlaneDistance = attenuationRadius; + + m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc); + } + + template + void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param) + { + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetShadowSetting()."); + + auto& light = m_pointLightData.GetData(handle.GetIndex()); + ShadowId shadowId = ShadowId(light.m_shadowIndex); + + AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled."); + if (shadowId.IsValid()) + { + AZStd::invoke(AZStd::forward(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward(param)); + } + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 25b9bfa2cd..8f159ea455 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace AZ { @@ -31,6 +32,8 @@ namespace AZ float m_invAttenuationRadiusSquared = 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. AZStd::array m_rgbIntensity = { { 0.0f, 0.0f, 0.0f } }; float m_bulbRadius = 0.0f; // Radius of spherical light in meters. + uint32_t m_shadowIndex; + uint32_t m_padding[3]; }; class PointLightFeatureProcessor final @@ -58,14 +61,21 @@ namespace AZ void SetPosition(LightHandle handle, const AZ::Vector3& lightPosition) override; void SetAttenuationRadius(LightHandle handle, float attenuationRadius) override; void SetBulbRadius(LightHandle handle, float bulbRadius) override; + void SetShadowsEnabled(LightHandle handle, bool enabled) override; const Data::Instance GetLightBuffer() const; uint32_t GetLightCount()const; private: PointLightFeatureProcessor(const PointLightFeatureProcessor&) = delete; + using ShadowId = ProjectedShadowFeatureProcessor::ShadowId; static constexpr const char* FeatureProcessorName = "PointLightFeatureProcessor"; + void UpdateShadow(LightHandle handle); + // Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor + template + void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); + ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_pointLightData; GpuBufferHandler m_lightBufferHandler; From 569c831532fd364927a1c81c4ddd545b848c7aa9 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Mon, 26 Apr 2021 14:53:31 -0700 Subject: [PATCH 02/17] Working PLS --- .../Atom/Features/PBR/Lights/PointLight.azsli | 99 +++++++++++++- .../CoreLights/ViewSrg.azsli | 4 +- .../RayTracingSceneSrg.azsli | 4 +- .../Shaders/LightCulling/LightCulling.azsl | 4 +- .../PointLightFeatureProcessorInterface.h | 2 + .../CoreLights/PointLightFeatureProcessor.cpp | 124 ++++++++++-------- .../CoreLights/PointLightFeatureProcessor.h | 12 +- 7 files changed, 181 insertions(+), 68 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index a59eb89dc7..588f6419af 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -13,6 +13,67 @@ #pragma once #include +#include + +int GetShadowDirectionIndex(float3 targetPos, float3 lightPos) +{ + float3 toPoint = targetPos - lightPos; + toPoint = normalize(toPoint); + + const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); + if (toPoint.x == -maxElement) + { + return 5; + } + else if (toPoint.x == maxElement) + { + return 4; + } + else if (toPoint.y == -maxElement) + { + return 3; + } + else if (toPoint.y == maxElement) + { + return 2; + } + else if (toPoint.z == -maxElement) + { + return 1; + } + else + { + return 0; + } +} + +int GetShadowIndex(ViewSrg::PointLight light, int i) +{ + if (i == 0) + { + return light.m_shadowIndices[0] & 0xFFFF; + } + else if (i==1) + { + return (light.m_shadowIndices[0] >> 16) & 0xFFFF; + } + else if (i==2) + { + return (light.m_shadowIndices[1]) & 0xFFFF; + } + else if (i==3) + { + return (light.m_shadowIndices[1] >> 16) & 0xFFFF; + } + else if (i==4) + { + return (light.m_shadowIndices[2]) & 0xFFFF; + } + else + { + return (light.m_shadowIndices[2] >> 16) & 0xFFFF; + } +} void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData) { @@ -31,11 +92,45 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD d2 = max(0.001 * 0.001, d2); // clamp the light to at least 1mm away to avoid extreme values. float3 lightIntensity = (light.m_rgbIntensityCandelas / d2) * radiusAttenuation; + // shadow + float litRatio = 1.0; + + // How much is back face shadowed, it's set to the reverse of litRatio to share the same default value with thickness, which should be 0 if no shadow map available + float backShadowRatio = 0.0; + if (o_enableShadows) + { + const float3 Directions[6] = {float3(0,0,1), float3(0,0,-1), float3(0,1,0), float3(0,-1,0), float3(1,0,0), float3(-1,0,0)}; + const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); + + { + + litRatio *= ProjectedShadow::GetVisibility( + GetShadowIndex(light, shadowDirectionIndex), + light.m_position, + surface.position, + Directions[shadowDirectionIndex], + surface.normal); + + } + + + /* + // Use backShadowRatio to carry thickness from shadow map for thick mode + backShadowRatio = 1.0 - litRatio; + if (o_transmission_mode == TransmissionMode::ThickObject) + { + backShadowRatio = ProjectedShadow::GetThickness( + shadowIndex, + surface.position); + } */ + + } + // Diffuse contribution - lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)); + lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio; // Tranmission contribution - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0); + lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0) * litRatio; // Adjust the light direcion for specular based on bulb size diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index c236730cc1..253fdfe974 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,8 +73,8 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndex; - uint m_padding[3]; + uint m_shadowIndices[3]; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli index b306ae7e61..ff7ef64277 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli @@ -63,8 +63,8 @@ partial ShaderResourceGroup RayTracingSceneSrg float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; - uint m_shadowIndex; - uint m_padding[3]; + uint m_shadowIndices[3]; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 8672350d35..1f914ee1b9 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -59,8 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndex; - uint m_padding[3]; + uint m_shadowIndices[3]; + uint m_padding; }; struct DiskLight diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index d55e50f012..de3d00dbde 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -51,6 +51,8 @@ namespace AZ virtual void SetBulbRadius(LightHandle handle, float bulbRadius) = 0; //! Sets if shadows are enabled virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; + //! Sets the shadowmap size (width and height) of the light. + virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 21d01c642b..fcc4acc246 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -44,6 +44,12 @@ namespace AZ PointLightFeatureProcessor::PointLightFeatureProcessor() : PointLightFeatureProcessorInterface() { + m_directions[0] = AZ::Vector3::CreateAxisZ(); + m_directions[1] = -AZ::Vector3::CreateAxisZ(); + m_directions[2] = AZ::Vector3::CreateAxisY(); + m_directions[3] = -AZ::Vector3::CreateAxisY(); + m_directions[4] = AZ::Vector3::CreateAxisX(); + m_directions[5] = -AZ::Vector3::CreateAxisX(); } void PointLightFeatureProcessor::Activate() @@ -84,11 +90,15 @@ namespace AZ { if (handle.IsValid()) { - ShadowId shadowId = ShadowId(m_pointLightData.GetData(handle.GetIndex()).m_shadowIndex); - if (shadowId.IsValid()) + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { - m_shadowFeatureProcessor->ReleaseShadow(shadowId); + ShadowId shadowId = ShadowId(m_pointLightData.GetData(handle.GetIndex()).m_shadowIndices[i]); + if (shadowId.IsValid()) + { + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + } } + m_pointLightData.RemoveIndex(handle.GetIndex()); m_deviceBufferNeedsUpdate = true; handle.Reset(); @@ -154,6 +164,7 @@ namespace AZ lightPosition.StoreToFloat3(position.data()); m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); } void PointLightFeatureProcessor::SetAttenuationRadius(LightHandle handle, float attenuationRadius) @@ -186,76 +197,68 @@ namespace AZ void PointLightFeatureProcessor::SetShadowsEnabled(LightHandle handle, bool enabled) { auto& light = m_pointLightData.GetData(handle.GetIndex()); - ShadowId shadowId = ShadowId(light.m_shadowIndex); - if (shadowId.IsValid() && enabled == false) + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { - // Disable shadows - m_shadowFeatureProcessor->ReleaseShadow(shadowId); - shadowId.Reset(); - light.m_shadowIndex = shadowId.GetIndex(); - m_deviceBufferNeedsUpdate = true; - } - else if (shadowId.IsNull() && enabled == true) - { - // Enable shadows - light.m_shadowIndex = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); + ShadowId shadowId = ShadowId(light.m_shadowIndices[i]); + if (shadowId.IsValid() && enabled == false) + { + // Disable shadows + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + shadowId.Reset(); + light.m_shadowIndices[i] = shadowId.GetIndex(); + m_deviceBufferNeedsUpdate = true; + } + else if (shadowId.IsNull() && enabled == true) + { + // Enable shadows + light.m_shadowIndices[i] = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); - UpdateShadow(handle); - m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); + m_deviceBufferNeedsUpdate = true; + } } } void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) { - const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); - ShadowId shadowId = ShadowId(pointLight.m_shadowIndex); - if (shadowId.IsNull()) + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { - // Early out if shadows are disabled. - return; + const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); + ShadowId shadowId = ShadowId(pointLight.m_shadowIndices[i]); + if (shadowId.IsNull()) + { + // Early out if shadows are disabled. + return; + } + + ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); + Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data()); + + desc.m_fieldOfViewYRadians = 1.58825f; + desc.m_transform = Transform::CreateLookAt(position, position + m_directions[i]); + desc.m_aspectRatio = 1.0f; + desc.m_nearPlaneDistance = 0.1f; + + const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; + if (invRadiusSquared <= 0.f) + { + AZ_Assert(false, "Attenuation radius have to be set before use the light."); + return; + } + const float attenuationRadius = sqrtf(1.f / invRadiusSquared); + desc.m_farPlaneDistance = attenuationRadius; + + m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc); } - - ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = - m_shadowFeatureProcessor->GetShadowProperties(shadowId); - - Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data()); - - constexpr float SmallAngle = 0.01f; - desc.m_fieldOfViewYRadians = 1.57f; - - // To handle bulb radius, set the position of the shadow caster behind the actual light depending on the radius of the bulb - // - // \ / - // \ / - // \_____/ <-- position of light itself (and forward plane of shadow casting view) - // . . - // . . - // * <-- position of shadow casting view - // - desc.m_transform = Transform::CreateLookAt(position, AZ::Vector3::CreateZero()); - - desc.m_aspectRatio = 1.0f; - desc.m_nearPlaneDistance = 0.1f; - - const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; - if (invRadiusSquared <= 0.f) - { - AZ_Assert(false, "Attenuation radius have to be set before use the light."); - return; - } - const float attenuationRadius = sqrtf(1.f / invRadiusSquared); - desc.m_farPlaneDistance = attenuationRadius; - - m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc); } template - void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param) + void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param, const int lightIndex) { AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetShadowSetting()."); auto& light = m_pointLightData.GetData(handle.GetIndex()); - ShadowId shadowId = ShadowId(light.m_shadowIndex); + ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]); AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled."); if (shadowId.IsValid()) @@ -264,5 +267,12 @@ namespace AZ } } + void PointLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) + { + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize, i); + } + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 8f159ea455..589da59955 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -32,8 +32,11 @@ namespace AZ float m_invAttenuationRadiusSquared = 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. AZStd::array m_rgbIntensity = { { 0.0f, 0.0f, 0.0f } }; float m_bulbRadius = 0.0f; // Radius of spherical light in meters. - uint32_t m_shadowIndex; - uint32_t m_padding[3]; + + static const int NumShadowFaces = 6; + + AZStd::array m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}}; + uint32_t m_padding; }; class PointLightFeatureProcessor final @@ -62,6 +65,7 @@ namespace AZ void SetAttenuationRadius(LightHandle handle, float attenuationRadius) override; void SetBulbRadius(LightHandle handle, float bulbRadius) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override; + void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; const Data::Instance GetLightBuffer() const; uint32_t GetLightCount()const; @@ -74,12 +78,14 @@ namespace AZ void UpdateShadow(LightHandle handle); // Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor template - void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); + void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param, const int lightIndex); ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_pointLightData; GpuBufferHandler m_lightBufferHandler; bool m_deviceBufferNeedsUpdate = false; + + AZStd::array m_directions; }; } // namespace Render } // namespace AZ From bbae3b6d48c3ab8e1c910e31edda2b671e9e4731 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Mon, 26 Apr 2021 16:16:05 -0700 Subject: [PATCH 03/17] Slight improvements --- .../Atom/Features/PBR/Lights/PointLight.azsli | 16 +++++----------- .../CoreLights/PointLightFeatureProcessor.cpp | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index 588f6419af..f803a5802c 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -101,20 +101,14 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD { const float3 Directions[6] = {float3(0,0,1), float3(0,0,-1), float3(0,1,0), float3(0,-1,0), float3(1,0,0), float3(-1,0,0)}; const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); - - { - - litRatio *= ProjectedShadow::GetVisibility( - GetShadowIndex(light, shadowDirectionIndex), + const int shadowIndex = GetShadowIndex(light, shadowDirectionIndex); + litRatio *= ProjectedShadow::GetVisibility( + shadowIndex, light.m_position, surface.position, Directions[shadowDirectionIndex], surface.normal); - - } - - - /* + // Use backShadowRatio to carry thickness from shadow map for thick mode backShadowRatio = 1.0 - litRatio; if (o_transmission_mode == TransmissionMode::ThickObject) @@ -122,7 +116,7 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD backShadowRatio = ProjectedShadow::GetThickness( shadowIndex, surface.position); - } */ + } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index fcc4acc246..62af94e548 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -234,7 +234,7 @@ namespace AZ ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data()); - desc.m_fieldOfViewYRadians = 1.58825f; + desc.m_fieldOfViewYRadians = DegToRad(90.5f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces desc.m_transform = Transform::CreateLookAt(position, position + m_directions[i]); desc.m_aspectRatio = 1.0f; desc.m_nearPlaneDistance = 0.1f; From 2eed8684b571944eaf5f1dc98ac73ff7f1420687 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Tue, 27 Apr 2021 14:08:54 -0700 Subject: [PATCH 04/17] Adding full shadowmap support --- .../PointLightFeatureProcessorInterface.h | 28 +++++++++ .../CoreLights/DiskLightFeatureProcessor.h | 2 +- .../CoreLights/PointLightFeatureProcessor.cpp | 59 +++++++++++++++---- .../CoreLights/PointLightFeatureProcessor.h | 22 +++---- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index de3d00dbde..20e6d366f5 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -23,6 +23,20 @@ namespace AZ namespace Render { + struct PointLightData + { + AZStd::array m_position = {{0.0f, 0.0f, 0.0f}}; + float m_invAttenuationRadiusSquared = + 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. + AZStd::array m_rgbIntensity = {{0.0f, 0.0f, 0.0f}}; + float m_bulbRadius = 0.0f; // Radius of spherical light in meters. + + static const int NumShadowFaces = 6; + + AZStd::array m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}}; + uint32_t m_padding; + }; + //! PointLightFeatureProcessorInterface provides an interface to acquire, release, and update a point light. class PointLightFeatureProcessorInterface : public RPI::FeatureProcessor @@ -53,6 +67,20 @@ namespace AZ virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; //! Sets the shadowmap size (width and height) of the light. virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; + //! Specifies filter method of shadows. + virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; + //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on + //! the boundary. 0 disables softening. + virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; + //! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering + //! sample count. + virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0; + //! Sets sample count for filtering of shadow boundary (up to 64) + virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; + //! Sets the shadowmap Pcf (percentage closer filtering) method. + virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0; + //! Sets all of the the point data for the provided LightHandle. + virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 483f3cb711..8391506f63 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -59,7 +59,7 @@ namespace AZ void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; - void SetPcfMethod(LightHandle handle, PcfMethod method); + void SetPcfMethod(LightHandle handle, PcfMethod method) override; void SetDiskData(LightHandle handle, const DiskLightData& data) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 62af94e548..94d5878e47 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -219,6 +219,15 @@ namespace AZ } } + void PointLightFeatureProcessor::SetPointData(LightHandle handle, const PointLightData& data) + { + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetDiskData()."); + + m_pointLightData.GetData(handle.GetIndex()) = data; + m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); + } + void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) { for (int i = 0; i < PointLightData::NumShadowFaces; ++i) @@ -237,7 +246,7 @@ namespace AZ desc.m_fieldOfViewYRadians = DegToRad(90.5f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces desc.m_transform = Transform::CreateLookAt(position, position + m_directions[i]); desc.m_aspectRatio = 1.0f; - desc.m_nearPlaneDistance = 0.1f; + desc.m_nearPlaneDistance = 0.0f; const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; if (invRadiusSquared <= 0.f) @@ -246,33 +255,59 @@ namespace AZ return; } const float attenuationRadius = sqrtf(1.f / invRadiusSquared); - desc.m_farPlaneDistance = attenuationRadius; + desc.m_farPlaneDistance = attenuationRadius + pointLight.m_bulbRadius; m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc); } } template - void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param, const int lightIndex) + void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param) { AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetShadowSetting()."); auto& light = m_pointLightData.GetData(handle.GetIndex()); - ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]); - - AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled."); - if (shadowId.IsValid()) + for (int lightIndex = 0; lightIndex < PointLightData::NumShadowFaces; ++lightIndex) { - AZStd::invoke(AZStd::forward(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward(param)); + ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]); + + AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled."); + if (shadowId.IsValid()) + { + AZStd::invoke(AZStd::forward(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward(param)); + } } } void PointLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) { - for (int i = 0; i < PointLightData::NumShadowFaces; ++i) - { - SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize, i); - } + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize); } + + void PointLightFeatureProcessor::SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); + } + + void PointLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); + } + + void PointLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count); + } + + void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count); + } + + void PointLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 589da59955..437ebc2f0a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -25,20 +25,6 @@ namespace AZ namespace Render { - - struct PointLightData - { - AZStd::array m_position = { { 0.0f, 0.0f, 0.0f } }; - float m_invAttenuationRadiusSquared = 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. - AZStd::array m_rgbIntensity = { { 0.0f, 0.0f, 0.0f } }; - float m_bulbRadius = 0.0f; // Radius of spherical light in meters. - - static const int NumShadowFaces = 6; - - AZStd::array m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}}; - uint32_t m_padding; - }; - class PointLightFeatureProcessor final : public PointLightFeatureProcessorInterface { @@ -66,6 +52,12 @@ namespace AZ void SetBulbRadius(LightHandle handle, float bulbRadius) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; + void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; + void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; + void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; + void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; + void SetPcfMethod(LightHandle handle, PcfMethod method) override; + void SetPointData(LightHandle handle, const PointLightData& data) override; const Data::Instance GetLightBuffer() const; uint32_t GetLightCount()const; @@ -78,7 +70,7 @@ namespace AZ void UpdateShadow(LightHandle handle); // Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor template - void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param, const int lightIndex); + void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param); ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr; IndexedDataVector m_pointLightData; From 805eb1ba34c32be9ad4d10690ce6e441a5b58dd3 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Tue, 27 Apr 2021 15:14:59 -0700 Subject: [PATCH 05/17] Adding editor point light support --- .../CoreLights/AreaLightComponentConfig.cpp | 2 +- .../Source/CoreLights/SphereLightDelegate.cpp | 55 +++++++++++++++++++ .../Source/CoreLights/SphereLightDelegate.h | 9 +++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index 2dc439b846..8f10204ae9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -112,7 +112,7 @@ namespace AZ bool AreaLightComponentConfig::SupportsShadows() const { - return m_shapeType == AZ_CRC_CE("DiskShape"); + return m_lightType == LightType::SpotDisk || m_lightType == LightType::Sphere; } bool AreaLightComponentConfig::ShadowsDisabled() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index de733e255b..7a74ad4c5c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -63,5 +63,60 @@ namespace AZ debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity)); } } + + void SphereLightDelegate::SetEnableShadow(bool enabled) + { + Base::SetEnableShadow(enabled); + GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); + } + + void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); + } + } + + void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); + } + } + + void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); + } + } + + void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetPcfMethod(PcfMethod method) + { + if (GetShadowsEnabled()) + { + GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method); + } + } + } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 7d790f2d6c..178540fd01 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -24,6 +24,8 @@ namespace AZ class SphereLightDelegate final : public LightDelegateBase { + using Base = LightDelegateBase; + public: SphereLightDelegate(LmbrCentral::SphereShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible); @@ -32,6 +34,13 @@ namespace AZ void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const override; float GetSurfaceArea() const override; float GetEffectiveSolidAngle() const override { return PhotometricValue::OmnidirectionalSteradians; } + void SetEnableShadow(bool enabled) override; + void SetShadowmapMaxSize(ShadowmapSize size) override; + void SetShadowFilterMethod(ShadowFilterMethod method) override; + void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; + void SetPredictionSampleCount(uint32_t count) override; + void SetFilteringSampleCount(uint32_t count) override; + void SetPcfMethod(PcfMethod method) override; private: From c729c72034dbe5b2a01f094c0d37dcb0bba7336f Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 09:35:56 -0700 Subject: [PATCH 06/17] Switching to XYZ instead of ZYX --- .../Atom/Features/PBR/Lights/PointLight.azsli | 14 +++++++------- .../CoreLights/PointLightFeatureProcessor.cpp | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index f803a5802c..dfd06a57ff 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -23,27 +23,27 @@ int GetShadowDirectionIndex(float3 targetPos, float3 lightPos) const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); if (toPoint.x == -maxElement) { - return 5; + return 0; } else if (toPoint.x == maxElement) { - return 4; + return 1; } else if (toPoint.y == -maxElement) { - return 3; + return 2; } else if (toPoint.y == maxElement) { - return 2; + return 3; } else if (toPoint.z == -maxElement) { - return 1; + return 4; } else { - return 0; + return 5; } } @@ -99,7 +99,7 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD float backShadowRatio = 0.0; if (o_enableShadows) { - const float3 Directions[6] = {float3(0,0,1), float3(0,0,-1), float3(0,1,0), float3(0,-1,0), float3(1,0,0), float3(-1,0,0)}; + const float3 Directions[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); const int shadowIndex = GetShadowIndex(light, shadowDirectionIndex); litRatio *= ProjectedShadow::GetVisibility( diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 94d5878e47..8480bec2ce 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -44,12 +44,12 @@ namespace AZ PointLightFeatureProcessor::PointLightFeatureProcessor() : PointLightFeatureProcessorInterface() { - m_directions[0] = AZ::Vector3::CreateAxisZ(); - m_directions[1] = -AZ::Vector3::CreateAxisZ(); - m_directions[2] = AZ::Vector3::CreateAxisY(); - m_directions[3] = -AZ::Vector3::CreateAxisY(); - m_directions[4] = AZ::Vector3::CreateAxisX(); - m_directions[5] = -AZ::Vector3::CreateAxisX(); + m_directions[0] = -AZ::Vector3::CreateAxisX(); + m_directions[1] = AZ::Vector3::CreateAxisX(); + m_directions[2] = -AZ::Vector3::CreateAxisY(); + m_directions[3] = AZ::Vector3::CreateAxisY(); + m_directions[4] = -AZ::Vector3::CreateAxisZ(); + m_directions[5] = AZ::Vector3::CreateAxisZ(); } void PointLightFeatureProcessor::Activate() From 37fd8d43ed97ee244ab81c855e28c9332635f3d2 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 10:40:31 -0700 Subject: [PATCH 07/17] Tabs to space and better naming and comments --- .../Atom/Features/PBR/Lights/PointLight.azsli | 132 +++++++++--------- .../CoreLights/PointLightFeatureProcessor.cpp | 18 +-- .../CoreLights/PointLightFeatureProcessor.h | 2 +- 3 files changed, 75 insertions(+), 77 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index dfd06a57ff..95482d432f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -15,64 +15,62 @@ #include #include -int GetShadowDirectionIndex(float3 targetPos, float3 lightPos) +int GetShadowDirectionIndex(const float3 targetPos, const float3 lightPos) { - float3 toPoint = targetPos - lightPos; - toPoint = normalize(toPoint); - - const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); - if (toPoint.x == -maxElement) - { - return 0; - } - else if (toPoint.x == maxElement) - { - return 1; - } - else if (toPoint.y == -maxElement) - { - return 2; - } - else if (toPoint.y == maxElement) - { - return 3; - } - else if (toPoint.z == -maxElement) - { - return 4; - } - else - { - return 5; - } + const float3 toPoint = targetPos - lightPos; + const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); + if (toPoint.x == -maxElement) + { + return 0; + } + else if (toPoint.x == maxElement) + { + return 1; + } + else if (toPoint.y == -maxElement) + { + return 2; + } + else if (toPoint.y == maxElement) + { + return 3; + } + else if (toPoint.z == -maxElement) + { + return 4; + } + else + { + return 5; + } } -int GetShadowIndex(ViewSrg::PointLight light, int i) +int UnpackShadowIndex(const ViewSrg::PointLight light, const int i) { - if (i == 0) - { - return light.m_shadowIndices[0] & 0xFFFF; - } - else if (i==1) - { - return (light.m_shadowIndices[0] >> 16) & 0xFFFF; - } - else if (i==2) - { - return (light.m_shadowIndices[1]) & 0xFFFF; - } - else if (i==3) - { - return (light.m_shadowIndices[1] >> 16) & 0xFFFF; - } - else if (i==4) - { - return (light.m_shadowIndices[2]) & 0xFFFF; - } - else - { - return (light.m_shadowIndices[2] >> 16) & 0xFFFF; - } + if (i == 0) + { + return light.m_shadowIndices[0] & 0xFFFF; + } + else if (i==1) + { + return (light.m_shadowIndices[0] >> 16) & 0xFFFF; + } + else if (i==2) + { + return (light.m_shadowIndices[1]) & 0xFFFF; + } + else if (i==3) + { + return (light.m_shadowIndices[1] >> 16) & 0xFFFF; + } + else if (i==4) + { + return (light.m_shadowIndices[2]) & 0xFFFF; + } + else + { + return (light.m_shadowIndices[2] >> 16) & 0xFFFF; + } } void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData) @@ -99,16 +97,17 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD float backShadowRatio = 0.0; if (o_enableShadows) { - const float3 Directions[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; - const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); - const int shadowIndex = GetShadowIndex(light, shadowDirectionIndex); - litRatio *= ProjectedShadow::GetVisibility( - shadowIndex, - light.m_position, - surface.position, - Directions[shadowDirectionIndex], - surface.normal); - + // The order should match m_pointShadowTransforms in PointLightFeatureProcessor.h/.cpp + const float3 PointShadowDirections[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; + const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); + const int shadowIndex = UnpackShadowIndex(light, shadowDirectionIndex); + litRatio *= ProjectedShadow::GetVisibility( + shadowIndex, + light.m_position, + surface.position, + PointShadowDirections[shadowDirectionIndex], + surface.normal); + // Use backShadowRatio to carry thickness from shadow map for thick mode backShadowRatio = 1.0 - litRatio; if (o_transmission_mode == TransmissionMode::ThickObject) @@ -116,9 +115,8 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD backShadowRatio = ProjectedShadow::GetThickness( shadowIndex, surface.position); - } - - } + } + } // Diffuse contribution lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 8480bec2ce..9a940ea7b0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -44,12 +44,13 @@ namespace AZ PointLightFeatureProcessor::PointLightFeatureProcessor() : PointLightFeatureProcessorInterface() { - m_directions[0] = -AZ::Vector3::CreateAxisX(); - m_directions[1] = AZ::Vector3::CreateAxisX(); - m_directions[2] = -AZ::Vector3::CreateAxisY(); - m_directions[3] = AZ::Vector3::CreateAxisY(); - m_directions[4] = -AZ::Vector3::CreateAxisZ(); - m_directions[5] = AZ::Vector3::CreateAxisZ(); + // Note must match PointShadowDirections in PointLight.azsli + m_pointShadowTransforms[0] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisX()); + m_pointShadowTransforms[1] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisX()); + m_pointShadowTransforms[2] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisY()); + m_pointShadowTransforms[3] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisY()); + m_pointShadowTransforms[4] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), -AZ::Vector3::CreateAxisZ()); + m_pointShadowTransforms[5] = AZ::Transform::CreateLookAt(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ()); } void PointLightFeatureProcessor::Activate() @@ -241,10 +242,9 @@ namespace AZ } ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); - Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data()); - desc.m_fieldOfViewYRadians = DegToRad(90.5f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces - desc.m_transform = Transform::CreateLookAt(position, position + m_directions[i]); + desc.m_transform = m_pointShadowTransforms[i]; + desc.m_transform.SetTranslation(pointLight.m_position[0], pointLight.m_position[1], pointLight.m_position[2]); desc.m_aspectRatio = 1.0f; desc.m_nearPlaneDistance = 0.0f; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 437ebc2f0a..c0c377e960 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -77,7 +77,7 @@ namespace AZ GpuBufferHandler m_lightBufferHandler; bool m_deviceBufferNeedsUpdate = false; - AZStd::array m_directions; + AZStd::array m_pointShadowTransforms; }; } // namespace Render } // namespace AZ From 66d36137b7522ad94853543a502b07dca98a0995 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 10:53:52 -0700 Subject: [PATCH 08/17] Tabs to spaces --- .../Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli | 4 ++-- .../Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli | 4 ++-- .../Common/Assets/Shaders/LightCulling/LightCulling.azsl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 253fdfe974..6c4a6d2a36 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,8 +73,8 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint m_shadowIndices[3]; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli index ff7ef64277..b392e07e06 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli @@ -63,8 +63,8 @@ partial ShaderResourceGroup RayTracingSceneSrg float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint m_shadowIndices[3]; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 1f914ee1b9..398103a93f 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -59,8 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint m_shadowIndices[3]; + uint m_padding; }; struct DiskLight From ce2af6be152a6ba43681a5a8b34381c849c7e552 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 11:53:27 -0700 Subject: [PATCH 09/17] Tabs to spaces --- .../PointLightFeatureProcessorInterface.h | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 20e6d366f5..aaffac6d5a 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -1,20 +1,20 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once -#include #include #include +#include namespace AZ { @@ -38,8 +38,7 @@ namespace AZ }; //! PointLightFeatureProcessorInterface provides an interface to acquire, release, and update a point light. - class PointLightFeatureProcessorInterface - : public RPI::FeatureProcessor + class PointLightFeatureProcessorInterface : public RPI::FeatureProcessor { public: AZ_RTTI(AZ::Render::PointLightFeatureProcessorInterface, "{D3E0B016-F3C6-4C7A-A29E-0B3A4FA87806}", AZ::RPI::FeatureProcessor); @@ -48,7 +47,8 @@ namespace AZ using LightHandle = RHI::Handle; static constexpr PhotometricUnit PhotometricUnitType = PhotometricUnit::Candela; - //! Creates a new point light which can be referenced by the returned LightHandle. Must be released via ReleaseLight() when no longer needed. + //! Creates a new point light which can be referenced by the returned LightHandle. Must be released via ReleaseLight() when no + //! longer needed. virtual LightHandle AcquireLight() = 0; //! Releases a LightHandle which removes the point light. virtual bool ReleaseLight(LightHandle& handle) = 0; @@ -65,7 +65,7 @@ namespace AZ virtual void SetBulbRadius(LightHandle handle, float bulbRadius) = 0; //! Sets if shadows are enabled virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; - //! Sets the shadowmap size (width and height) of the light. + //! Sets the shadowmap size (width and height) of the light. virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; From 9dd3fe49df16f403076b097cb21e9d96b97f48a6 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 17:27:20 -0700 Subject: [PATCH 10/17] fixing spelling and increasing angle so that the borders are not visible at 256 res --- .../Code/Source/CoreLights/DiskLightFeatureProcessor.cpp | 2 +- .../Code/Source/CoreLights/PointLightFeatureProcessor.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index 58bbed699a..d0fb702d5a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -380,7 +380,7 @@ namespace AZ const float invRadiusSquared = diskLight.m_invAttenuationRadiusSquared; if (invRadiusSquared <= 0.f) { - AZ_Assert(false, "Attenuation radius have to be set before use the light."); + AZ_Assert(false, "Attenuation radius must be set before using the light."); return; } const float attenuationRadius = sqrtf(1.f / invRadiusSquared); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 9a940ea7b0..5110674492 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -222,7 +222,7 @@ namespace AZ void PointLightFeatureProcessor::SetPointData(LightHandle handle, const PointLightData& data) { - AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetDiskData()."); + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetPointData()."); m_pointLightData.GetData(handle.GetIndex()) = data; m_deviceBufferNeedsUpdate = true; @@ -231,9 +231,9 @@ namespace AZ void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) { + const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { - const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); ShadowId shadowId = ShadowId(pointLight.m_shadowIndices[i]); if (shadowId.IsNull()) { @@ -242,7 +242,7 @@ namespace AZ } ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); - desc.m_fieldOfViewYRadians = DegToRad(90.5f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces + desc.m_fieldOfViewYRadians = DegToRad(91.0f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces desc.m_transform = m_pointShadowTransforms[i]; desc.m_transform.SetTranslation(pointLight.m_position[0], pointLight.m_position[1], pointLight.m_position[2]); desc.m_aspectRatio = 1.0f; @@ -251,7 +251,7 @@ namespace AZ const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; if (invRadiusSquared <= 0.f) { - AZ_Assert(false, "Attenuation radius have to be set before use the light."); + AZ_Assert(false, "Attenuation radius must be set before using the light."); return; } const float attenuationRadius = sqrtf(1.f / invRadiusSquared); From 815c02fb576cbded9c0cd2b8d7407bc3d9788d93 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 17:45:17 -0700 Subject: [PATCH 11/17] better var names --- .../Atom/Features/PBR/Lights/PointLight.azsli | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index 95482d432f..42eb4b81da 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -15,7 +15,10 @@ #include #include -int GetShadowDirectionIndex(const float3 targetPos, const float3 lightPos) +// The order should match m_pointShadowTransforms in PointLightFeatureProcessor.h/.cpp +static const float3 PointLightShadowCubemapDirections[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; + +int GetPointLightShadowCubemapFace(const float3 targetPos, const float3 lightPos) { const float3 toPoint = targetPos - lightPos; const float maxElement = max(abs(toPoint.z), max(abs(toPoint.x), abs(toPoint.y))); @@ -45,7 +48,7 @@ int GetShadowDirectionIndex(const float3 targetPos, const float3 lightPos) } } -int UnpackShadowIndex(const ViewSrg::PointLight light, const int i) +int UnpackPointLightShadowIndex(const ViewSrg::PointLight light, const int i) { if (i == 0) { @@ -97,15 +100,14 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD float backShadowRatio = 0.0; if (o_enableShadows) { - // The order should match m_pointShadowTransforms in PointLightFeatureProcessor.h/.cpp - const float3 PointShadowDirections[6] = {float3(-1,0,0), float3(1,0,0), float3(0,-1,0), float3(0,1,0), float3(0,0,-1), float3(0,0,1)}; - const int shadowDirectionIndex = GetShadowDirectionIndex(surface.position, light.m_position); - const int shadowIndex = UnpackShadowIndex(light, shadowDirectionIndex); + const int shadowCubemapFace = GetPointLightShadowCubemapFace(surface.position, light.m_position); + const int shadowIndex = UnpackPointLightShadowIndex(light, shadowCubemapFace); + litRatio *= ProjectedShadow::GetVisibility( shadowIndex, light.m_position, surface.position, - PointShadowDirections[shadowDirectionIndex], + PointLightShadowCubemapDirections[shadowCubemapFace], surface.normal); // Use backShadowRatio to carry thickness from shadow map for thick mode From 59077f068c54c74ea1b6de64dc9ea2b4fc4c0c71 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Wed, 28 Apr 2021 18:09:37 -0700 Subject: [PATCH 12/17] bit shifts instead of if else also comments --- .../Atom/Features/PBR/Lights/PointLight.azsli | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index 42eb4b81da..853d77e372 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -48,33 +48,14 @@ int GetPointLightShadowCubemapFace(const float3 targetPos, const float3 lightPos } } -int UnpackPointLightShadowIndex(const ViewSrg::PointLight light, const int i) +// PointLight::m_shadowIndices actually consists of uint16_t x 6 on the CPU, but visible as a uint32_t x 3 on the GPU. +// This function returns the proper uint16_t value given an input face in the range 0-5 +int UnpackPointLightShadowIndex(const ViewSrg::PointLight light, const int face) { - if (i == 0) - { - return light.m_shadowIndices[0] & 0xFFFF; - } - else if (i==1) - { - return (light.m_shadowIndices[0] >> 16) & 0xFFFF; - } - else if (i==2) - { - return (light.m_shadowIndices[1]) & 0xFFFF; - } - else if (i==3) - { - return (light.m_shadowIndices[1] >> 16) & 0xFFFF; - } - else if (i==4) - { - return (light.m_shadowIndices[2]) & 0xFFFF; - } - else - { - return (light.m_shadowIndices[2] >> 16) & 0xFFFF; - } -} + const int index = face >> 1; + const int shiftAmount = (face & 1) * 16; + return (light.m_shadowIndices[index] >> shiftAmount) & 0xFFFF; +} void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData) { From 738883a9b07b855d4e0f7ed81a433b2601e8e83f Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Fri, 30 Apr 2021 11:43:32 -0700 Subject: [PATCH 13/17] Kens feedback --- .../CoreLights/PointLightFeatureProcessor.cpp | 4 +++- .../Source/CoreLights/SphereLightDelegate.cpp | 18 +++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 5110674492..82f41afbee 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -231,6 +231,8 @@ namespace AZ void PointLightFeatureProcessor::UpdateShadow(LightHandle handle) { + constexpr float SqrtHalf = 0.707106781187f; // sqrt(0.5); + const auto& pointLight = m_pointLightData.GetData(handle.GetIndex()); for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { @@ -246,7 +248,7 @@ namespace AZ desc.m_transform = m_pointShadowTransforms[i]; desc.m_transform.SetTranslation(pointLight.m_position[0], pointLight.m_position[1], pointLight.m_position[2]); desc.m_aspectRatio = 1.0f; - desc.m_nearPlaneDistance = 0.0f; + desc.m_nearPlaneDistance = SqrtHalf * pointLight.m_bulbRadius; const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; if (invRadiusSquared <= 0.f) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index 7a74ad4c5c..e3cf1fac78 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -67,12 +67,16 @@ namespace AZ void SphereLightDelegate::SetEnableShadow(bool enabled) { Base::SetEnableShadow(enabled); - GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); + + if (GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); + } } void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); } @@ -80,7 +84,7 @@ namespace AZ void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); } @@ -88,7 +92,7 @@ namespace AZ void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); } @@ -96,7 +100,7 @@ namespace AZ void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); } @@ -104,7 +108,7 @@ namespace AZ void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); } @@ -112,7 +116,7 @@ namespace AZ void SphereLightDelegate::SetPcfMethod(PcfMethod method) { - if (GetShadowsEnabled()) + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method); } From cc15e0d489f5768bc681fd19958456d52c8e8b39 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Mon, 3 May 2021 13:19:53 -0700 Subject: [PATCH 14/17] Avoid alignment issue if it ever went to cbuffer --- .../Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli | 3 +-- .../Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli | 3 +-- .../Common/Assets/Shaders/LightCulling/LightCulling.azsl | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 6c4a6d2a36..aeb57259e7 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,8 +73,7 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint4 m_shadowIndices; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli index b392e07e06..2bccee4902 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli @@ -63,8 +63,7 @@ partial ShaderResourceGroup RayTracingSceneSrg float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint4 m_shadowIndices; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 398103a93f..41b42ca68b 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -59,8 +59,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint m_shadowIndices[3]; - uint m_padding; + uint4 m_shadowIndices; }; struct DiskLight From b5d62b9cf69b2c287396ffc56ed78d5eeeec45a4 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Tue, 4 May 2021 10:36:57 -0700 Subject: [PATCH 15/17] Better variables --- .../Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli | 3 ++- .../Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli | 3 ++- .../Common/Assets/Shaders/LightCulling/LightCulling.azsl | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index aeb57259e7..7a51d4c629 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -73,7 +73,8 @@ partial ShaderResourceGroup ViewSrg float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint4 m_shadowIndices; + uint3 m_shadowIndices; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli index 2bccee4902..2ae74466d6 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrg.azsli @@ -63,7 +63,8 @@ partial ShaderResourceGroup RayTracingSceneSrg float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; - uint4 m_shadowIndices; + uint3 m_shadowIndices; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl index 41b42ca68b..0327a723d6 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCulling.azsl @@ -59,7 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2. float3 m_rgbIntensityCandelas; float m_bulbRadius; - uint4 m_shadowIndices; + uint3 m_shadowIndices; + uint m_padding; }; struct DiskLight From a2d2a372202590f736de47e533fc013cb4c1e9db Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Tue, 4 May 2021 10:38:21 -0700 Subject: [PATCH 16/17] Better commenting and readability fixes --- .../CoreLights/PointLightFeatureProcessorInterface.h | 11 +++++++---- .../Source/CoreLights/PointLightFeatureProcessor.cpp | 7 ++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index aaffac6d5a..30d88cb839 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -26,13 +26,16 @@ namespace AZ struct PointLightData { AZStd::array m_position = {{0.0f, 0.0f, 0.0f}}; - float m_invAttenuationRadiusSquared = - 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. + + // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations. + float m_invAttenuationRadiusSquared = 0.0f; + AZStd::array m_rgbIntensity = {{0.0f, 0.0f, 0.0f}}; - float m_bulbRadius = 0.0f; // Radius of spherical light in meters. + + // Radius of spherical light in meters. + float m_bulbRadius = 0.0f; static const int NumShadowFaces = 6; - AZStd::array m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}}; uint32_t m_padding; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 82f41afbee..bb81c52b15 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -201,7 +201,7 @@ namespace AZ for (int i = 0; i < PointLightData::NumShadowFaces; ++i) { ShadowId shadowId = ShadowId(light.m_shadowIndices[i]); - if (shadowId.IsValid() && enabled == false) + if (shadowId.IsValid() && !enabled) { // Disable shadows m_shadowFeatureProcessor->ReleaseShadow(shadowId); @@ -209,7 +209,7 @@ namespace AZ light.m_shadowIndices[i] = shadowId.GetIndex(); m_deviceBufferNeedsUpdate = true; } - else if (shadowId.IsNull() && enabled == true) + else if (shadowId.IsNull() && enabled) { // Enable shadows light.m_shadowIndices[i] = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); @@ -244,7 +244,8 @@ namespace AZ } ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); - desc.m_fieldOfViewYRadians = DegToRad(91.0f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces + // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces + desc.m_fieldOfViewYRadians = DegToRad(91.0f); desc.m_transform = m_pointShadowTransforms[i]; desc.m_transform.SetTranslation(pointLight.m_position[0], pointLight.m_position[1], pointLight.m_position[2]); desc.m_aspectRatio = 1.0f; From c51e90d2243a69f096174fa18896f35b3880c918 Mon Sep 17 00:00:00 2001 From: Michael Riegger Date: Tue, 4 May 2021 12:12:27 -0700 Subject: [PATCH 17/17] Fix unused variable --- .../Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index 853d77e372..b28f0f1708 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -105,7 +105,7 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio; // Tranmission contribution - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0) * litRatio; + lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), backShadowRatio); // Adjust the light direcion for specular based on bulb size