Files
2026-08-09 04:23:10 -07:00

192 lines
7.0 KiB
C++

/*
==================================================================================
SAMPLE_SHADOW_BUFFER_PCF
in float4 shadowTexCoord;
out float shadow;
==================================================================================
*/
#template SAMPLE_SHADOW_BUFFER_PCF( shadow, shadowTexCoord )
{
#if defined( XBOX )
// The Xbox 360 does not implement percentage-closer-filtering (PCF) in hardware.
// Instead the following implements bilinear PCF between four point samples.
float3 texCoord = shadowTexCoord;
float2 texelXY = texCoord.xy * $shadowBufferResolution.x - _float2( 0.5 );
float2 floorXY = floor( texelXY );
float2 fracXY = texelXY - floorXY;
float step = $shadowBufferResolution.y;
float2 baseXY = ( floorXY + _float2( 0.5 ) ) * $shadowBufferResolution.y;
float4 samples;
samples.x = tex2D( $lightDepthMap, baseXY + float2( 0*step, 0*step ) ).x;
samples.y = tex2D( $lightDepthMap, baseXY + float2( 1*step, 0*step ) ).x;
samples.z = tex2D( $lightDepthMap, baseXY + float2( 1*step, 1*step ) ).x;
samples.w = tex2D( $lightDepthMap, baseXY + float2( 0*step, 1*step ) ).x;
float4 pcf = float4( greaterThanEqual( ( _float4( 1.0 ) - samples ), texCoord.zzzz ) );
float4 weights;
weights.x = ( 1.0 - fracXY.x ) * ( 1.0 - fracXY.y );
weights.y = ( fracXY.x ) * ( 1.0 - fracXY.y );
weights.z = ( fracXY.x ) * ( fracXY.y );
weights.w = ( 1.0 - fracXY.x ) * ( fracXY.y );
shadow = dot4( pcf, weights );
#else
shadow = shadow2Ddepth( $lightDepthCompareMap, shadowTexCoord );
#endif
}
#endtemplate
/*
==================================================================================
SAMPLE_SHADOW_BUFFER_4ROOKS_PCF
in float4 shadowTexCoord;
out float shadow;
==================================================================================
*/
#template SAMPLE_SHADOW_BUFFER_4ROOKS_PCF( shadow, shadowTexCoord )
{
float s = $shadowBufferResolution.y * 2.0;
float4 shadow4;
SAMPLE_SHADOW_BUFFER_PCF( shadow4.x, shadowTexCoord.xyz + s * float3( -0.375, -0.125, 0 ) );
SAMPLE_SHADOW_BUFFER_PCF( shadow4.y, shadowTexCoord.xyz + s * float3( -0.125, 0.375, 0 ) );
SAMPLE_SHADOW_BUFFER_PCF( shadow4.z, shadowTexCoord.xyz + s * float3( 0.125, -0.375, 0 ) );
SAMPLE_SHADOW_BUFFER_PCF( shadow4.w, shadowTexCoord.xyz + s * float3( 0.375, 0.125, 0 ) );
shadow = dot( shadow4, _float4( 0.25 ) );
}
#endtemplate
/*
==================================================================================
SAMPLE_VARIANCE_SHADOW_MAP
in float4 shadowTexCoord;
out float shadow;
$varianceShadowMapSettings.x = minimumVariance
$varianceShadowMapSettings.y = deltaScale
$varianceShadowMapSettings.z = bleedReduction
$varianceShadowMapSettings.w = 1.0 / ( 1.0 - bleedReduction )
==================================================================================
*/
#template SAMPLE_VARIANCE_SHADOW_MAP( shadow, shadowTexCoord )
{
// Fetch the moments.
float2 moments = tex2D( $lightDepthVarianceMap, shadowTexCoord.xy ).xy;
// Compute variance.
float variance = moments.y - ( moments.x * moments.x );
variance = max( variance, $varianceShadowMapSettings.x );
// Compute probabilistic upper bound.
float d = $varianceShadowMapSettings.y * saturate( shadowTexCoord.z - moments.x );
float p_max = saturate( variance / ( variance + d * d ) );
// Remove the [0, bleedReduction] tail and linearly rescale (bleedReduction, 1].
shadow = saturate( ( p_max - $varianceShadowMapSettings.z ) * $varianceShadowMapSettings.w );
}
#endtemplate
/*
==================================================================================
SAMPLE_POINT_LIGHT_SHADOW
in float4 shadowTexCoord;
out float shadow;
==================================================================================
*/
#template SAMPLE_POINT_LIGHT_SHADOW( shadow, shadowTexCoord )
{
// calculate the maximum absolute shadow texture coordinate
float3 absTexCoord = abs( shadowTexCoord.xyz );
float3 maxTexCoord = max( absTexCoord.xyz, max( absTexCoord.yzx, absTexCoord.zxy ) );
// create a vector with a 1.0 for the first largest absolute component and 0.0 for the other components
float4 axis;
axis.xyz = float3( greaterThanEqual( absTexCoord, maxTexCoord ) ); // set 1.0 for any component equal to the max
axis.yz = saturate( axis.yz - axis.xx - axis.xy ); // make sure only one component is set to 1.0
axis.w = 0.0;
// rotate the shadow texture coordinate from one of the cube sides to the flat shadow buffer
float4 rotate = axis.yxxy + axis.zwzw;
float4 flatTexCoord;
flatTexCoord.x = dot( rotate.xy, shadowTexCoord.xz );
flatTexCoord.y = dot( rotate.zw, shadowTexCoord.yz );
flatTexCoord.z = -maxTexCoord.x;
flatTexCoord.w = shadowTexCoord.w;
// calculate the bias for the shadow buffer sub-image that corresponds to this axis
float sBias = 0.5 + dot( axis.xyz, float3( greaterThanEqual( float3( 0, 0, 0 ), shadowTexCoord.xyz ) ) );
float tBias = 0.5 + dot( axis.xyz, float3( 0, 1, 2 ) );
float4 faceTexCoord;
faceTexCoord.x = dot4( flatTexCoord, $shadowProjectionS + sBias * $shadowProjectionQ );
faceTexCoord.y = dot4( flatTexCoord, $shadowProjectionT + tBias * $shadowProjectionQ );
faceTexCoord.z = dot4( flatTexCoord, $shadowProjectionR );
faceTexCoord.w = dot4( flatTexCoord, $shadowProjectionQ );
faceTexCoord.xyz /= faceTexCoord.w;
faceTexCoord.xy *= $shadowBufferResolution.z;
SAMPLE_SHADOW_BUFFER_4ROOKS_PCF( shadow, faceTexCoord );
}
#endtemplate
/*
==================================================================================
SAMPLE_SPOT_LIGHT_SHADOW
in float4 shadowTexCoord;
out float shadow;
==================================================================================
*/
#template SAMPLE_SPOT_LIGHT_SHADOW( shadow, shadowTexCoord )
{
float3 texCoord = shadowTexCoord.xyz / shadowTexCoord.w;
SAMPLE_SHADOW_BUFFER_4ROOKS_PCF( shadow, texCoord );
}
#endtemplate
/*
==================================================================================
SAMPLE_PARALLEL_LIGHT_SHADOW
in float4 shadowTexCoord;
in float viewZ;
out float shadow;
==================================================================================
*/
#template SAMPLE_PARALLEL_LIGHT_SHADOW( shadow, shadowTexCoord, viewZ )
{
float3 texCoord = shadowTexCoord.xyz / shadowTexCoord.w;
float sliceLOD = log2( max( 1.0, viewZ * $parallelLightSliceScale.x ) ) * $parallelLightSliceScale.z;
float sliceLODi = floor( sliceLOD );
float2 slice = min( float2( 3.0, 3.0 ), float2( sliceLODi, sliceLODi ) + float2( 0.0, 1.0 ) );
float2 stScale = exp2( - slice * $parallelLightSliceScale.y );
float4 stBias;
stBias.xy = 0.25 + frac( slice * 0.5 );
stBias.zw = 0.25 + floor( slice * 0.5 ) * 0.5;
float4 sliceTexCoords = texCoord.xxyy * stScale.xyxy + stBias;
float3 slice1TexCoord = float3( sliceTexCoords.x, sliceTexCoords.z, texCoord.z );
float3 slice2TexCoord = float3( sliceTexCoords.y, sliceTexCoords.w, texCoord.z );
float fraction = saturate( ( slice.y - sliceLOD ) * $parallelLightSliceScale.w );
float shadow1;
SAMPLE_SHADOW_BUFFER_4ROOKS_PCF( shadow1, slice1TexCoord );
float shadow2;
SAMPLE_SHADOW_BUFFER_4ROOKS_PCF( shadow2, slice2TexCoord );
shadow = lerp( shadow2, shadow1, fraction );
}
#endtemplate