From 90bf2520be0a0c23d34590593e94f0907349b88c Mon Sep 17 00:00:00 2001 From: Santi Paprika Date: Fri, 10 Dec 2021 13:57:04 +0100 Subject: [PATCH] Add and expose distance attenuation to compensate low-res shadow maps Signed-off-by: Santi Paprika --- .../Materials/Types/EnhancedPBR.materialtype | 15 ++++++++++++++- .../Materials/Types/EnhancedPBR_Common.azsli | 1 + .../Materials/Types/EnhancedPBR_ForwardPass.azsl | 3 +++ .../Common/Assets/Materials/Types/Skin.azsl | 3 +++ .../Assets/Materials/Types/Skin.materialtype | 15 ++++++++++++++- .../Assets/Materials/Types/Skin_Common.azsli | 1 + .../Atom/Features/PBR/Lighting/LightingData.azsli | 3 +++ .../Features/PBR/Lights/DirectionalLight.azsli | 10 ++++++++-- .../Atom/Features/PBR/Lights/DiskLight.azsli | 7 ++++++- .../Atom/Features/PBR/Lights/PointLight.azsli | 8 +++++++- 10 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index ef1d2539f6..31f8bd3c32 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -1239,7 +1239,7 @@ { "name": "angleOffset", "displayName": " Angle Offset", - "description": "Angle to accept below (N . L = 0) in scattering through thin objects", + "description": "cosine of angle to extend below (N . L = 0) in scattering through thin objects", "type": "float", "defaultValue": 0.1, "min": -1.0, @@ -1249,6 +1249,19 @@ "name": "m_angleOffset" } }, + { + "name": "distanceAttenuation", + "displayName": " Distance Attenuation", + "description": "Attenuation applied to hide artifacts due to low-res shadow maps (e.g. objects far to the camera when using directional lights or objects far to the light when using sphere/disk lights", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 10.0, + "connection": { + "type": "ShaderInput", + "name": "m_distanceAttenuation" + } + }, { "name": "transmissionScale", "displayName": " Scale", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli index 98f091cb12..7c791e1cd0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli @@ -102,6 +102,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial uint m_transmissionThicknessMapUvIndex; float m_shrinkFactor; float m_angleOffset; + float m_distanceAttenuation; } // Callback function for ParallaxMapping.azsli diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index bc660979f6..e35941c623 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -283,6 +283,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // Shrink (absolute) offset towards the normal opposite direction to ensure correct shadow map projection lightingData.shrinkFactor = MaterialSrg::m_shrinkFactor; + // Attenuation applied to hide artifacts due to low-res shadow maps + lightingData.distanceAttenuation = MaterialSrg::m_distanceAttenuation; + // ------- Clearcoat ------- // [GFX TODO][ATOM-14603]: Clean up the double uses of these clear coat flags diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl index 4908e736f4..ca02d496c5 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl @@ -349,6 +349,9 @@ PbrLightingOutput SkinPS_Common(VSOutput IN) // Shrink (absolute) offset towards the normal opposite direction to ensure correct shadow map projection lightingData.shrinkFactor = MaterialSrg::m_shrinkFactor; + // Attenuation applied to hide artifacts due to low-res shadow maps + lightingData.distanceAttenuation = MaterialSrg::m_distanceAttenuation; + // ------- Occlusion ------- lightingData.diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 33b07bb86b..fa190657c0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -653,7 +653,7 @@ { "name": "angleOffset", "displayName": " Angle Offset", - "description": "Angle to accept below (N . L = 0) in scattering through thin objects", + "description": "cosine of angle to extend below (N . L = 0) in scattering through thin objects", "type": "float", "defaultValue": 0.1, "min": -1.0, @@ -663,6 +663,19 @@ "name": "m_angleOffset" } }, + { + "name": "distanceAttenuation", + "displayName": " Distance Attenuation", + "description": "Attenuation applied to hide artifacts due to low-res shadow maps (e.g. objects far to the camera when using directional lights or objects far to the light when using sphere/disk lights", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 10.0, + "connection": { + "type": "ShaderInput", + "name": "m_distanceAttenuation" + } + }, { "name": "transmissionScale", "displayName": " Scale", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_Common.azsli index 1fa2039c72..2ec1e6e8dc 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_Common.azsli @@ -73,6 +73,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial uint m_transmissionThicknessMapUvIndex; float m_shrinkFactor; float m_angleOffset; + float m_distanceAttenuation; Texture2D m_wrinkle_baseColor_texture1; Texture2D m_wrinkle_baseColor_texture2; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli index 8f3bca703e..cc55c4796e 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli @@ -37,6 +37,9 @@ class LightingData // Shrink (absolute) offset towards the normal opposite direction to ensure correct shadow map projection float shrinkFactor; + // Attenuation applied to hide artifacts due to low-res shadow maps + float distanceAttenuation; + // Normalized direction from surface to camera float3 dirToCamera; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli index 0b48094bbf..ffac82232f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli @@ -18,7 +18,7 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData) // Shadowed check const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight; float litRatio = 1.0f; - + float camToSurfDist = distance(ViewSrg::m_worldPosition, surface.position); // Transmission distance inside object float transmissionDistance = 0.0f; @@ -84,7 +84,13 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData) lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight) * currentLitRatio; lightingData.specularLighting += GetSpecularLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight) * currentLitRatio; - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight, currentTransmissionDistance); + + float3 backLighting = GetBackLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight, currentTransmissionDistance); + + // Attenuation applied to hide artifacts due to low-res shadow maps (might need some work in the future) + float attenuation = 1.0 / pow(max(1.0, camToSurfDist/2.0), lightingData.distanceAttenuation + 1.0); + + lightingData.translucentBackLighting += backLighting * attenuation; } // Add debug coloring for directional light shadow diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli index fbef38595d..209a6af823 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli @@ -114,8 +114,13 @@ void ApplyDiskLight(ViewSrg::DiskLight light, Surface surface, inout LightingDat lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, posToLightDir) * litRatio; // Transmission contribution - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, posToLightDir, transmissionDistance); + float3 backLighting = GetBackLighting(surface, lightingData, lightIntensity, posToLightDir, transmissionDistance); + // Attenuation applied to hide artifacts due to low-res shadow maps (might need some work in the future) + float attenuation = 1.0 / pow(max(1.0, sqrt(distanceToLight2)), lightingData.distanceAttenuation + 1.0); + + lightingData.translucentBackLighting += backLighting * attenuation; + // Adjust the light direction for specular based on disk size // Calculate the reflection off the normal from the view direction 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 a7b6b822c9..2eb815410d 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 @@ -67,6 +67,7 @@ uint ComputeShadowIndex(const ViewSrg::PointLight light, const Surface surface) void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData) { float3 posToLight = light.m_position - surface.position; + float posToLightDist = length(posToLight); float d2 = dot(posToLight, posToLight); // light distance squared float falloff = d2 * light.m_invAttenuationRadiusSquared; @@ -112,7 +113,12 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio; // Transmission contribution - lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), transmissionDistance); + float3 backLighting = GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), transmissionDistance); + + // Attenuation applied to hide artifacts due to low-res shadow maps (might need some work in the future) + float attenuation = 1.0 / pow(max(1.0, posToLightDist), lightingData.distanceAttenuation + 1.0); + + lightingData.translucentBackLighting += backLighting * attenuation; // Adjust the light direcion for specular based on bulb size