// There are two variants provided, one takes the texture and sampler explicitly so they can be statically passed in.
// The variant without resource parameters dynamically accesses the texture when sampling.
// Helper function to offset depth based on the surface normal and light direction.
// If the light hits the surface perpendicularly there will be no offset.
real3 EvalShadow_NormalBias( real3 normalWS, real NoL, real2 texelSize, real normalBias )
{
return max( texelSize.x, texelSize.y ) * normalBias * (1.0 - NoL) * normalWS;
}
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real3 posNDC, bool clampToRect )
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real3 posNDC, bool clampToRect, bool perspProj )
posCS.z -= sd.bias * posCS.w;
posNDC = posCS.xyz / posCS.w;
posNDC = perspProj ? (posCS.xyz / posCS.w) : posCS.xyz;
real3 posTC = float3( posNDC.xy * 0.5 + 0.5, posNDC.z );
real3 posTC = real3( posNDC.xy * 0.5 + 0.5, posNDC.z );
posTC.xy = clampToRect ? clamp( posTC.xy, sd.texelSizeRcp.zw*0.5, 1.0.xx - sd.texelSizeRcp.zw*0.5 ) : posTC.xy;
posTC.xy = posTC.xy * sd.scaleOffset.xy + sd.scaleOffset.zw;
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS )
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, bool perspProj )
return EvalShadow_GetTexcoords( sd, positionWS, ndc, false );
return EvalShadow_GetTexcoords( sd, positionWS, ndc, false, perspProj );
uint2 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real2 closestSampleNDC )
uint2 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real2 closestSampleNDC, bool perspProj )
real2 posNDC = posCS.xy / posCS.w;
real2 posNDC = perspProj ? (posCS.xy / posCS.w) : posCS.xy;
// calc TCs
real2 posTC = posNDC * 0.5 + 0.5;
closestSampleNDC = (floor(posTC * sd.textureSize.zw) + 0.5) * sd.texelSizeRcp.zw * 2.0 - 1.0.xx;
//
// Biasing functions
//
// helper function to get the world texel size
real EvalShadow_WorldTexelSize( ShadowData sd, float L_dist, bool perspProj )
{
return perspProj ? (sd.viewBias.w * L_dist) : sd.viewBias.w;
}
// used to scale down view biases to mitigate light leaking across shadowed corners
#if SHADOW_USE_VIEW_BIAS_SCALING != 0
real EvalShadow_ReceiverBiasWeightFlag( float flag )
{
return (asint( flag ) & 2) ? 1.0 : 0.0;
}
real3 EvalShadow_ReceiverBiasWeightPos( real3 positionWS, real3 normalWS, real3 L, real worldTexelSize )
{
#if SHADOW_USE_ONLY_VIEW_BASED_BIASING != 0
return positionWS + L * worldTexelSize;
#else
return positionWS + normalWS * worldTexelSize;
#endif
}
real EvalShadow_ReceiverBiasWeight( ShadowContext shadowContext, uint shadowAlgorithm, ShadowData sd, uint texIdx, uint sampIdx, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj )
{
real weight = 1.0;
[branch]
if( shadowAlgorithm <= GPUSHADOWALGORITHM_PCF_TENT_7X7 )
{
real3 pos = EvalShadow_ReceiverBiasWeightPos( positionWS, normalWS, L, EvalShadow_WorldTexelSize( sd, L_dist, perspProj ) );
real3 tcs = EvalShadow_GetTexcoords( sd, pos, perspProj );
weight = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, tcs, slice ).x;
}
return lerp( 1.0, weight, EvalShadow_ReceiverBiasWeightFlag( sd.nrmlBias.w ) );
}
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerComparisonState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj )
{
real3 pos = EvalShadow_ReceiverBiasWeightPos( positionWS, normalWS, L, EvalShadow_WorldTexelSize( sd, L_dist, perspProj ) );
return lerp( 1.0, SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, samp, EvalShadow_GetTexcoords( sd, pos, perspProj ), slice ).x, EvalShadow_ReceiverBiasWeightFlag( sd.nrmlBias.w ) );
}
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj )
{
// only used by PCF filters
return 1.0;
}
#else // SHADOW_USE_VIEW_BIAS_SCALING != 0
real EvalShadow_ReceiverBiasWeight( ShadowContext shadowContext, uint shadowAlgorithm, ShadowData sd, uint texIdx, uint sampIdx, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj ) { return 1.0; }
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerComparisonState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj ) { return 1.0; }
real EvalShadow_ReceiverBiasWeight(ShadowData sd, Texture2DArray tex, SamplerState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, real slice, bool perspProj) { return 1.0; }
#endif // SHADOW_USE_VIEW_BIAS_SCALING != 0
// receiver bias either using the normal to weight normal and view biases, or just light view biasing
float3 EvalShadow_ReceiverBias( ShadowData sd, float3 positionWS, float3 normalWS, float3 L, float L_dist, float lightviewBiasWeight, bool perspProj )
{
#if SHADOW_USE_ONLY_VIEW_BASED_BIASING != 0 // only light vector based biasing
float viewBiasScale = sd.viewBias.z;
return positionWS + L * viewBiasScale * lightviewBiasWeight * EvalShadow_WorldTexelSize( sd, L_dist, perspProj );
#else // biasing based on the angle between the normal and the light vector
float viewBiasMin = sd.viewBias.x;
float viewBiasMax = sd.viewBias.y;
float viewBiasScale = sd.viewBias.z;
float nrmlBiasMin = sd.nrmlBias.x;
float nrmlBiasMax = sd.nrmlBias.y;
float nrmlBiasScale = sd.nrmlBias.z;
float NdotL = saturate( dot( normalWS, L ) );
float sine = sqrt( saturate( 1.0 - NdotL * NdotL ) );
float tangent = abs( NdotL ) > 0.0 ? (sine / NdotL) : 0.0;
sine = clamp( sine * nrmlBiasScale, nrmlBiasMin, nrmlBiasMax );
tangent = clamp( tangent * viewBiasScale * lightviewBiasWeight, viewBiasMin, viewBiasMax );
float3 view_bias = L * tangent;
float3 normal_bias = normalWS * sine;
return positionWS + (normal_bias + view_bias) * EvalShadow_WorldTexelSize( sd, L_dist, perspProj );
#endif
}
// sample bias used by wide PCF filters to offset individual taps
#if SHADOW_USE_SAMPLE_BIASING != 0
real EvalShadow_SampleBiasFlag( float flag )
{
return (asint( flag ) & 1) ? 1.0 : 0.0;
}
float2 EvalShadow_SampleBias_Persp( ShadowData sd, float3 positionWS, float3 normalWS, float3 tcs )
{
float3 e1, e2;
if( abs( normalWS.z ) > 0.05 )
{
e1 = float3( 1.0, 0.0, -normalWS.x / normalWS.z );
e2 = float3( 0.0, 1.0, -normalWS.y / normalWS.z );
}
else if( abs( normalWS.y ) > 0.05 )
{
e1 = float3( 1.0, -normalWS.x / normalWS.y, 0.0 );
e2 = float3( 0.0, -normalWS.z / normalWS.y, 1.0 );
}
else
{
e1 = float3( -normalWS.y / normalWS.x, 1.0, 0.0 );
e2 = float3( -normalWS.z / normalWS.x, 0.0, 1.0 );
}
float4 p1 = mul( float4( positionWS + e1, 1.0 ), sd.worldToShadow );
float4 p2 = mul( float4( positionWS + e2, 1.0 ), sd.worldToShadow );
p1.xyz /= p1.w;
p2.xyz /= p2.w;
p1.xyz = float3( p1.xy * 0.5 + 0.5, p1.z );
p2.xyz = float3( p2.xy * 0.5 + 0.5, p2.z );
p1.xy = p1.xy * sd.scaleOffset.xy + sd.scaleOffset.zw;
p2.xy = p2.xy * sd.scaleOffset.xy + sd.scaleOffset.zw;
float3 nrm = cross( p1.xyz - tcs, p2.xyz - tcs );
nrm.xy /= -nrm.z;
return all( isfinite( nrm.xy ) ) ? (EvalShadow_SampleBiasFlag( sd.nrmlBias.w ) * nrm.xy) : 0.0.xx;
}
float2 EvalShadow_SampleBias_Ortho( ShadowData sd, float3 normalWS )
{
float3 nrm = mul( (float3x3) sd.shadowToWorld, normalWS );
nrm.x *= sd.scaleOffset.y;
nrm.y *= sd.scaleOffset.x;
nrm.z *= sd.scaleOffset.x * sd.scaleOffset.y;
nrm.xy /= -nrm.z;
return all( isfinite( nrm.xy ) ) ? (EvalShadow_SampleBiasFlag( sd.nrmlBias.w ) * nrm.xy) : 0.0.xx;
}
#else // SHADOW_USE_SAMPLE_BIASING != 0
float2 EvalShadow_SampleBias_Persp( ShadowData sd, float3 positionWS, float3 normalWS, float3 tcs ) { return 0.0.xx; }
float2 EvalShadow_SampleBias_Ortho( ShadowData sd, float3 normalWS ) { return 0.0.xx; }
#endif // SHADOW_USE_SAMPLE_BIASING != 0
//
real EvalShadow_PointDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real4 L )
real EvalShadow_PointDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist )
ShadowData sd = shadowContext.shadowDatas[index];
real3 biased_posWS = positionWS + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias );
real3 lpos = positionWS + L.xyz * L.w;
positionWS = biased_posWS;
int faceIndex = EvalShadow_GetCubeFaceID( lpos - biased_posWS ) + 1;
// load the right shadow data for the current face
sd = shadowContext.shadowDatas[index + faceIndex];
uint payloadOffset = GetPayloadOffset( sd );
// normal based bias
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS );
ShadowData sd = shadowContext.shadowDatas[index + EvalShadow_GetCubeFaceID( L ) + 1];
// sample the texture according to the given algorithm
// get the texture
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
// bias the world position
float recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, slice, true );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true );
// get the per sample bias
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC );
// sample the texture according to the given algorithm
uint payloadOffset = GetPayloadOffset( sd );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
#define EvalShadow_PointDepth_( _samplerType ) \
real EvalShadow_PointDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real4 L ) \
{ \
ShadowData sd = shadowContext.shadowDatas[index]; \
real3 biased_posWS = positionWS + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
real3 lpos = positionWS + L.xyz * L.w; \
positionWS = biased_posWS; \
int faceIndex = EvalShadow_GetCubeFaceID( lpos - biased_posWS ) + 1; \
/* load the right shadow data for the current face */ \
sd = shadowContext.shadowDatas[index + faceIndex]; \
uint payloadOffset = GetPayloadOffset( sd ); \
/* normal based bias */ \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
#define EvalShadow_PointDepth_( _samplerType ) \
real EvalShadow_PointDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist ) \
{ \
ShadowData sd = shadowContext.shadowDatas[index + EvalShadow_GetCubeFaceID( L ) + 1]; \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, slice, true ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true ); \
/* get the per sample bias */ \
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC ); \
/* sample the texture */ \
uint payloadOffset = GetPayloadOffset( sd ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, tex, samp ); \
}
EvalShadow_PointDepth_( SamplerComparisonState )
EvalShadow_PointDepth_( SamplerState )
// Spot shadows
//
real EvalShadow_SpotDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L )
real EvalShadow_SpotDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist )
uint payloadOffset = GetPayloadOffset( sd );
// normal based bias
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp.zw, sd.normalBias );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS );
real slice;
float slice;
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
// bias the world position
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, slice, true );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true );
// get the per sample bias
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC );
// sample the texture according to the given algorithm
uint payloadOffset = GetPayloadOffset( sd );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
#define EvalShadow_SpotDepth_( _samplerType ) \
real EvalShadow_SpotDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
{ \
/* load the right shadow data for the current face */ \
ShadowData sd = shadowContext.shadowDatas[index]; \
uint payloadOffset = GetPayloadOffset( sd ); \
/* normal based bias */ \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
#define EvalShadow_SpotDepth_( _samplerType ) \
real EvalShadow_SpotDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist ) \
{ \
/* load the right shadow data for the current face */ \
ShadowData sd = shadowContext.shadowDatas[index]; \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, slice, true ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true ); \
/* get the per sample bias */ \
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC ); \
/* sample the texture */ \
uint payloadOffset = GetPayloadOffset( sd ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, tex, samp ); \
}
EvalShadow_SpotDepth_( SamplerComparisonState )
EvalShadow_SpotDepth_( SamplerState )
// Punctual shadows for Point and Spot
//
real EvalShadow_PunctualDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real4 L )
real EvalShadow_PunctualDepth( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist )
// load the right shadow data for the current face
int faceIndex = 0;
UnpackShadowType( sd.shadowType, shadowType );
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
// load the right shadow data for the current face
{
real3 biased_posWS = positionWS + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias );
real3 lpos = positionWS + L.xyz * L.w;
positionWS = biased_posWS;
faceIndex = EvalShadow_GetCubeFaceID( lpos - biased_posWS ) + 1;
}
else
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias );
sd = shadowContext.shadowDatas[index + faceIndex];
uint payloadOffset = GetPayloadOffset( sd );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS );
// sample the texture according to the given algorithm
sd = shadowContext.shadowDatas[index + EvalShadow_GetCubeFaceID( L ) + 1];
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
// bias the world position
float recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, slice, true );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true );
// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true );
// get the per sample bias
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC );
// sample the texture according to the given algorithm
uint payloadOffset = GetPayloadOffset( sd );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
#define EvalShadow_PunctualDepth_( _samplerType ) \
real EvalShadow_PunctualDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real4 L ) \
{ \
/* load the right shadow data for the current face */ \
int faceIndex = 0; \
/* get the shadow type */ \
ShadowData sd = shadowContext.shadowDatas[index]; \
uint shadowType; \
UnpackShadowType( sd.shadowType, shadowType ); \
\
[branch] \
if( shadowType == GPUSHADOWTYPE_POINT ) \
{ \
real3 biased_posWS = positionWS + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
real3 lpos = positionWS + L.xyz * L.w; \
positionWS = biased_posWS; \
faceIndex = EvalShadow_GetCubeFaceID( lpos - biased_posWS ) + 1; \
} \
else \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
\
sd = shadowContext.shadowDatas[index + faceIndex]; \
uint payloadOffset = GetPayloadOffset( sd ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
#define EvalShadow_PunctualDepth_( _samplerType ) \
real EvalShadow_PunctualDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L, real L_dist ) \
{ \
int faceIndex = 0; \
/* get the shadow type */ \
ShadowData sd = shadowContext.shadowDatas[index]; \
uint shadowType; \
UnpackShadowType( sd.shadowType, shadowType ); \
\
/* load the right shadow data for the current face */ \
[branch] \
if( shadowType == GPUSHADOWTYPE_POINT ) \
sd = shadowContext.shadowDatas[index + EvalShadow_GetCubeFaceID( L ) + 1]; \
\
float slice; \
UnpackShadowmapId( sd.id, slice ); \
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, slice, true ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true ); \
/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true ); \
/* get the per sample bias */ \
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC ); \
/* sample the texture */ \
uint payloadOffset = GetPayloadOffset( sd ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, tex, samp ); \
}
EvalShadow_PunctualDepth_( SamplerComparisonState )
EvalShadow_PunctualDepth_( SamplerState )
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// sample the texture
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, 1.0, slice, false );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true, false );
// sample the texture
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
real shadow1 = 1.0;
// evaluate the first cascade
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
real shadow1 = 1.0;
shadowSplitIndex++;
if( shadowSplitIndex < kMaxShadowCascades )
if( alpha > 0.0 )
{
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false );
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false );
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false, false );
sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
}
}
shadow = lerp( shadow, shadow1, alpha );
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
\
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, 1.0, slice, false ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
real shadow1 = 1.0; \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true, false ); \
/* evalute the first cascade */ \
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
real shadow1 = 1.0; \
\
shadowSplitIndex++; \
if( shadowSplitIndex < kMaxShadowCascades ) \
if( alpha > 0.0 ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false ); \
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false, false ); \
sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sampleBias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// get texture description
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, 1.0, slice, false );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true, false );
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 );
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz;
if( shadowSplitIndex < nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) )
{
sd = shadowContext.shadowDatas[index + 1 + nextSplit];
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[nextSplit] * sd.texelSizeRcp.zw, sd.normalBias );
posTC = EvalShadow_GetTexcoords( sd, positionWS );
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false );
posTC = EvalShadow_GetTexcoords( sd, positionWS, false );
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithm, texIdx, sampIdx );
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha );
}
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
\
/* get texture description */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, 1.0, slice, false ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false ); \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true, false ); \
\
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 ); \
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz; \
if( shadowSplitIndex != nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + nextSplit]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[nextSplit] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, false ); \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha ); \
} \
\
sd = shadowContext.shadowDatas[index + faceIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
uint texIdx, sampIdx;
sd = shadowContext.shadowDatas[index + faceIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
float slice;
ShadowData sd = shadowContext.shadowDatas[index];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
uint texIdx, sampIdx;
ShadowData sd = shadowContext.shadowDatas[index];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
float slice;
sd = shadowContext.shadowDatas[index + faceIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
uint texIdx, sampIdx;
sd = shadowContext.shadowDatas[index + faceIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
// load the texel
float slice;
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, false );
// load the texel
uint texIdx, sampIdx;
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
real4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, false );
// load the texel
uint texIdx, sampIdx;