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..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 @@ -13,6 +13,49 @@ #pragma once #include +#include + +// 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))); + 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; + } +} + +// 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) +{ + 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) { @@ -31,11 +74,38 @@ 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 int shadowCubemapFace = GetPointLightShadowCubemapFace(surface.position, light.m_position); + const int shadowIndex = UnpackPointLightShadowIndex(light, shadowCubemapFace); + + litRatio *= ProjectedShadow::GetVisibility( + shadowIndex, + light.m_position, + surface.position, + PointLightShadowCubemapDirections[shadowCubemapFace], + 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), backShadowRatio); // Adjust the light direcion for specular based on bulb size diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli index a7bb6cd3b1..fdf7ba92de 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli @@ -61,6 +61,8 @@ ShaderResourceGroup RayTracingSceneSrg : SRG_RayTracingScene float m_invAttenuationRadiusSquared; float3 m_rgbIntensity; float m_bulbRadius; + uint3 m_shadowIndices; + uint m_padding; }; StructuredBuffer m_pointLights; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 5404cf8b69..7a51d4c629 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; + 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 367720d13b..0327a723d6 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; + uint3 m_shadowIndices; + 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 68e1a01e56..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 @@ -1,19 +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 { @@ -22,9 +23,25 @@ namespace AZ namespace Render { + struct PointLightData + { + AZStd::array m_position = {{0.0f, 0.0f, 0.0f}}; + + // 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}}; + + // 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; + }; + //! 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); @@ -33,7 +50,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; @@ -48,6 +66,24 @@ 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; + //! 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.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/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 446b008921..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; @@ -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..bb81c52b15 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -44,6 +44,13 @@ namespace AZ PointLightFeatureProcessor::PointLightFeatureProcessor() : PointLightFeatureProcessorInterface() { + // 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() @@ -54,6 +61,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 +91,15 @@ namespace AZ { if (handle.IsValid()) { + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + 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(); @@ -148,6 +165,7 @@ namespace AZ lightPosition.StoreToFloat3(position.data()); m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); } void PointLightFeatureProcessor::SetAttenuationRadius(LightHandle handle, float attenuationRadius) @@ -177,5 +195,122 @@ namespace AZ return m_lightBufferHandler.GetElementCount(); } + void PointLightFeatureProcessor::SetShadowsEnabled(LightHandle handle, bool enabled) + { + auto& light = m_pointLightData.GetData(handle.GetIndex()); + for (int i = 0; i < PointLightData::NumShadowFaces; ++i) + { + ShadowId shadowId = ShadowId(light.m_shadowIndices[i]); + if (shadowId.IsValid() && !enabled) + { + // Disable shadows + m_shadowFeatureProcessor->ReleaseShadow(shadowId); + shadowId.Reset(); + light.m_shadowIndices[i] = shadowId.GetIndex(); + m_deviceBufferNeedsUpdate = true; + } + else if (shadowId.IsNull() && enabled) + { + // Enable shadows + light.m_shadowIndices[i] = m_shadowFeatureProcessor->AcquireShadow().GetIndex(); + + UpdateShadow(handle); + m_deviceBufferNeedsUpdate = true; + } + } + } + + void PointLightFeatureProcessor::SetPointData(LightHandle handle, const PointLightData& data) + { + AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetPointData()."); + + m_pointLightData.GetData(handle.GetIndex()) = data; + m_deviceBufferNeedsUpdate = true; + UpdateShadow(handle); + } + + 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) + { + ShadowId shadowId = ShadowId(pointLight.m_shadowIndices[i]); + if (shadowId.IsNull()) + { + // Early out if shadows are disabled. + return; + } + + ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc = m_shadowFeatureProcessor->GetShadowProperties(shadowId); + // 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; + desc.m_nearPlaneDistance = SqrtHalf * pointLight.m_bulbRadius; + + const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared; + if (invRadiusSquared <= 0.f) + { + AZ_Assert(false, "Attenuation radius must be set before using the light."); + return; + } + const float attenuationRadius = sqrtf(1.f / invRadiusSquared); + desc.m_farPlaneDistance = attenuationRadius + pointLight.m_bulbRadius; + + 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()); + for (int lightIndex = 0; lightIndex < PointLightData::NumShadowFaces; ++lightIndex) + { + 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) + { + 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 25b9bfa2cd..c0c377e960 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 { @@ -24,15 +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. - }; - class PointLightFeatureProcessor final : public PointLightFeatureProcessorInterface { @@ -58,18 +50,34 @@ 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; + 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; 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; bool m_deviceBufferNeedsUpdate = false; + + AZStd::array m_pointShadowTransforms; }; } // namespace Render } // namespace AZ 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..e3cf1fac78 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -63,5 +63,64 @@ namespace AZ debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity)); } } + + void SphereLightDelegate::SetEnableShadow(bool enabled) + { + Base::SetEnableShadow(enabled); + + if (GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); + } + } + + void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); + } + } + + void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); + } + } + + void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); + } + } + + void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); + } + } + + void SphereLightDelegate::SetPcfMethod(PcfMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + 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: