Thin transmission mode fix for directional lights
Signed-off-by: Santi Paprika <santi.gonzalez.cs@gmail.com>
This commit is contained in:
@@ -92,6 +92,7 @@ struct VSOutput
|
||||
float3 m_bitangent : BITANGENT;
|
||||
float3 m_worldPosition : UV0;
|
||||
float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV4;
|
||||
float3 m_shrinkedShadowCoords[ViewSrg::MaxCascadeCount] : UV9;
|
||||
|
||||
// Extended fields (only referenced in this azsl file)...
|
||||
float2 m_uv[UvSetCount] : UV1;
|
||||
@@ -137,6 +138,14 @@ VSOutput SkinVS(VSInput IN)
|
||||
|
||||
VertexHelper(IN, OUT, worldPosition, false);
|
||||
|
||||
// Fetch shadow coords for shrinked world position (used in thin transmission materials)
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
shadowIndex,
|
||||
worldPosition - 0.005 * OUT.m_normal,
|
||||
OUT.m_normal,
|
||||
OUT.m_shrinkedShadowCoords);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -336,6 +345,7 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
|
||||
|
||||
// Directional light shadow coordinates
|
||||
lightingData.shadowCoords = IN.m_shadowCoords;
|
||||
lightingData.shrinkedShadowCoords = IN.m_shrinkedShadowCoords;
|
||||
|
||||
// Diffuse and Specular response (used in IBL calculations)
|
||||
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
|
||||
|
||||
@@ -16,24 +16,26 @@
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
// Analytical integation (approximation) of diffusion profile over radius, could be replaced by other pre integrated kernels
|
||||
// such as sum of Gaussian
|
||||
// such as sum of Gaussian (see T(s))
|
||||
float3 TransmissionKernel(float t, float3 s)
|
||||
{
|
||||
float3 exponent = s * t;
|
||||
return 0.25 * (1.0 / exp(exponent) + 3.0 / exp(exponent / 3.0));
|
||||
}
|
||||
|
||||
float ThinObjectFalloff(const float3 surfaceNormal, const float3 dirToLight)
|
||||
// Analytical integation (approximation) of diffusion profile over radius, could be precomputed in a LUT
|
||||
float3 T(float s)
|
||||
{
|
||||
const float ndl = saturate(dot(-surfaceNormal, dirToLight));
|
||||
|
||||
// ndl works decently well but it can produce a harsh discontinuity in the area just before
|
||||
// the shadow starts appearing on objects like cylinder and tubes.
|
||||
// Smoothing out ndl does a decent enough job of removing this artifact.
|
||||
return smoothstep(0, 1, ndl * ndl);
|
||||
// dipoles and multipoles are approximated with sums of a small number of Gaussians with variable weights and variances
|
||||
return float3(0.233, 0.455, 0.649) * exp(-s*s/0.0064) +
|
||||
float3(0.1, 0.336, 0.344) * exp(-s*s/0.0484) +
|
||||
float3(0.118, 0.198, 0.0) * exp(-s*s/0.187) +
|
||||
float3(0.113, 0.007, 0.007) * exp(-s*s/0.567) +
|
||||
float3(0.358, 0.004, 0.0) * exp(-s*s/1.99) +
|
||||
float3(0.078, 0.0, 0.0) * exp(-s*s/7.41);
|
||||
}
|
||||
|
||||
float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight, float shadowRatio)
|
||||
float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight, float transmissionDistance)
|
||||
{
|
||||
float3 result = float3(0.0, 0.0, 0.0);
|
||||
float thickness = 0.0;
|
||||
@@ -49,7 +51,7 @@ float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightI
|
||||
// https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/
|
||||
|
||||
{
|
||||
thickness = max(shadowRatio, surface.transmission.thickness);
|
||||
thickness = max(transmissionDistance, surface.transmission.thickness);
|
||||
float transmittance = pow( saturate( dot( lightingData.dirToCamera, -normalize( dirToLight + surface.normal * transmissionParams.z ) ) ), transmissionParams.y ) * transmissionParams.w;
|
||||
float lamberAttenuation = exp(-thickness * transmissionParams.x) * saturate(1.0 - thickness);
|
||||
result = transmittance * lamberAttenuation * lightIntensity;
|
||||
@@ -57,18 +59,21 @@ float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightI
|
||||
break;
|
||||
|
||||
case TransmissionMode::ThinObject:
|
||||
// Thin object mode, using thin-film assumption proposed by Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency"
|
||||
// Thin object mode, based on Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency"
|
||||
// http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf
|
||||
|
||||
float litRatio = 1.0 - shadowRatio;
|
||||
if (litRatio)
|
||||
|
||||
{
|
||||
const float thickness = surface.transmission.thickness * transmissionParams.w;
|
||||
const float3 invScattering = rcp(transmissionParams.xyz);
|
||||
const float falloff = ThinObjectFalloff(surface.normal, dirToLight);
|
||||
result = TransmissionKernel(thickness, invScattering) * falloff * lightIntensity * litRatio;
|
||||
}
|
||||
// Irradiance arround surface point.
|
||||
// Begin the transmittance dot product slightly before it would with the regular dot(N,L)
|
||||
float E = max(0.30 + dot(-surface.normal, dirToLight), 0.0);
|
||||
|
||||
// Transmission distance computed from shadowmaps modulated by editor-exposed parameters
|
||||
float s = transmissionDistance * surface.transmission.thickness * (20 - transmissionParams.w) * 10;
|
||||
|
||||
// Albedo at front (surface point) is used to approximate irradiance at the back of the object
|
||||
// See observation 4 in [Jimenez J. et al, 2010]
|
||||
result = T(s) * lightIntensity * surface.albedo * E;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -28,6 +28,9 @@ class LightingData
|
||||
// Direction light shadow coordinates
|
||||
float3 shadowCoords[ViewSrg::MaxCascadeCount];
|
||||
|
||||
// Direction light shadow coordinates for shrinked positions
|
||||
float3 shrinkedShadowCoords[ViewSrg::MaxCascadeCount];
|
||||
|
||||
// Normalized direction from surface to camera
|
||||
float3 dirToCamera;
|
||||
|
||||
|
||||
+19
-6
@@ -18,7 +18,9 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
|
||||
// Shadowed check
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
float litRatio = 1.0f;
|
||||
float transmissionDistance = 0.0f;
|
||||
float backShadowRatio = 0.0f;
|
||||
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
litRatio = DirectionalLightShadow::GetVisibility(
|
||||
@@ -30,6 +32,12 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
|
||||
if (o_transmission_mode == TransmissionMode::ThickObject)
|
||||
{
|
||||
backShadowRatio = DirectionalLightShadow::GetThickness(shadowIndex, lightingData.shadowCoords);
|
||||
}
|
||||
else if (o_transmission_mode == TransmissionMode::ThinObject)
|
||||
{
|
||||
// Use shrinked positions for thin object transmission to ensure they fall onto the object when querying
|
||||
// the depth from the shadow map
|
||||
transmissionDistance = DirectionalLightShadow::GetThickness(shadowIndex, lightingData.shrinkedShadowCoords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,21 +58,26 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
|
||||
// [GFX TODO][ATOM-2012] care of multiple directional light
|
||||
// Currently shadow check is done only for index == shadowIndex.
|
||||
float currentLitRatio = 1.0f;
|
||||
float currentBackShadowRatio = 1.0f;
|
||||
float currentTransmissionParameter = 1.0f;
|
||||
if (o_enableShadows)
|
||||
{
|
||||
currentLitRatio = (index == shadowIndex) ? litRatio : 1.;
|
||||
|
||||
currentBackShadowRatio = 1.0 - currentLitRatio;
|
||||
bool activeLight = index == shadowIndex;
|
||||
currentLitRatio = activeLight ? litRatio : 1.;
|
||||
if (o_transmission_mode == TransmissionMode::ThickObject)
|
||||
{
|
||||
currentBackShadowRatio = (index == shadowIndex) ? backShadowRatio : 0.;
|
||||
// Back shadow ratio (add contribution only if current directional light is the active one for shadows)
|
||||
currentTransmissionParameter = activeLight ? backShadowRatio : 0.;
|
||||
}
|
||||
else if (o_transmission_mode == TransmissionMode::ThinObject)
|
||||
{
|
||||
// Transmission distance (add contribution only if current directional light is the active one for shadows)
|
||||
currentTransmissionParameter = activeLight ? transmissionDistance : 9999.f;
|
||||
}
|
||||
}
|
||||
|
||||
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, currentBackShadowRatio);
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight, currentTransmissionParameter);
|
||||
}
|
||||
|
||||
// Add debug coloring for directional light shadow
|
||||
|
||||
Reference in New Issue
Block a user