浏览代码

Merge pull request #858 from Unity-Technologies/shadows-biasing

Shadows biasing
/main
GitHub 7 年前
当前提交
2376836c
共有 44 个文件被更改,包括 1186 次插入727 次删除
  1. 8
      ScriptableRenderPipeline/Core/CoreRP/Editor/CoreEditorUtils.cs
  2. 7
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/D3D11.hlsl
  3. 7
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/PSSL.hlsl
  4. 20
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/Validate.hlsl
  5. 7
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/XBoxOne.hlsl
  6. 8
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/AreaLighting.hlsl
  7. 10
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowBlurMoments.compute
  8. 74
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Shadow.hlsl
  9. 819
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl
  10. 262
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSampling.hlsl
  11. 36
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowTexFetch.hlsl
  12. 15
      ScriptableRenderPipeline/Core/CoreRP/Shadow/AdditionalShadowData.cs
  13. 144
      ScriptableRenderPipeline/Core/CoreRP/Shadow/Shadow.cs
  14. 25
      ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs
  15. 57
      ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs.hlsl
  16. 45
      ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowUtilities.cs
  17. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs
  18. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs
  19. 38
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/DeferredDirectionalShadow.compute
  20. 14
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl
  21. 16
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs
  22. 26
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl
  23. 18
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/Shadow.hlsl
  24. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-bigtile.compute
  25. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-clustered.compute
  26. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild.compute
  27. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/materialflags.compute
  28. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  29. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VBuffer.hlsl
  30. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/LayeredLit/LayeredLitData.hlsl
  31. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  32. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitDataDisplacement.hlsl
  33. 22
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.compute
  34. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.shader
  35. 48
      TestbedPipelines/Fptl/LightingTemplate.hlsl
  36. 9
      TestbedPipelines/Fptl/Shadow.hlsl
  37. 12
      TestbedPipelines/OnTileDeferredPipeline/Shaders/LightingTemplate.hlsl
  38. 9
      TestbedPipelines/OnTileDeferredPipeline/Shaders/Shadow.hlsl
  39. 26
      TestbedPipelines/OnTileDeferredPipeline/Shaders/UnityStandardForwardMobile.cginc
  40. 36
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowClear.shader
  41. 9
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowClear.shader.meta
  42. 24
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalShadowData.cs
  43. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalShadowData.cs.meta
  44. 8
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightShaderLibrary.meta

8
ScriptableRenderPipeline/Core/CoreRP/Editor/CoreEditorUtils.cs


material.shaderKeywords = null;
}
public static T[] GetAdditionalData<T>(params UnityEngine.Object[] targets)
public static T[] GetAdditionalData<T>(UnityEngine.Object[] targets, Action<T> initDefault = null)
where T : Component
{
// Handles multi-selection

for (int i = 0; i < data.Length; i++)
{
if (data[i] == null)
{
if (initDefault != null)
{
initDefault(data[i]);
}
}
}
return data;

7
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/D3D11.hlsl


#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;

7
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/PSSL.hlsl


#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;

20
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/Validate.hlsl


REQUIRE_DEFINED(INITIALIZE_OUTPUT)
*/
// Default values for things that have not been defined in the platform headers
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif

7
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/API/XBoxOne.hlsl


#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;

8
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/AreaLighting.hlsl


real e = sinSqSigma * cosOmega;
[branch]
UNITY_BRANCH
if (omega < HALF_PI - sigma)
{
// No horizon occlusion (case #1).

#else // Ref: Moving Frostbite to Physically Based Rendering, page 47 (2015, optimized).
real cosSqOmega = cosOmega * cosOmega; // y^2
[branch]
UNITY_BRANCH
if (cosSqOmega > sinSqSigma) // (y^2)>x
{
return saturate(sinSqSigma * cosOmega); // Clip[x*y,{0,1}]

real PolygonIrradiance(real4x3 L)
{
#ifdef APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
[unroll]
UNITY_UNROLL
for (uint i = 0; i < 4; i++)
{
L[i] = normalize(L[i]);

[unroll]
UNITY_UNROLL
for (uint edge = 0; edge < 4; edge++)
{
real3 V1 = L[edge];

10
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowBlurMoments.compute


int2 ldsIdx = (int2) groupThreadId.xy;
moment_t hblurredMoments[2];
[unroll]
UNITY_UNROLL
[unroll]
UNITY_UNROLL
for( int iw = 0; iw < 2; iw++ )
{
if( ldsIdx.x < LDS_STRIDE )

[loop]
UNITY_LOOP
for( uint is = 0; is < sampleCnt; is++ )
{
float depth = depthTex.Load( min( srcIdx, validSrc ), is ).x;

hblurredMoments[ih] = 0;
int2 idx = { groupThreadId.x + blurBorder, groupThreadId.y };
[loop]
UNITY_LOOP
for( int blurOffset = -blurBorder; blurOffset <= blurBorder; blurOffset++ )
{
hblurredMoments[ih] += readFromShared( int2( idx.x + blurOffset, idx.y ), LDS_STRIDE ) * blurWeights[abs( blurOffset )];

ldsIdx = (int2) groupThreadId.xy + int2( 0, blurBorder );
moment_t vblurredMoment = 0.0;
[unroll]
UNITY_UNROLL
for( int blurOffset = -blurBorder; blurOffset <= blurBorder; blurOffset++ )
{
vblurredMoment += readFromShared( int2( ldsIdx.x, ldsIdx.y + blurOffset ), THREADS ) * blurWeights[abs(blurOffset)];

74
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Shadow.hlsl


*/
/* Default values for optional defines:
#define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0 // Dynamic indexing only works on >= sm 5.1
#define SHADOW_OPTIMIZE_REGISTER_USAGE 0 // Redefine this as 1 in your ShadowContext.hlsl to optimize for register usage over instruction count
// #define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL // Enable custom implementations of GetPunctualShadowAttenuation. If not defined, a default implementation will be used.
// #define SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL // Enable custom implementations of GetDirectionalShadowAttenuation. If not defined, a default implementation will be used.
#define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0 // Dynamic indexing only works on >= sm 5.1
#define SHADOW_OPTIMIZE_REGISTER_USAGE 0 // Redefine this as 1 in your ShadowContext.hlsl to optimize for register usage over instruction count
#define SHADOW_USE_VIEW_BIAS_SCALING 0 // Enable view bias scaling to mitigate light leaking across edges. Uses the light vector if SHADOW_USE_ONLY_VIEW_BASED_BIASING is defined, otherwise uses the normal.
#define SHADOW_USE_ONLY_VIEW_BASED_BIASING 0 // Enable only light view vector based biasing. If undefined, biasing will be based on the normal and calling code must provide a valid normal.
#define SHADOW_USE_SAMPLE_BIASING 0 // Enable per sample biasing for wide multi-tap PCF filters. Incompatible with SHADOW_USE_ONLY_VIEW_BASED_BIASING.
#define SHADOW_USE_DEPTH_BIAS 0 // Enable clip space z biasing
// #define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL // Enable custom implementations of GetPunctualShadowAttenuation. If not defined, a default implementation will be used.
// #define SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL // Enable custom implementations of GetDirectionalShadowAttenuation. If not defined, a default implementation will be used.
#define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0
# define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0
#define SHADOW_OPTIMIZE_REGISTER_USAGE 0
# define SHADOW_OPTIMIZE_REGISTER_USAGE 0
#endif
#ifndef SHADOW_USE_VIEW_BIAS_SCALING
# define SHADOW_USE_VIEW_BIAS_SCALING 0
#endif
#ifndef SHADOW_USE_SAMPLE_BIAS
# define SHADOW_USE_SAMPLE_BIAS 0
#endif
#ifndef SHADOW_USE_SAMPLE_BIAS
# define SHADOW_USE_SAMPLE_BIAS 0
#endif
#ifndef SHADOW_USE_DEPTH_BIAS
# define SHADOW_USE_DEPTH_BIAS 0
#endif
#if SHADOW_USE_ONLY_VIEW_BASED_BIASING != 0
# if SHADOW_USE_SAMPLE_BIASING != 0
# pragma message "Shadows: SHADOW_USE_SAMPLE_BIASING was enabled together with SHADOW_USE_ONLY_VIEW_BASED_BIASING. Sample biasing requires the normal. Disabling SHADOW_USE_SAMPLE_BIASING again."
# undef SHADOW_USE_SAMPLE_BIASING
# define SHADOW_USE_SAMPLE_BIASING 0
# endif
# pragma warning(disable : 3557) // loop only executes for 1 iteration(s)
# pragma warning( disable : 3557 ) // loop only executes for 1 iteration(s)
#include "ShadowTexFetch.hlsl" // Resource sampling definitions (don't modify)
#include "ShadowTexFetch.hlsl" // Resource sampling definitions (don't modify)
StructuredBuffer<ShadowData> shadowDatas;
StructuredBuffer<int4> payloads;
SHADOWCONTEXT_DECLARE_TEXTURES( SHADOWCONTEXT_MAX_TEX2DARRAY, SHADOWCONTEXT_MAX_TEXCUBEARRAY, SHADOWCONTEXT_MAX_COMPSAMPLER, SHADOWCONTEXT_MAX_SAMPLER )
StructuredBuffer<ShadowData> shadowDatas;
StructuredBuffer<int4> payloads;
SHADOWCONTEXT_DECLARE_TEXTURES( SHADOWCONTEXT_MAX_TEX2DARRAY, SHADOWCONTEXT_MAX_TEXCUBEARRAY, SHADOWCONTEXT_MAX_COMPSAMPLER, SHADOWCONTEXT_MAX_SAMPLER )
void UnpackShadowmapId( uint shadowmapId, out uint texIdx, out uint sampIdx, out real slice )
{
texIdx = (shadowmapId >> 24) & 0xff;
sampIdx = (shadowmapId >> 16) & 0xff;
slice = (real)(shadowmapId & 0xffff);
}
void UnpackShadowmapId( uint shadowmapId, out real slice )
{
slice = (real)(shadowmapId & 0xffff);
}
void UnpackShadowType( uint packedShadowType, out uint shadowType, out uint shadowAlgorithm )
{
shadowType = packedShadowType >> 10;

}
// shadow sampling prototypes
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real4 L );
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real4 L, real2 positionSS );
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real3 L, real L_dist );
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real3 L, real L_dist, real2 positionSS );
// shadow sampling prototypes with screenspace info
real GetDirectionalShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real3 L );

#include "ShadowAlgorithms.hlsl" // engine default algorithms (don't modify)
#ifndef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real4 L )
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real3 L, real L_dist )
return EvalShadow_PunctualDepth(shadowContext, positionWS, normalWS, shadowDataIndex, L);
return EvalShadow_PunctualDepth( shadowContext, positionWS, normalWS, shadowDataIndex, L, L_dist );
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real4 L, real2 positionSS )
real GetPunctualShadowAttenuation( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int shadowDataIndex, real3 L, real L_dist, real2 positionSS )
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
#endif

return EvalShadow_CascadedDepth_Blend( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_CascadedDepth_Blend( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetDirectionalShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetDirectionalShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
}
#endif

819
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl


// 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 )
float4 EvalShadow_WorldToShadow( ShadowData sd, real3 positionWS, bool perspProj )
return max( texelSize.x, texelSize.y ) * normalBias * (1.0 - NoL) * normalWS;
}
if( perspProj )
{
positionWS = positionWS - sd.pos;
float3x3 view = { sd.rot0, sd.rot1, sd.rot2 };
positionWS = mul( view, positionWS );
}
else
{
float3x4 view;
view[0] = float4( sd.rot0, sd.pos.x );
view[1] = float4( sd.rot1, sd.pos.y );
view[2] = float4( sd.rot2, sd.pos.z );
positionWS = mul( view, float4( positionWS, 1.0 ) ).xyz;
}
float4x4 proj;
proj = 0.0;
proj._m00 = sd.proj[0];
proj._m11 = sd.proj[1];
proj._m22 = sd.proj[2];
proj._m23 = sd.proj[3];
if( perspProj )
proj._m32 = -1.0;
else
proj._m33 = 1.0;
return mul( proj, float4( positionWS, 1.0 ) );
}
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real3 posNDC, bool clampToRect )
real3 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real3 posNDC, bool perspProj )
real4 posCS = mul(real4(positionWS, 1.0), sd.worldToShadow);
posCS.z -= sd.bias * posCS.w;
posNDC = posCS.xyz / posCS.w;
real4 posCS = EvalShadow_WorldToShadow( sd, positionWS, perspProj );
posNDC = perspProj ? (posCS.xyz / posCS.w) : posCS.xyz;
real3 posTC = posNDC * 0.5 + 0.5;
posTC.xy = clampToRect ? clamp( posTC.xy, sd.texelSizeRcp.zw*0.5, 1.0.xx - sd.texelSizeRcp.zw*0.5 ) : posTC.xy;
real3 posTC = real3( posNDC.xy * 0.5 + 0.5, posNDC.z );
#if UNITY_REVERSED_Z
posTC.z = 1.0 - posTC.z;
#endif
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, perspProj );
uint2 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real2 closestSampleNDC )
uint2 EvalShadow_GetTexcoords( ShadowData sd, real3 positionWS, out real2 closestSampleNDC, bool perspProj )
real4 posCS = mul( real4( positionWS, 1.0 ), sd.worldToShadow );
real2 posNDC = posCS.xy / posCS.w;
real4 posCS = EvalShadow_WorldToShadow( sd, positionWS, perspProj );
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;

int EvalShadow_GetCubeFaceID( real3 sampleToLight )
//
// Biasing functions
//
// helper function to get the world texel size
real EvalShadow_WorldTexelSize( ShadowData sd, float L_dist, bool perspProj )
real3 lightToSample = -sampleToLight; // TODO: pass the correct (flipped) direction
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;
}
bool EvalShadow_ReceiverBiasWeightUseNormalFlag( float flag )
{
return (asint( flag ) & 4) ? true : false;
}
#ifdef INTRINSIC_CUBEMAP_FACE_ID
return (int)CubeMapFaceID(lightToSample);
real3 EvalShadow_ReceiverBiasWeightPos( real3 positionWS, real3 normalWS, real3 L, real worldTexelSize, real tolerance, bool useNormal )
{
#if SHADOW_USE_ONLY_VIEW_BASED_BIASING != 0
return positionWS + L * worldTexelSize * tolerance;
// TODO: use CubeMapFaceID() defined in Common.hlsl for all pipelines on all platforms.
real3 dir = sampleToLight;
real3 adir = abs(dir);
return positionWS + (useNormal ? normalWS : L) * worldTexelSize * tolerance;
#endif
}
real EvalShadow_ReceiverBiasWeight( ShadowContext shadowContext, uint shadowAlgorithm, ShadowData sd, uint texIdx, uint sampIdx, real3 positionWS, real3 normalWS, real3 L, real L_dist, bool perspProj )
{
real weight = 1.0;
UNITY_BRANCH
if( shadowAlgorithm <= GPUSHADOWALGORITHM_PCF_TENT_7X7 )
{
real3 pos = EvalShadow_ReceiverBiasWeightPos( positionWS, normalWS, L, EvalShadow_WorldTexelSize( sd, L_dist, perspProj ), sd.edgeTolerance, EvalShadow_ReceiverBiasWeightUseNormalFlag( sd.normalBias.w ) );
real3 tcs = EvalShadow_GetTexcoords( sd, pos, perspProj );
weight = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, tcs, sd.slice ).x;
}
return lerp( 1.0, weight, EvalShadow_ReceiverBiasWeightFlag( sd.normalBias.w ) );
}
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerComparisonState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, bool perspProj )
{
real3 pos = EvalShadow_ReceiverBiasWeightPos( positionWS, normalWS, L, EvalShadow_WorldTexelSize( sd, L_dist, perspProj ), sd.edgeTolerance, EvalShadow_ReceiverBiasWeightUseNormalFlag( sd.normalBias.w ) );
return lerp( 1.0, SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, samp, EvalShadow_GetTexcoords( sd, pos, perspProj ), sd.slice ).x, EvalShadow_ReceiverBiasWeightFlag( sd.normalBias.w ) );
}
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, 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, bool perspProj ) { return 1.0; }
real EvalShadow_ReceiverBiasWeight( ShadowData sd, Texture2DArray tex, SamplerComparisonState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, bool perspProj ) { return 1.0; }
real EvalShadow_ReceiverBiasWeight (ShadowData sd, Texture2DArray tex, SamplerState samp, real3 positionWS, real3 normalWS, real3 L, real L_dist, 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 normalBiasMin = sd.normalBias.x;
float normalBiasMax = sd.normalBias.y;
float normalBiasScale = sd.normalBias.z;
// +Z -Z
int faceIndex = dir.z > 0.0 ? CUBEMAPFACE_NEGATIVE_Z : CUBEMAPFACE_POSITIVE_Z;
float NdotL = dot( normalWS, L );
float sine = sqrt( saturate( 1.0 - NdotL * NdotL ) );
float tangent = abs( NdotL ) > 0.0 ? (sine / NdotL) : 0.0;
sine = clamp( sine * normalBiasScale, normalBiasMin, normalBiasMax );
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
}
// +X -X
if (adir.x > adir.y && adir.x > adir.z)
// 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.65 )
faceIndex = dir.x > 0.0 ? CUBEMAPFACE_NEGATIVE_X : CUBEMAPFACE_POSITIVE_X;
e1 = float3( 1.0, 0.0, -normalWS.x / normalWS.z );
e2 = float3( 0.0, 1.0, -normalWS.y / normalWS.z );
// +Y -Y
else if (adir.y > adir.x && adir.y > adir.z)
else if( abs( normalWS.y ) > 0.65 )
{
e1 = float3( 1.0, -normalWS.x / normalWS.y, 0.0 );
e2 = float3( 0.0, -normalWS.z / normalWS.y, 1.0 );
}
else
faceIndex = dir.y > 0.0 ? CUBEMAPFACE_NEGATIVE_Y : CUBEMAPFACE_POSITIVE_Y;
e1 = float3( -normalWS.y / normalWS.x, 1.0, 0.0 );
e2 = float3( -normalWS.z / normalWS.x, 0.0, 1.0 );
return faceIndex;
#endif
float4 p1 = EvalShadow_WorldToShadow( sd, positionWS + e1, true );
float4 p2 = EvalShadow_WorldToShadow( sd, positionWS + e2, true );
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 isfinite( nrm.xy ) ? (EvalShadow_SampleBiasFlag( sd.normalBias.w ) * nrm.xy) : 0.0.xx;
float2 EvalShadow_SampleBias_Ortho( ShadowData sd, float3 normalWS )
{
float3x3 view = float3x3( sd.rot0, sd.rot1, sd.rot2 );
float3 nrm = mul( view, normalWS );
nrm.x /= sd.proj[0];
nrm.y /= sd.proj[1];
nrm.z /= sd.proj[2];
nrm.x *= sd.scaleOffset.y;
nrm.y *= sd.scaleOffset.x;
nrm.z *= sd.scaleOffset.x * sd.scaleOffset.y;
nrm.xy /= -nrm.z;
return isfinite( nrm.xy ) ? (EvalShadow_SampleBiasFlag( sd.normalBias.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 + CubeMapFaceID( -L ) + 1];
// sample the texture according to the given algorithm
// get the texture
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
// bias the world position
float recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, 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, 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 */ \
real 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 + CubeMapFaceID( -L ) + 1]; \
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, 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, 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;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
// bias the world position
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, 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, 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 */ \
real 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]; \
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, 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, 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 );
[branch]
// load the right shadow data for the current face
UNITY_BRANCH
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;
sd.rot0 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot0;
sd.rot1 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot1;
sd.rot2 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot2;
sd.shadowToWorld = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].shadowToWorld;
sd.scaleOffset.zw = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].scaleOffset.zw;
sd.slice = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].slice;
else
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L.xyz ) ), sd.texelSizeRcp.zw, sd.normalBias );
sd = shadowContext.shadowDatas[index + faceIndex];
uint payloadOffset = GetPayloadOffset( sd );
uint texIdx, sampIdx;
UnpackShadowmapId( sd.id, texIdx, sampIdx );
// bias the world position
float recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, L_dist, true );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, L_dist, recvBiasWeight, true );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, true );
// get the per sample bias
real2 sampleBias = EvalShadow_SampleBias_Persp( sd, positionWS, normalWS, posTC );
uint texIdx, sampIdx;
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
uint payloadOffset = GetPayloadOffset( sd );
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, 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 */ \
real 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 */ \
UNITY_BRANCH \
if( shadowType == GPUSHADOWTYPE_POINT ) \
{ \
sd.rot0 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot0; \
sd.rot1 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot1; \
sd.rot2 = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].rot2; \
sd.shadowToWorld = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].shadowToWorld; \
sd.scaleOffset.zw = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].scaleOffset.zw; \
sd.slice = shadowContext.shadowDatas[index + CubeMapFaceID( -L ) + 1].slice; \
} \
\
/* bias the world position */ \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, L_dist, 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, shadowAlgorithm, tex, samp ); \
//
// Directional shadows (cascaded shadow map)

#define SHADOW_REPEAT_CASCADE( _x ) _x, _x, _x, _x
int EvalShadow_GetSplitSphereIndexForDirshadows( real3 positionWS, real4 dirShadowSplitSpheres[4], out real relDistance )
void EvalShadow_LoadCascadeData( ShadowContext shadowContext, uint index, inout ShadowData sd )
real3 fromCenter0 = positionWS.xyz - dirShadowSplitSpheres[0].xyz;
real3 fromCenter1 = positionWS.xyz - dirShadowSplitSpheres[1].xyz;
real3 fromCenter2 = positionWS.xyz - dirShadowSplitSpheres[2].xyz;
real3 fromCenter3 = positionWS.xyz - dirShadowSplitSpheres[3].xyz;
real4 distances2 = real4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
sd.shadowToWorld = shadowContext.shadowDatas[index].shadowToWorld;
sd.proj = shadowContext.shadowDatas[index].proj;
sd.pos = shadowContext.shadowDatas[index].pos;
sd.scaleOffset.zw = shadowContext.shadowDatas[index].scaleOffset.zw;
sd.slice = shadowContext.shadowDatas[index].slice;
sd.viewBias.w = shadowContext.shadowDatas[index].viewBias.w;
}
real4 dirShadowSplitSphereSqRadii;
dirShadowSplitSphereSqRadii.x = dirShadowSplitSpheres[0].w;
dirShadowSplitSphereSqRadii.y = dirShadowSplitSpheres[1].w;
dirShadowSplitSphereSqRadii.z = dirShadowSplitSpheres[2].w;
dirShadowSplitSphereSqRadii.w = dirShadowSplitSpheres[3].w;
int EvalShadow_GetSplitIndex( ShadowContext shadowContext, int index, real3 positionWS, out uint payloadOffset, out real alpha )
{
payloadOffset = shadowContext.shadowDatas[index].payloadOffset;
real4 weights = real4( distances2 < dirShadowSplitSphereSqRadii );
weights.yzw = saturate( weights.yzw - weights.xyz );
int i = 0;
real relDistance = 0.0;
real3 wposDir, splitSphere;
int idx = int( 4.0 - dot( weights, real4( 4.0, 3.0, 2.0, 1.0 ) ) );
relDistance = distances2[idx] / dirShadowSplitSphereSqRadii[idx];
return idx <= 3 ? idx : -1;
}
// find the current cascade
for( ; i < kMaxShadowCascades; i++, payloadOffset++ )
{
float4 sphere = asfloat( shadowContext.payloads[payloadOffset] );
wposDir = -sphere.xyz + positionWS;
float distSq = dot( wposDir, wposDir );
relDistance = distSq / sphere.w;
if( relDistance <= 1.0 )
{
splitSphere = sphere.xyz;
wposDir /= sqrt( distSq );
break;
}
}
int shadowSplitIndex = i < kMaxShadowCascades ? i : -1;
int EvalShadow_GetSplitSphereIndexForDirshadows( real3 positionWS, real4 dirShadowSplitSpheres[4] )
{
real relDist;
return EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDist );
}
payloadOffset = shadowContext.shadowDatas[index].payloadOffset + kMaxShadowCascades;
real3 cascadeDir = asfloat( shadowContext.payloads[payloadOffset].xyz );
payloadOffset++;
real border = asfloat( shadowContext.payloads[payloadOffset][shadowSplitIndex] );
payloadOffset++;
alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
real cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
uint EvalShadow_LoadSplitSpheres( ShadowContext shadowContext, int index, out real4 splitSpheres[4] )
{
uint offset = GetPayloadOffset( shadowContext.shadowDatas[index] );
splitSpheres[0] = asfloat( shadowContext.payloads[offset + 0] );
splitSpheres[1] = asfloat( shadowContext.payloads[offset + 1] );
splitSpheres[2] = asfloat( shadowContext.payloads[offset + 2] );
splitSpheres[3] = asfloat( shadowContext.payloads[offset + 3] );
return offset + 4;
return shadowSplitIndex;
real4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
real relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
real4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real border = borders[shadowSplitIndex];
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
ShadowData sd = shadowContext.shadowDatas[index];
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd );
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// sample the texture
uint texIdx, sampIdx;
UnpackShadowmapId( sd.id, texIdx, sampIdx );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
// Be careful of this code, we need it here before the if statement otherwise the compiler screws up optimizing dirShadowSplitSpheres VGPRs away
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz;
real3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( shadowSplitIndex+1, kMaxShadowCascades-1 )].xyz );
real3 wposDir = normalize( -splitSphere + positionWS );
real cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( shadowContext, shadowAlgorithm, sd, texIdx, sampIdx, positionWS, normalWS, L, 1.0, false );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false );
real3 posNDC;
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
// sample the texture
uint texIdx, sampIdx;
real 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;
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, false );
// evaluate the first cascade
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, 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 );
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd );
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false );
real3 posNDC;
UnpackShadowmapId( sd.id, slice );
sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
[branch]
UNITY_BRANCH
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sampleBias, shadowAlgorithm, texIdx, sampIdx );
}
}
shadow = lerp( shadow, shadow1, alpha );

real EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
real EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
/* load the right shadow data for the current face */ \
real4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
real relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
uint payloadOffset; \
real alpha; \
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha ); \
\
real4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
real4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
real border = borders[shadowSplitIndex]; \
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
ShadowData sd = shadowContext.shadowDatas[index]; \
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd ); \
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
real3 orig_pos = positionWS; \
real3 orig_pos = positionWS; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* Be careful of this code, we need it here before the if statement otherwise the compiler screws up optimizing dirShadowSplitSpheres VGPRs away */ \
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz; \
real3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( shadowSplitIndex+1, kMaxShadowCascades-1 )].xyz ); \
real3 wposDir = normalize( -splitSphere + positionWS ); \
real cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, 1.0, false ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false ); \
real3 posNDC; \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
/* sample the texture */ \
real 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, false ); \
/* evalute the first cascade */ \
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, 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 ); \
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd ); \
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false ); \
real3 posNDC; \
UnpackShadowmapId( sd.id, slice ); \
sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
[branch] \
UNITY_BRANCH \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sampleBias, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \

real EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
real EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
{ \
uint shadowAlgorithms[kMaxShadowCascades] = { SHADOW_REPEAT_CASCADE( shadowAlgorithm ) }; \
return EvalShadow_CascadedDepth_Blend( shadowContext, shadowAlgorithms, tex, samp, positionWS, normalWS, index, L ); \

real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L )
{
// load the right shadow data for the current face
real4 dirShadowSplitSpheres[kMaxShadowCascades];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
real relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha);
real4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real border = borders[shadowSplitIndex];
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
ShadowData sd = shadowContext.shadowDatas[index];
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd );
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// get texture description
uint texIdx, sampIdx;
UnpackShadowmapId( sd.id, texIdx, sampIdx );
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, false );
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false );
real3 posNDC;
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, false );
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 );
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz;
real3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( 3, shadowSplitIndex + 1 )].xyz );
real3 wposDir = normalize( -splitSphere + positionWS );
real cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 );
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 );
EvalShadow_LoadCascadeData( shadowContext, index + 1 + nextSplit, sd );
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false );
posTC = EvalShadow_GetTexcoords( sd, positionWS, false );
uint texIdx, sampIdx;
real 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, shadowAlgorithm, texIdx, sampIdx );
real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
real4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
real relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
uint payloadOffset; \
real alpha; \
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha ); \
\
\
real4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
real4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
real border = borders[shadowSplitIndex]; \
real alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
\
ShadowData sd = shadowContext.shadowDatas[index]; \
EvalShadow_LoadCascadeData( shadowContext, index + 1 + shadowSplitIndex, sd ); \
\
real3 orig_pos = positionWS; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
real3 orig_pos = positionWS; \
real recvBiasWeight = EvalShadow_ReceiverBiasWeight( sd, tex, samp, positionWS, normalWS, L, 1.0, false ); \
positionWS = EvalShadow_ReceiverBias( sd, positionWS, normalWS, L, 1.0, recvBiasWeight, false ); \
real3 posNDC; \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 ); \
real3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz; \
real3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[nextSplit].xyz ); \
real3 wposDir = normalize( -splitSphere + positionWS ); \
real cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
\
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, false ); \
\
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 ); \
\
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 ); \
EvalShadow_LoadCascadeData( shadowContext, index + 1 + nextSplit, sd ); \
positionWS = EvalShadow_ReceiverBias( sd, orig_pos, normalWS, L, 1.0, recvBiasWeight, false ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, false ); \
real 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, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
\
real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
\
real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \
{ \
uint shadowAlgorithms[kMaxShadowCascades] = { SHADOW_REPEAT_CASCADE( shadowAlgorithm ) }; \
return EvalShadow_CascadedDepth_Dither( shadowContext, shadowAlgorithms, tex, samp, positionWS, normalWS, index, L ); \

// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
// load the right shadow data for the current face
int faceIndex = EvalShadow_GetCubeFaceID( L ) + 1;
int faceIndex = CubeMapFaceID( -L ) + 1;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, sd.slice );
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
// load the right shadow data for the current face
int faceIndex = EvalShadow_GetCubeFaceID( L ) + 1;
int faceIndex = CubeMapFaceID( -L ) + 1;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
real slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, sd.slice, 0 ).x;
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

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 );
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, sd.slice );
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

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 );
real slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, sd.slice, 0 ).x;
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

uint shadowType;
UnpackShadowType( sd.shadowType, shadowType );
// load the right shadow data for the current face
int faceIndex = shadowType == GPUSHADOWTYPE_POINT ? (EvalShadow_GetCubeFaceID( L ) + 1) : 0;
int faceIndex = shadowType == GPUSHADOWTYPE_POINT ? (CubeMapFaceID( -L ) + 1) : 0;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, sd.slice );
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

uint shadowType;
UnpackShadowType( sd.shadowType, shadowType );
// load the right shadow data for the current face
int faceIndex = shadowType == GPUSHADOWTYPE_POINT ? (EvalShadow_GetCubeFaceID( L ) + 1) : 0;
int faceIndex = shadowType == GPUSHADOWTYPE_POINT ? (CubeMapFaceID( -L ) + 1) : 0;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, true );
real slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, sd.slice, 0 ).x;
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

real3 EvalShadow_GetClosestSample_Cascade( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real4 L )
{
// load the right shadow data for the current face
real4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
real relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
real4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, false );
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
UnpackShadowmapId( sd.id, texIdx, sampIdx );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, sd.slice );
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

real3 EvalShadow_GetClosestSample_Cascade( ShadowContext shadowContext, Texture2DArray tex, real3 positionWS, real3 normalWS, int index, real4 L )
{
// load the right shadow data for the current face
real4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
real relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
real4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
real4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy, false );
real slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
UnpackShadowmapId( sd.id, texIdx, sampIdx );
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, sd.slice, 0 ).x;
// reconstruct depth position
real4 closestWS = mul( closestNDC, sd.shadowToWorld );

262
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSampling.hlsl


//
// 1 tap PCF sampling
//
real SampleShadow_PCF_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, real bias, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_PCF_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 coord, float slice, uint texIdx, uint sampIdx )
#if SHADOW_USE_DEPTH_BIAS == 1
tcs.z += depthBias;
coord.z += depthBias;
#endif
return SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, tcs, slice ).x;
return SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, coord, slice ).x;
real SampleShadow_PCF_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, real bias, uint slice, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_PCF_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 coord, float slice, Texture2DArray tex, SamplerComparisonState compSamp )
#if SHADOW_USE_DEPTH_BIAS == 1
tcs.z += depthBias;
coord.z += depthBias;
#endif
return SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, tcs, slice );
return SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, coord, slice );
real SampleShadow_PCF_Tent_3x3( ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_PCF_Tent_3x3( ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, uint texIdx, uint sampIdx )
// TODO move this to shadow data to avoid the rcp?
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
real shadow = 0.0;
real fetchesWeights[4];

[loop] for (int i = 0; i < 4; i++)
UNITY_LOOP
for( int i = 0; i < 4; i++ )
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
real SampleShadow_PCF_Tent_3x3(ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_PCF_Tent_3x3(ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, Texture2DArray tex, SamplerComparisonState compSamp )
// TODO move this to shadow data to avoid the rcp?
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
real shadow = 0.0;
real fetchesWeights[4];

for (int i = 0; i < 4; i++)
{
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
}
return shadow;
}

//
real SampleShadow_PCF_Tent_5x5( ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_PCF_Tent_5x5( ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, uint texIdx, uint sampIdx )
// TODO move this to shadow data to avoid the rcp?
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
SampleShadow_ComputeSamples_Tent_5x5(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
[loop] for (int i = 0; i < 9; i++)
SampleShadow_ComputeSamples_Tent_5x5( shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV );
UNITY_LOOP
for( int i = 0; i < 9; i++ )
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
real SampleShadow_PCF_Tent_5x5(ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_PCF_Tent_5x5(ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, Texture2DArray tex, SamplerComparisonState compSamp )
// TODO move this to shadow data to avoid the rcp
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
SampleShadow_ComputeSamples_Tent_5x5(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
SampleShadow_ComputeSamples_Tent_5x5( shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV );
#if SHADOW_OPTIMIZE_REGISTER_USAGE == 1 && SHADOW_USE_SAMPLE_BIASING == 0
// the loops are only there to prevent the compiler form coalescing all 9 texture fetches which increases register usage
int i;
UNITY_LOOP
for( i = 0; i < 1; i++ )
{
shadow += fetchesWeights[ 0] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 0].xy, coord.z + dot( fetchesUV[ 0].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 1] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 1].xy, coord.z + dot( fetchesUV[ 1].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 2] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 2].xy, coord.z + dot( fetchesUV[ 2].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 3] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 3].xy, coord.z + dot( fetchesUV[ 3].xy - coord.xy, sampleBias ) ), slice ).x;
}
UNITY_LOOP
for( i = 0; i < 1; i++ )
{
shadow += fetchesWeights[ 4] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 4].xy, coord.z + dot( fetchesUV[ 4].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 5] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 5].xy, coord.z + dot( fetchesUV[ 5].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 6] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 6].xy, coord.z + dot( fetchesUV[ 6].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 7] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 7].xy, coord.z + dot( fetchesUV[ 7].xy - coord.xy, sampleBias ) ), slice ).x;
}
shadow += fetchesWeights[ 8] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 8].xy, coord.z + dot( fetchesUV[ 8].xy - coord.xy, sampleBias ) ), slice ).x;
#else
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
#endif
return shadow;
}

real SampleShadow_PCF_Tent_7x7( ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_PCF_Tent_7x7( ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, uint texIdx, uint sampIdx )
// TODO move this to shadow data to avoid the rcp
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
SampleShadow_ComputeSamples_Tent_7x7(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
[loop] for (int i = 0; i < 16; i++)
SampleShadow_ComputeSamples_Tent_7x7( shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV );
UNITY_LOOP
for( int i = 0; i < 16; i++ )
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
real SampleShadow_PCF_Tent_7x7(ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 coord, uint slice, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_PCF_Tent_7x7(ShadowContext shadowContext, inout uint payloadOffset, real4 textureSize, real4 texelSizeRcp, real3 coord, real2 sampleBias, float slice, Texture2DArray tex, SamplerComparisonState compSamp )
// TODO move this to shadow data to avoid the rcp
real4 shadowMapTexture_TexelSize = real4(texelSizeRcp.xy, rcp(texelSizeRcp.xy));
real4 shadowMapTexture_TexelSize = real4( texelSizeRcp.xy, textureSize.xy );
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
SampleShadow_ComputeSamples_Tent_7x7(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
SampleShadow_ComputeSamples_Tent_7x7( shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV );
// the loops are only there to prevent the compiler form coalescing all 16 texture fetches which increases register usage
[loop]
UNITY_LOOP
shadow += fetchesWeights[ 0] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 0].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 1] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 1].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 2] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 2].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 3] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 3].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 0] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 0].xy, coord.z + dot( fetchesUV[ 0].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 1] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 1].xy, coord.z + dot( fetchesUV[ 1].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 2] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 2].xy, coord.z + dot( fetchesUV[ 2].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 3] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 3].xy, coord.z + dot( fetchesUV[ 3].xy - coord.xy, sampleBias ) ), slice ).x;
[loop]
UNITY_LOOP
shadow += fetchesWeights[ 4] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 4].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 5] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 5].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 6] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 6].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 7] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 7].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 4] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 4].xy, coord.z + dot( fetchesUV[ 4].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 5] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 5].xy, coord.z + dot( fetchesUV[ 5].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 6] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 6].xy, coord.z + dot( fetchesUV[ 6].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 7] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 7].xy, coord.z + dot( fetchesUV[ 7].xy - coord.xy, sampleBias ) ), slice ).x;
[loop]
UNITY_LOOP
shadow += fetchesWeights[ 8] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 8].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 9] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 9].xy, coord.z ), slice ).x;
shadow += fetchesWeights[10] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[10].xy, coord.z ), slice ).x;
shadow += fetchesWeights[11] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[11].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 8] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 8].xy, coord.z + dot( fetchesUV[ 8].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[ 9] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[ 9].xy, coord.z + dot( fetchesUV[ 9].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[10] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[10].xy, coord.z + dot( fetchesUV[10].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[11] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[11].xy, coord.z + dot( fetchesUV[11].xy - coord.xy, sampleBias ) ), slice ).x;
[loop]
UNITY_LOOP
shadow += fetchesWeights[12] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[12].xy, coord.z ), slice ).x;
shadow += fetchesWeights[13] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[13].xy, coord.z ), slice ).x;
shadow += fetchesWeights[14] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[14].xy, coord.z ), slice ).x;
shadow += fetchesWeights[15] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[15].xy, coord.z ), slice ).x;
shadow += fetchesWeights[12] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[12].xy, coord.z + dot( fetchesUV[12].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[13] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[13].xy, coord.z + dot( fetchesUV[13].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[14] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[14].xy, coord.z + dot( fetchesUV[14].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[15] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[15].xy, coord.z + dot( fetchesUV[15].xy - coord.xy, sampleBias ) ), slice ).x;
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( fetchesUV[i].xy, coord.z + dot( fetchesUV[i].xy - coord.xy, sampleBias ) ), slice ).x;
}
#endif
return shadow;

// 9 tap adaptive PCF sampling
//
real SampleShadow_PCF_9tap_Adaptive( ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 tcs, real bias, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_PCF_9tap_Adaptive( ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 tcs, real2 sampleBias, float slice, uint texIdx, uint sampIdx )
{
real2 params = asfloat( shadowContext.payloads[payloadOffset].xy );
real depthBias = params.x;

texelSizeRcp *= filterSize;
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
// Terms0 are weights for the individual samples, the other terms are offsets in texel space
real4 vShadow3x3PCFTerms0 = real4( 20.0 / 267.0, 33.0 / 267.0, 55.0 / 267.0, 0.0 );

real4 v20Taps;
v20Taps.x = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.xy, tcs.z ), slice ).x; // 1 1
v20Taps.y = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.zy, tcs.z ), slice ).x; // -1 1
v20Taps.z = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.xw, tcs.z ), slice ).x; // 1 -1
v20Taps.w = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.zw, tcs.z ), slice ).x; // -1 -1
v20Taps.x = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.xy, tcs.z + dot( vShadow3x3PCFTerms1.xy, sampleBias ) ), slice ).x; // 1 1
v20Taps.y = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.zy, tcs.z + dot( vShadow3x3PCFTerms1.zy, sampleBias ) ), slice ).x; // -1 1
v20Taps.z = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.xw, tcs.z + dot( vShadow3x3PCFTerms1.xw, sampleBias ) ), slice ).x; // 1 -1
v20Taps.w = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms1.zw, tcs.z + dot( vShadow3x3PCFTerms1.zw, sampleBias ) ), slice ).x; // -1 -1
real flSum = dot( v20Taps.xyzw, real4( 0.25, 0.25, 0.25, 0.25 ) );
// fully in light or shadow? -> bail
if( ( flSum == 0.0 ) || ( flSum == 1.0 ) )

flSum *= vShadow3x3PCFTerms0.x * 4.0;
real4 v33Taps;
v33Taps.x = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms2.xz, tcs.z ), slice ).x; // 1 0
v33Taps.y = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms3.xz, tcs.z ), slice ).x; // -1 0
v33Taps.z = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms3.zy, tcs.z ), slice ).x; // 0 -1
v33Taps.w = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms2.zy, tcs.z ), slice ).x; // 0 1
v33Taps.x = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms2.xz, tcs.z + dot( vShadow3x3PCFTerms2.xz, sampleBias ) ), slice ).x; // 1 0
v33Taps.y = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms3.xz, tcs.z + dot( vShadow3x3PCFTerms3.xz, sampleBias ) ), slice ).x; // -1 0
v33Taps.z = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms3.zy, tcs.z + dot( vShadow3x3PCFTerms3.zy, sampleBias ) ), slice ).x; // 0 -1
v33Taps.w = SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, real3( tcs.xy + vShadow3x3PCFTerms2.zy, tcs.z + dot( vShadow3x3PCFTerms2.zy, sampleBias ) ), slice ).x; // 0 1
flSum += dot( v33Taps.xyzw, vShadow3x3PCFTerms0.yyyy );
flSum += SampleCompShadow_T2DA( shadowContext, texIdx, sampIdx, tcs, slice ).x * vShadow3x3PCFTerms0.z;

real SampleShadow_PCF_9tap_Adaptive(ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 tcs, real bias, uint slice, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_PCF_9tap_Adaptive(ShadowContext shadowContext, inout uint payloadOffset, real4 texelSizeRcp, real3 tcs, real2 sampleBias, float slice, Texture2DArray tex, SamplerComparisonState compSamp )
{
real2 params = asfloat( shadowContext.payloads[payloadOffset].xy );
real depthBias = params.x;

texelSizeRcp *= filterSize;
#if SHADOW_USE_DEPTH_BIAS == 1
#endif
// Terms0 are weights for the individual samples, the other terms are offsets in texel space
real4 vShadow3x3PCFTerms0 = real4(20.0 / 267.0, 33.0 / 267.0, 55.0 / 267.0, 0.0);

real4 v20Taps;
v20Taps.x = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.xy, tcs.z ), slice ).x; // 1 1
v20Taps.y = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.zy, tcs.z ), slice ).x; // -1 1
v20Taps.z = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.xw, tcs.z ), slice ).x; // 1 -1
v20Taps.w = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.zw, tcs.z ), slice ).x; // -1 -1
v20Taps.x = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.xy, tcs.z + dot( vShadow3x3PCFTerms1.xy, sampleBias ) ), slice ).x; // 1 1
v20Taps.y = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.zy, tcs.z + dot( vShadow3x3PCFTerms1.zy, sampleBias ) ), slice ).x; // -1 1
v20Taps.z = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.xw, tcs.z + dot( vShadow3x3PCFTerms1.xw, sampleBias ) ), slice ).x; // 1 -1
v20Taps.w = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms1.zw, tcs.z + dot( vShadow3x3PCFTerms1.zw, sampleBias ) ), slice ).x; // -1 -1
real flSum = dot( v20Taps.xyzw, real4( 0.25, 0.25, 0.25, 0.25 ) );
// fully in light or shadow? -> bail
if( ( flSum == 0.0 ) || ( flSum == 1.0 ) )

flSum *= vShadow3x3PCFTerms0.x * 4.0;
real4 v33Taps;
v33Taps.x = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms2.xz, tcs.z ), slice ).x; // 1 0
v33Taps.y = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms3.xz, tcs.z ), slice ).x; // -1 0
v33Taps.z = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms3.zy, tcs.z ), slice ).x; // 0 -1
v33Taps.w = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms2.zy, tcs.z ), slice ).x; // 0 1
v33Taps.x = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms2.xz, tcs.z + dot( vShadow3x3PCFTerms2.xz, sampleBias ) ), slice ).x; // 1 0
v33Taps.y = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms3.xz, tcs.z + dot( vShadow3x3PCFTerms3.xz, sampleBias ) ), slice ).x; // -1 0
v33Taps.z = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms3.zy, tcs.z + dot( vShadow3x3PCFTerms3.zy, sampleBias ) ), slice ).x; // 0 -1
v33Taps.w = SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, real3( tcs.xy + vShadow3x3PCFTerms2.zy, tcs.z + dot( vShadow3x3PCFTerms2.zy, sampleBias ) ), slice ).x; // 0 1
flSum += dot( v33Taps.xyzw, vShadow3x3PCFTerms0.yyyy );
flSum += SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, tcs, slice ).x * vShadow3x3PCFTerms0.z;

//
// 1 tap VSM sampling
//
real SampleShadow_VSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, uint texIdx, uint sampIdx )
real SampleShadow_VSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, uint texIdx, uint sampIdx )
{
#if UNITY_REVERSED_Z
real depth = 1.0 - tcs.z;

return ShadowMoments_ChebyshevsInequality( moments, depth, varianceBias, lightLeakBias );
}
real SampleShadow_VSM_1tap(ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, Texture2DArray tex, SamplerState samp )
real SampleShadow_VSM_1tap(ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, Texture2DArray tex, SamplerState samp )
{
#if UNITY_REVERSED_Z
real depth = 1.0 - tcs.z;

//
// 1 tap EVSM sampling
//
real SampleShadow_EVSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, uint texIdx, uint sampIdx, bool fourMoments )
real SampleShadow_EVSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, uint texIdx, uint sampIdx, bool fourMoments )
{
#if UNITY_REVERSED_Z
real depth = 1.0 - tcs.z;

real2 depthScale = evsmExponents * warpedDepth;
real2 minVariance = depthScale * depthScale * varianceBias;
[branch]
UNITY_BRANCH
if( fourMoments )
{
real posContrib = ShadowMoments_ChebyshevsInequality( moments.xz, warpedDepth.x, minVariance.x, lightLeakBias );

}
}
real SampleShadow_EVSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, Texture2DArray tex, SamplerState samp, bool fourMoments )
real SampleShadow_EVSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, Texture2DArray tex, SamplerState samp, bool fourMoments )
{
#if UNITY_REVERSED_Z
real depth = 1.0 - tcs.z;

real2 depthScale = evsmExponents * warpedDepth;
real2 minVariance = depthScale * depthScale * varianceBias;
[branch]
UNITY_BRANCH
if( fourMoments )
{
real posContrib = ShadowMoments_ChebyshevsInequality( moments.xz, warpedDepth.x, minVariance.x, lightLeakBias );

//
// 1 tap MSM sampling
//
real SampleShadow_MSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, uint texIdx, uint sampIdx, bool useHamburger )
real SampleShadow_MSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, uint texIdx, uint sampIdx, bool useHamburger )
{
real4 params = asfloat( shadowContext.payloads[payloadOffset] );
real lightLeakBias = params.x;

return (z[1] < 0.0 || z[2] > 1.0) ? ShadowMoments_SolveDelta4MSM( z, b, lightLeakBias ) : ShadowMoments_SolveDelta3MSM( z, b.xy, lightLeakBias );
}
real SampleShadow_MSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, uint slice, Texture2DArray tex, SamplerState samp, bool useHamburger )
real SampleShadow_MSM_1tap( ShadowContext shadowContext, inout uint payloadOffset, real3 tcs, float slice, Texture2DArray tex, SamplerState samp, bool useHamburger )
{
real4 params = asfloat( shadowContext.payloads[payloadOffset] );
real lightLeakBias = params.x;

//-----------------------------------------------------------------------------------------------------
// helper function to dispatch a specific shadow algorithm
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real depthBias, uint slice, uint algorithm, uint texIdx, uint sampIdx )
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real2 sampleBias, uint algorithm, uint texIdx, uint sampIdx )
[branch]
UNITY_BRANCH
case GPUSHADOWALGORITHM_PCF_1TAP : return SampleShadow_PCF_1tap( shadowContext, payloadOffset, posTC, depthBias, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_9TAP : return SampleShadow_PCF_9tap_Adaptive( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, depthBias, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_3X3 : return SampleShadow_PCF_Tent_3x3( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_5X5 : return SampleShadow_PCF_Tent_5x5( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_7X7 : return SampleShadow_PCF_Tent_7x7( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_VSM : return SampleShadow_VSM_1tap( shadowContext, payloadOffset, posTC, slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_EVSM_2 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, slice, texIdx, sampIdx, false );
case GPUSHADOWALGORITHM_EVSM_4 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, slice, texIdx, sampIdx, true );
case GPUSHADOWALGORITHM_MSM_HAM : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, slice, texIdx, sampIdx, true );
case GPUSHADOWALGORITHM_MSM_HAUS : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, slice, texIdx, sampIdx, false );
case GPUSHADOWALGORITHM_PCF_1TAP : return SampleShadow_PCF_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_9TAP : return SampleShadow_PCF_9tap_Adaptive( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_3X3 : return SampleShadow_PCF_Tent_3x3( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_5X5 : return SampleShadow_PCF_Tent_5x5( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_PCF_TENT_7X7 : return SampleShadow_PCF_Tent_7x7( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_VSM : return SampleShadow_VSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx );
case GPUSHADOWALGORITHM_EVSM_2 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx, false );
case GPUSHADOWALGORITHM_EVSM_4 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx, true );
case GPUSHADOWALGORITHM_MSM_HAM : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx, true );
case GPUSHADOWALGORITHM_MSM_HAUS : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, texIdx, sampIdx, false );
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real depthBias, uint slice, uint algorithm, Texture2DArray tex, SamplerComparisonState compSamp )
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real2 sampleBias, uint algorithm, Texture2DArray tex, SamplerComparisonState compSamp )
[branch]
UNITY_BRANCH
case GPUSHADOWALGORITHM_PCF_1TAP : return SampleShadow_PCF_1tap( shadowContext, payloadOffset, posTC, depthBias, slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_9TAP : return SampleShadow_PCF_9tap_Adaptive( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, depthBias, slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_3X3 : return SampleShadow_PCF_Tent_3x3( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_5X5 : return SampleShadow_PCF_Tent_5x5( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_7X7 : return SampleShadow_PCF_Tent_7x7( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_1TAP : return SampleShadow_PCF_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_9TAP : return SampleShadow_PCF_9tap_Adaptive( shadowContext, payloadOffset, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_3X3 : return SampleShadow_PCF_Tent_3x3( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_5X5 : return SampleShadow_PCF_Tent_5x5( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, tex, compSamp );
case GPUSHADOWALGORITHM_PCF_TENT_7X7 : return SampleShadow_PCF_Tent_7x7( shadowContext, payloadOffset, shadowData.textureSize, shadowData.texelSizeRcp, posTC, sampleBias, shadowData.slice, tex, compSamp );
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real depthBias, uint slice, uint algorithm, Texture2DArray tex, SamplerState samp )
real SampleShadow_SelectAlgorithm( ShadowContext shadowContext, ShadowData shadowData, inout uint payloadOffset, real3 posTC, real2 sampleBias, uint algorithm, Texture2DArray tex, SamplerState samp )
[branch]
UNITY_BRANCH
case GPUSHADOWALGORITHM_VSM : return SampleShadow_VSM_1tap( shadowContext, payloadOffset, posTC, slice, tex, samp );
case GPUSHADOWALGORITHM_EVSM_2 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, slice, tex, samp, false );
case GPUSHADOWALGORITHM_EVSM_4 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, slice, tex, samp, true );
case GPUSHADOWALGORITHM_MSM_HAM : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, slice, tex, samp, true );
case GPUSHADOWALGORITHM_MSM_HAUS : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, slice, tex, samp, false );
case GPUSHADOWALGORITHM_VSM : return SampleShadow_VSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, samp );
case GPUSHADOWALGORITHM_EVSM_2 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, samp, false );
case GPUSHADOWALGORITHM_EVSM_4 : return SampleShadow_EVSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, samp, true );
case GPUSHADOWALGORITHM_MSM_HAM : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, samp, true );
case GPUSHADOWALGORITHM_MSM_HAUS : return SampleShadow_MSM_1tap( shadowContext, payloadOffset, posTC, shadowData.slice, tex, samp, false );
default: return 1.0;
}
}

36
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowTexFetch.hlsl


// Sampler and texture combinations are static. No shadowmap will ever be sampled with two different samplers.
// Once shadowmaps and samplers are fixed consider writing custom dispatchers directly accessing textures and samplers.
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_COMP( _Tex2DArraySlots, _SamplerCompSlots ) \
real4 SampleCompShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, real3 tcs, real slice ) \
real4 SampleCompShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, real3 tcs, real slice ) \
[unroll] for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
UNITY_UNROLL for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
[unroll] for( uint j = 0; j < _SamplerCompSlots; j++ ) \
UNITY_UNROLL for( uint j = 0; j < _SamplerCompSlots; j++ ) \
[branch] if( i == texIdx && j == sampIdx ) \
UNITY_BRANCH if( i == texIdx && j == sampIdx ) \
{ \
res = SAMPLE_TEXTURE2D_ARRAY_SHADOW( ctxt.tex2DArray[i], ctxt.compSamplers[j], tcs, slice ); \
break; \

}
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_SAMP( _Tex2DArraySlots, _SamplerSlots ) \
real4 SampleShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, real2 tcs, real slice, real lod = 0.0 ) \
real4 SampleShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, real2 tcs, real slice, real lod = 0.0 ) \
[unroll] for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
UNITY_UNROLL for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
[unroll] for( uint j = 0; j < _SamplerSlots; j++ ) \
UNITY_UNROLL for( uint j = 0; j < _SamplerSlots; j++ ) \
[branch] if( i == texIdx && j == sampIdx ) \
UNITY_BRANCH if( i == texIdx && j == sampIdx ) \
{ \
res = SAMPLE_TEXTURE2D_ARRAY_LOD( ctxt.tex2DArray[i], ctxt.samplers[j], tcs, slice, lod ); \
break; \

# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ) \
real LoadShadow_T2DA( ShadowContext ctxt, uint texIdx, uint2 tcs, uint slice, uint lod = 0 ) \
{ \
real res = 1.0; \
[unroll] for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
real res = 1.0; \
UNITY_UNROLL for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
[branch] if( i == texIdx ) \
UNITY_BRANCH if( i == texIdx ) \
{ \
res = LOAD_TEXTURE2D_ARRAY_LOD( ctxt.tex2DArray[i], tcs, slice, lod ).x; \
break; \

real4 SampleCompShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, real4 tcs, real cubeIdx ) \
{ \
real4 res = 1.0.xxxx; \
[unroll] for( uint i = 0; i < _TexCubeArraySlots; i++ ) \
UNITY_UNROLL for( uint i = 0; i < _TexCubeArraySlots; i++ ) \
[unroll] for( uint j = 0; j < _SamplerCompSlots; j++ ) \
UNITY_UNROLL for( uint j = 0; j < _SamplerCompSlots; j++ ) \
[branch] if( i == texIdx && j == sampIdx ) \
UNITY_BRANCH if( i == texIdx && j == sampIdx ) \
{ \
res = SAMPLE_TEXTURECUBE_ARRAY_SHADOW( ctxt.texCubeArray[i], ctxt.compSamplers[j], tcs, cubeIdx ); \
break; \

}
# define SHADOW_DEFINE_SAMPLING_FUNC_TCA_SAMP( _TexCubeArraySlots, _SamplerSlots ) \
real4 SampleShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, real3 tcs, real cubeIdx, real lod = 0.0 ) \
real4 SampleShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, real3 tcs, real cubeIdx, real lod = 0.0 ) \
[unroll] for( uint i = 0; i < _TexCubeArraySlots; i++ ) \
UNITY_UNROLL for( uint i = 0; i < _TexCubeArraySlots; i++ ) \
[unroll] for( uint j = 0; j < _SamplerSlots; j++ ) \
UNITY_UNROLL for( uint j = 0; j < _SamplerSlots; j++ ) \
[branch] if( i == texIdx && j == sampIdx ) \
UNITY_BRANCH if( i == texIdx && j == sampIdx ) \
{ \
res = SAMPLE_TEXTURECUBE_ARRAY_LOD( ctxt.texCubeArray[i], ctxt.samplers[j], tcs, cubeIdx, lod ); \
break; \

15
ScriptableRenderPipeline/Core/CoreRP/Shadow/AdditionalShadowData.cs


public float contactShadowFadeDistance = 5.0f;
[Range(4, 64)]
public uint contactShadowSampleCount = 8;
// bias control
public float viewBiasMin = 0.5f;
public float viewBiasMax = 10.0f;
[Range(0.0F, 15.0F)]
public float viewBiasScale = 1.0f;
public float normalBiasMin = 0.2f;
public float normalBiasMax = 4.0f;
[Range(0.0F, 10.0F)]
public float normalBiasScale = 1.0f;
public bool sampleBiasScale = true;
public bool edgeLeakFixup = true;
public bool edgeToleranceNormal = true;
[Range(0.0F, 1.0F)]
public float edgeTolerance = 1.0f;
// shadow related parameters
[System.Serializable]

144
ScriptableRenderPipeline/Core/CoreRP/Shadow/Shadow.cs


protected uint[] m_TmpWidths = new uint[ShadowmapBase.ShadowRequest.k_MaxFaceCount];
protected uint[] m_TmpHeights = new uint[ShadowmapBase.ShadowRequest.k_MaxFaceCount];
protected Vector4[] m_TmpSplits = new Vector4[k_MaxCascadesInShader];
protected float[] m_TmpScales = new float[((k_MaxCascadesInShader+3)/4)*4];
private Material m_ClearMat;
private readonly VectorArray<CachedEntry>.Cleanup m_Cleanup;
private readonly VectorArray<CachedEntry>.Comparator<Key> m_Comparator;
public bool captureFrame { get; set; }

#endif
public int Default() { return ShadowUtils.Asint( ValScale * ValDef ); }
}
readonly ValRange m_DefPCF_DepthBias = new ValRange( "Depth Bias", 0.0f, 0.05f, 1.0f, 000.1f );
readonly ValRange m_DefPCF_DepthBias = new ValRange( "Depth Bias", 0.0f, 0.0f, 1.0f, 000.1f );
m_ClearMat = new Material( Shader.Find( "Hidden/ScriptableRenderPipeline/ShadowClear" ) );
m_Cleanup = (CachedEntry entry) => { Free( entry ); };
m_Comparator = (ref Key k, ref CachedEntry entry) => { return k.id == entry.key.id && k.faceIdx == entry.key.faceIdx; };

m_Shadowmap = new RenderTexture( (int) m_Width, (int) m_Height, (int) m_ShadowmapBits, m_ShadowmapFormat, RenderTextureReadWrite.Linear );
CreateShadowmap( m_Shadowmap );
m_Shadowmap.Create();
#if false && UNITY_PS4 && !UNITY_EDITOR
if( m_Shadowmap != null )
UnityEngine.PS4.RenderSettings.DisableDepthBufferCompression( m_Shadowmap );
#endif
}
virtual protected void CreateShadowmap( RenderTexture shadowmap )

float nearPlaneOffset = QualitySettings.shadowNearPlaneOffset;
GPUShadowAlgorithm sanitizedAlgo = ShadowUtils.ClearPrecision( sr.shadowAlgorithm );
AdditionalShadowData asd = lights[sr.index].light.GetComponent<AdditionalShadowData>();
if( !asd )
return false;
int cascadeCnt = 0;
int cascadeCnt = 0;
AdditionalShadowData asd = lights[sr.index].light.GetComponent<AdditionalShadowData>();
if( !asd )
return false;
uint multiFaceIdx = key.shadowDataIdx;
// For lights with multiple faces, the first shadow data contains
// per light information, so not all fields contain valid data.
// Shader code must make sure to read per face data from per face entries.
sd.texelSizeRcp = new Vector4( m_WidthRcp, m_HeightRcp, 1.0f / widths[0], 1.0f / heights[0] );
sd.PackShadowType( sr.shadowType, sanitizedAlgo );
sd.payloadOffset = payload.Count();
entries.AddUnchecked( sd );
key.shadowDataIdx++;
}

ce.zclip = sr.shadowType != GPUShadowType.Directional;
// modify
Matrix4x4 vp, invvp;
Matrix4x4 vp, invvp, devproj;
vp = ShadowUtils.ExtractPointLightMatrix( lights[sr.index], key.faceIdx, 2.0f, out ce.current.view, out ce.current.proj, out invvp, out ce.current.lightDir, out ce.current.splitData );
{
// calculate the fov bias
float guardAngle = ShadowUtils.CalcGuardAnglePerspective( 90.0f, ce.current.viewport.width, GetFilterWidthInTexels( sr, asd ), asd.normalBiasMax, 79.0f );
vp = ShadowUtils.ExtractPointLightMatrix( lights[sr.index], key.faceIdx, guardAngle, out ce.current.view, out ce.current.proj, out devproj, out invvp, out ce.current.lightDir, out ce.current.splitData );
}
vp = ShadowUtils.ExtractSpotLightMatrix( lights[sr.index], out ce.current.view, out ce.current.proj, out invvp, out ce.current.lightDir, out ce.current.splitData );
{
float spotAngle = lights[sr.index].spotAngle;
float guardAngle = ShadowUtils.CalcGuardAnglePerspective( spotAngle, ce.current.viewport.width, GetFilterWidthInTexels( sr, asd ), asd.normalBiasMax, 180.0f - spotAngle );
vp = ShadowUtils.ExtractSpotLightMatrix( lights[sr.index], guardAngle, out ce.current.view, out ce.current.proj, out devproj, out invvp, out ce.current.lightDir, out ce.current.splitData );
}
vp = ShadowUtils.ExtractDirectionalLightMatrix( lights[sr.index], key.faceIdx, cascadeCnt, cascadeRatios, nearPlaneOffset, width, height, out ce.current.view, out ce.current.proj, out invvp, out ce.current.lightDir, out ce.current.splitData, m_CullResults, (int) sr.index );
vp = ShadowUtils.ExtractDirectionalLightMatrix( lights[sr.index], key.faceIdx, cascadeCnt, cascadeRatios, nearPlaneOffset, width, height, out ce.current.view, out ce.current.proj, out devproj, out invvp, out ce.current.lightDir, out ce.current.splitData, m_CullResults, (int) sr.index );
m_TmpSplits[key.faceIdx] = ce.current.splitData.cullingSphere;
if( ce.current.splitData.cullingSphere.w != float.NegativeInfinity )
{

m_TmpScales[face] = Mathf.Max( texelSizeX, texelSizeY );
vp = invvp = Matrix4x4.identity; // should never happen, though
vp = invvp = devproj = Matrix4x4.identity; // should never happen, though
if (cameraRelativeRendering)
{

vp *= translation;
translation.SetColumn( 3, -camPosWS );
translation[15] = 1.0f;
invvp = translation * invvp;
if (sr.shadowType == GPUShadowType.Directional)
{
m_TmpSplits[key.faceIdx].x -= camPosWS.x;

}
// extract texel size in world space
int flags = 0;
flags |= asd.sampleBiasScale ? (1 << 0) : 0;
flags |= asd.edgeLeakFixup ? (1 << 1) : 0;
flags |= asd.edgeToleranceNormal ? (1 << 2) : 0;
sd.edgeTolerance = asd.edgeTolerance;
sd.viewBias = new Vector4( asd.viewBiasMin, asd.viewBiasMax, asd.viewBiasScale, 2.0f / ce.current.proj.m00 / ce.current.viewport.width * 1.4142135623730950488016887242097f );
sd.normalBias = new Vector4( asd.normalBiasMin, asd.normalBiasMax, asd.normalBiasScale, ShadowUtils.Asfloat( flags ) );
sd.worldToShadow = vp.transpose; // apparently we need to transpose matrices that are sent to HLSL
if (sr.shadowType == GPUShadowType.Directional)
sd.pos = new Vector3( ce.current.view.m03, ce.current.view.m13, ce.current.view.m23 );
else
sd.pos = cameraRelativeRendering ? (lights[sr.index].light.transform.position - camera.transform.position) : lights[sr.index].light.transform.position;
sd.proj = new Vector4( devproj.m00, devproj.m11, devproj.m22, devproj.m23 );
sd.rot0 = new Vector3( ce.current.view.m00, ce.current.view.m01, ce.current.view.m02 );
sd.rot1 = new Vector3( ce.current.view.m10, ce.current.view.m11, ce.current.view.m12 );
sd.rot2 = new Vector3( ce.current.view.m20, ce.current.view.m21, ce.current.view.m22 );
sd.PackShadowmapId( m_TexSlot, m_SampSlot, ce.current.slice );
sd.PackShadowmapId( m_TexSlot, m_SampSlot );
sd.slice = ce.current.slice;
if( multiFace )
{
entries[multiFaceIdx] = sd;
multiFace = false;
}
resIdx++;
facecnt--;
key.shadowDataIdx++;

// Returns how many entries will be written into the payload buffer per light.
virtual protected uint ReservePayload( ShadowRequest sr )
{
uint payloadSize = sr.shadowType == GPUShadowType.Directional ? (k_MaxCascadesInShader + ((uint)m_TmpScales.Length / 4) + ((uint)m_TmpBorders.Length / 4)) : 0;
uint payloadSize = sr.shadowType == GPUShadowType.Directional ? (1 + k_MaxCascadesInShader + ((uint)m_TmpBorders.Length / 4)) : 0;
virtual protected float GetFilterWidthInTexels( ShadowRequest sr, AdditionalShadowData asd )
{
ShadowAlgorithm algo;
ShadowVariant vari;
ShadowPrecision prec;
ShadowUtils.Unpack( sr.shadowAlgorithm, out algo, out vari, out prec );
if( algo != ShadowAlgorithm.PCF )
return 1.0f;
switch( vari )
{
case ShadowVariant.V0: return 1;
case ShadowVariant.V1:
{
int shadowDataFormat;
int[] shadowData = asd.GetShadowData( out shadowDataFormat );
return ShadowUtils.Asfloat( shadowData[1] );
}
case ShadowVariant.V2: return 3;
case ShadowVariant.V3: return 5;
case ShadowVariant.V4: return 7;
default: return 1.0f;
}
}
// Writes additional per light data into the payload vector. Make sure to call base.WritePerLightPayload first.
virtual protected void WritePerLightPayload(List<VisibleLight> lights, ShadowRequest sr, ref ShadowData sd, ref ShadowPayloadVector payload, ref uint payloadOffset )
{

uint first = k_MaxCascadesInShader, second = k_MaxCascadesInShader;
first = (first == k_MaxCascadesInShader && m_TmpSplits[i].w > 0.0f) ? i : first;
second = (second == k_MaxCascadesInShader && m_TmpSplits[i].w > 0.0f) ? i : second;
for( int i = 0; i < m_TmpScales.Length; i += 4 )
{
sp.Set( m_TmpScales[i+0], m_TmpScales[i+1], m_TmpScales[i+2], m_TmpScales[i+3] );
payload[payloadOffset] = sp;
payloadOffset++;
}
if( second != k_MaxCascadesInShader )
sp.Set( (m_TmpSplits[second] - m_TmpSplits[first]).normalized );
else
sp.Set( 0.0f, 0.0f, 0.0f, 0.0f );
payload[payloadOffset] = sp;
payloadOffset++;
for( int i = 0; i < m_TmpBorders.Length; i += 4 )
{

ShadowData sd = entries[ce.key.shadowDataIdx];
// update the shadow data with the actual result of the layouting step
sd.scaleOffset = new Vector4( ce.current.viewport.width * m_WidthRcp, ce.current.viewport.height * m_HeightRcp, ce.current.viewport.x * m_WidthRcp, ce.current.viewport.y * m_HeightRcp );
sd.PackShadowmapId( m_TexSlot, m_SampSlot, ce.current.slice );
sd.PackShadowmapId( m_TexSlot, m_SampSlot );
sd.slice = ce.current.slice;
// write back the correct results
entries[ce.key.shadowDataIdx] = sd;
}

cb.GetTemporaryRT(m_TempDepthId, (int)m_Width, (int)m_Height, (int)m_ShadowmapBits, FilterMode.Bilinear, RenderTextureFormat.Shadowmap, RenderTextureReadWrite.Default);
cb.SetRenderTarget( new RenderTargetIdentifier( m_TempDepthId ) );
}
cb.ClearRenderTarget( true, !IsNativeDepth(), m_ClearColor );
}
override public void Update( FrameId frameId, ScriptableRenderContext renderContext, CommandBuffer cmd, CullResults cullResults, List<VisibleLight> lights)

}
cmd.SetViewport( m_EntryCache[i].current.viewport );
cbName = "Shadowmap.ClearRect";
cmd.BeginSample( cbName );
if( m_ClearMat == null )
m_ClearMat = new Material( Shader.Find( "Hidden/ScriptableRenderPipeline/ShadowClear" ) );
CoreUtils.DrawFullScreen( cmd, m_ClearMat, null, 0 );
cmd.EndSample( cbName );
cmd.SetViewProjectionMatrices( m_EntryCache[i].current.view, m_EntryCache[i].current.proj );
cmd.SetGlobalVector( "g_vLightDirWs", m_EntryCache[i].current.lightDir );
cmd.SetGlobalFloat( m_ZClipId, m_EntryCache[i].zclip ? 1.0f : 0.0f );

case ShadowAlgorithm.MSM : return cnt + 1;
default: return cnt;
}
}
override protected float GetFilterWidthInTexels( ShadowRequest sr, AdditionalShadowData asd )
{
return 1.0f;
}
// Writes additional per light data into the payload vector. Make sure to call base.WritePerLightPayload first.

// set light specific values that are not related to the shadowmap
GPUShadowType shadowtype = GetShadowLightType(l);
// current bias value range is way too large, so scale by 0.01 for now until we've decided whether to actually keep this value or not.
sd.bias = 0.01f * (SystemInfo.usesReversedZBuffer ? l.shadowBias : -l.shadowBias);
sd.normalBias = 2.0f * l.shadowNormalBias;
shadowIndices.AddUnchecked( (int) shadowDatas.Count() );

int offset = (m_TmpRequests[index].facecount > 1 ) ? 1 : 0;
VectorArray<ShadowData> shadowDatas = m_ShadowCtxt.shadowDatas;
ShadowData faceData = shadowDatas[(uint)(m_ShadowIndices[index] + offset + faceIndex)];
uint texID, samplerID, slice;
faceData.UnpackShadowmapId(out texID, out samplerID, out slice);
m_Shadowmaps[texID].DisplayShadowMap(cmd, faceData.scaleOffset, slice, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue);
uint texID, samplerID;
faceData.UnpackShadowmapId(out texID, out samplerID);
m_Shadowmaps[texID].DisplayShadowMap(cmd, faceData.scaleOffset, (uint) faceData.slice, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue);
}
public override void DisplayShadowMap(CommandBuffer cmd, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue)

25
ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs


public struct ShadowData
{
// shadow texture related params (need to be set by ShadowmapBase and derivatives)
public Matrix4x4 worldToShadow; // to light space matrix
public Matrix4x4 shadowToWorld; // from light space matrix
public Vector4 proj; // projection matrix value _00, _11, _22, _23
public Vector3 pos; // view matrix light position
public Vector3 rot0; // first column of view matrix rotation
public Vector3 rot1; // second column of view matrix rotation
public Vector3 rot2; // third column of view matrix rotation
public Vector4 scaleOffset; // scale and offset of shadowmap in atlas
public Vector4 textureSize; // the shadowmap's size in x and y. xy is texture relative, zw is viewport relative.
public Vector4 texelSizeRcp; // reciprocal of the shadowmap's texel size in x and y. xy is texture relative, zw is viewport relative.

public float slice; // shadowmap slice
public Vector4 viewBias; // x = min, y = max, z = scale, w = shadowmap texel size in world space at distance 1 from light
public Vector4 normalBias; // x = min, y = max, z = scale, w = enable/disable sample biasing
public float edgeTolerance; // specifies the offset along either the normal or view vector used for calculating the edge leak fixup
public Vector3 _pad; // 16 byte padding
public Matrix4x4 shadowToWorld; // from light space matrix
// light related params (need to be set via ShadowMgr and derivatives)
public float bias; // bias setting
public float normalBias; // bias based on the normal
public void PackShadowmapId( uint texIdx, uint sampIdx, uint slice )
public void PackShadowmapId( uint texIdx, uint sampIdx )
Debug.Assert( slice <= 0xffff );
id = texIdx << 24 | sampIdx << 16 | slice;
id = texIdx << 24 | sampIdx << 16;
public void UnpackShadowmapId(out uint texIdx, out uint sampIdx, out uint slice)
public void UnpackShadowmapId( out uint texIdx, out uint sampIdx )
slice = (id & 0xffff);
}
public void PackShadowType( GPUShadowType type, GPUShadowAlgorithm algorithm )

57
ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs.hlsl


// PackingRules = Exact
struct ShadowData
{
float4x4 worldToShadow;
float4x4 shadowToWorld;
float4 proj;
float3 pos;
float3 rot0;
float3 rot1;
float3 rot2;
float4 scaleOffset;
float4 textureSize;
float4 texelSizeRcp;

float bias;
float normalBias;
float slice;
float4 viewBias;
float4 normalBias;
float edgeTolerance;
float3 _pad;
float4x4 shadowToWorld;
float4x4 GetWorldToShadow(ShadowData value)
float4 GetProj(ShadowData value)
{
return value.proj;
}
float3 GetPos(ShadowData value)
{
return value.pos;
}
float3 GetRot0(ShadowData value)
{
return value.rot0;
}
float3 GetRot1(ShadowData value)
return value.worldToShadow;
return value.rot1;
float4x4 GetShadowToWorld(ShadowData value)
float3 GetRot2(ShadowData value)
return value.shadowToWorld;
return value.rot2;
}
float4 GetScaleOffset(ShadowData value)
{

{
return value.payloadOffset;
}
float GetBias(ShadowData value)
float GetSlice(ShadowData value)
return value.bias;
return value.slice;
float GetNormalBias(ShadowData value)
float4 GetViewBias(ShadowData value)
{
return value.viewBias;
}
float4 GetNormalBias(ShadowData value)
}
float GetEdgeTolerance(ShadowData value)
{
return value.edgeTolerance;
}
float3 Get_pad(ShadowData value)
{
return value._pad;
}
float4x4 GetShadowToWorld(ShadowData value)
{
return value.shadowToWorld;
}

45
ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowUtilities.cs


vpinv = invview * invproj;
}
public static Matrix4x4 ExtractSpotLightMatrix( VisibleLight vl, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData )
public static Matrix4x4 ExtractSpotLightMatrix( VisibleLight vl, float guardAngle, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 deviceProj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData )
{
splitData = new ShadowSplitData();
splitData.cullingSphere.Set( 0.0f, 0.0f, 0.0f, float.NegativeInfinity );

// calculate projection
float zfar = vl.range;
float znear = vl.light.shadowNearPlane >= nearmin ? vl.light.shadowNearPlane : nearmin;
float fov = vl.spotAngle;
float fov = vl.spotAngle + guardAngle;
// and the compound
InvertPerspective( ref proj, ref view, out vpinverse );
return proj * view;
// and the compound (deviceProj will potentially inverse-Z)
deviceProj = GL.GetGPUProjectionMatrix( proj, false );
InvertPerspective( ref deviceProj, ref view, out vpinverse );
return deviceProj * view;
public static Matrix4x4 ExtractPointLightMatrix( VisibleLight vl, uint faceIdx, float fovBias, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData )
public static Matrix4x4 ExtractPointLightMatrix( VisibleLight vl, uint faceIdx, float guardAngle, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 deviceProj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData )
{
if( faceIdx > (uint) CubemapFace.NegativeZ )
Debug.LogError( "Tried to extract cubemap face " + faceIdx + "." );

// calculate projection
float farPlane = vl.range;
float nearPlane = vl.light.shadowNearPlane >= nearmin ? vl.light.shadowNearPlane : nearmin;
proj = Matrix4x4.Perspective( 90.0f + fovBias, 1.0f, nearPlane, farPlane );
// and the compound
InvertPerspective( ref proj, ref view, out vpinverse );
return proj * view;
proj = Matrix4x4.Perspective( 90.0f + guardAngle, 1.0f, nearPlane, farPlane );
// and the compound (deviceProj will potentially inverse-Z)
deviceProj = GL.GetGPUProjectionMatrix( proj, false );
InvertPerspective( ref deviceProj, ref view, out vpinverse );
return deviceProj * view;
public static Matrix4x4 ExtractDirectionalLightMatrix( VisibleLight vl, uint cascadeIdx, int cascadeCount, float[] splitRatio, float nearPlaneOffset, uint width, uint height, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData, CullResults cullResults, int lightIndex )
public static Matrix4x4 ExtractDirectionalLightMatrix( VisibleLight vl, uint cascadeIdx, int cascadeCount, float[] splitRatio, float nearPlaneOffset, uint width, uint height, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 deviceProj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData, CullResults cullResults, int lightIndex )
{
Debug.Assert( width == height, "Currently the cascaded shadow mapping code requires square cascades." );
splitData = new ShadowSplitData();

for( int i = 0, cnt = splitRatio.Length < 3 ? splitRatio.Length : 3; i < cnt; i++ )
ratios[i] = splitRatio[i];
cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives( lightIndex, (int) cascadeIdx, cascadeCount, ratios, (int) width, nearPlaneOffset, out view, out proj, out splitData );
// and the compound
InvertOrthographic( ref proj, ref view, out vpinverse );
return proj * view;
// and the compound (deviceProj will potentially inverse-Z)
deviceProj = GL.GetGPUProjectionMatrix( proj, false );
InvertOrthographic( ref deviceProj, ref view, out vpinverse );
return deviceProj * view;
}
public static float CalcGuardAnglePerspective( float angleInDeg, float resolution, float filterWidth, float normalBiasMax, float guardAngleMaxInDeg )
{
float angleInRad = angleInDeg * 0.5f * Mathf.Deg2Rad;
float res = 2.0f / resolution;
float texelSize = Mathf.Cos( angleInRad ) * res;
float beta = normalBiasMax * texelSize * 1.4142135623730950488016887242097f;
float guardAngle = Mathf.Atan( beta );
texelSize = Mathf.Tan( angleInRad + guardAngle ) * res;
guardAngle = Mathf.Atan( (resolution + Mathf.Ceil( filterWidth )) * texelSize * 0.5f ) * 2.0f * Mathf.Rad2Deg - angleInDeg;
guardAngle *= 2.0f;
return guardAngle < guardAngleMaxInDeg ? guardAngle : guardAngleMaxInDeg;
}
public static GPUShadowAlgorithm Pack( ShadowAlgorithm algo, ShadowVariant vari, ShadowPrecision prec )

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs


light.gameObject.AddComponent<HDAdditionalLightData>();
if (light.GetComponent<AdditionalShadowData>() == null)
light.gameObject.AddComponent<AdditionalShadowData>();
{
AdditionalShadowData shadowData = light.gameObject.AddComponent<AdditionalShadowData>();
HDAdditionalShadowData.InitDefaultHDAdditionalShadowData(shadowData);
}
}
}

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs


// Get & automatically add additional HD data if not present
var lightData = CoreEditorUtils.GetAdditionalData<HDAdditionalLightData>(targets);
var shadowData = CoreEditorUtils.GetAdditionalData<AdditionalShadowData>(targets);
var shadowData = CoreEditorUtils.GetAdditionalData<AdditionalShadowData>(targets, HDAdditionalShadowData.InitDefaultHDAdditionalShadowData);
m_SerializedAdditionalLightData = new SerializedObject(lightData);
m_SerializedAdditionalShadowData = new SerializedObject(shadowData);

38
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/DeferredDirectionalShadow.compute


// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel DeferredDirectionalShadow DEFERRED_DIRECTIONAL=DeferredDirectionalShadow
#pragma kernel DeferredDirectionalShadow_Contact DEFERRED_DIRECTIONAL=DeferredDirectionalShadow_Contact ENABLE_CONTACT_SHADOWS
#pragma kernel DeferredDirectionalShadow DEFERRED_DIRECTIONAL=DeferredDirectionalShadow
#pragma kernel DeferredDirectionalShadow_Contact DEFERRED_DIRECTIONAL=DeferredDirectionalShadow_Contact ENABLE_CONTACT_SHADOWS
#pragma kernel DeferredDirectionalShadow_Normals DEFERRED_DIRECTIONAL=DeferredDirectionalShadow_Normals ENABLE_NORMALS
#pragma kernel DeferredDirectionalShadow_Contact_Normals DEFERRED_DIRECTIONAL=DeferredDirectionalShadow_Contact_Normals ENABLE_CONTACT_SHADOWS ENABLE_NORMALS
#ifdef ENABLE_NORMALS
# define LIGHTLOOP_TILE_PASS 1
# define USE_FPTL_LIGHTLIST 1 // deferred opaque always use FPTL
# define UNITY_MATERIAL_LIT
#else
# define SHADOW_USE_ONLY_VIEW_BASED_BIASING 1 // Enable only light view vector based biasing. If undefined, biasing will be based on the normal and calling code must provide a valid normal.
#endif
#ifdef SHADER_API_PSSL
# pragma argument( scheduler=minpressure ) // instruct the shader compiler to prefer minimizing vgpr usage
#endif
#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "../ShaderVariables.hlsl"

RWTexture2D<float4> _DeferredShadowTextureUAV;
CBUFFER_START(DeferredShadowParameters)
float _DirectionalShadowIndex;
uint _DirectionalShadowIndex;
float3 _LightDirection;
float4 _ScreenSpaceShadowsParameters;
int _SampleCount;

uint2 pixelCoord = groupId * DEFERRED_SHADOW_TILE_SIZE + groupThreadId;
uint2 tileCoord = groupId;
float depth = LOAD_TEXTURE2D(_MainDepthTexture, pixelCoord.xy).x;
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_VP, tileCoord);
float depth = LOAD_TEXTURE2D(_MainDepthTexture, pixelCoord.xy).x;
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_VP, tileCoord);
#ifdef ENABLE_NORMALS
BSDFData bsdfData;
BakeLightingData unused;
DECODE_FROM_GBUFFER(posInput.positionSS, UINT_MAX, bsdfData, unused.bakeDiffuseLighting);
float3 nrm = bsdfData.normalWS;
#else
float3 nrm = 0.0.xxx;
#endif
float shadow = GetDirectionalShadowAttenuation(shadowContext, posInput.positionWS, float3(0.0, 0.0, 0.0), (uint)_DirectionalShadowIndex, float3(0.0, 0.0, 0.0));
float shadow = GetDirectionalShadowAttenuation(shadowContext, posInput.positionWS, nrm, _DirectionalShadowIndex, _LightDirection);
#ifdef ENABLE_CONTACT_SHADOWS
float contactShadow = 1.0f;

14
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl


color = lightData.color;
attenuation = 1.0; // Note: no volumetric attenuation along shadow rays for directional lights
[branch] if (lightData.cookieIndex >= 0)
UNITY_BRANCH if (lightData.cookieIndex >= 0)
{
float3 lightToSample = positionWS - lightData.positionWS;
float3 cookie = EvaluateCookie_Directional(lightLoopContext, lightData, lightToSample);

shadow = shadowMask = (lightData.shadowMaskSelector.x >= 0.0) ? dot(bakeLightingData.bakeShadowMask, lightData.shadowMaskSelector) : 1.0;
#endif
[branch] if (lightData.shadowIndex >= 0)
UNITY_BRANCH if (lightData.shadowIndex >= 0)
{
#ifdef USE_DEFERRED_DIRECTIONAL_SHADOWS
shadow = LOAD_TEXTURE2D(_DeferredShadowTexture, posInput.positionSS).x;

float4 cookie;
[branch] if (lightType == GPULIGHTTYPE_POINT)
UNITY_BRANCH if (lightType == GPULIGHTTYPE_POINT)
{
cookie.rgb = SampleCookieCube(lightLoopContext, positionLS, lightData.cookieIndex);
cookie.a = 1;

#endif
// Projector lights always have cookies, so we can perform clipping inside the if().
[branch] if (lightData.cookieIndex >= 0)
UNITY_BRANCH if (lightData.cookieIndex >= 0)
{
float4 cookie = EvaluateCookie_Punctual(lightLoopContext, lightData, lightToSample);

shadow = shadowMask = (lightData.shadowMaskSelector.x >= 0.0) ? dot(bakeLightingData.bakeShadowMask, lightData.shadowMaskSelector) : 1.0;
#endif
[branch] if (lightData.shadowIndex >= 0)
UNITY_BRANCH if (lightData.shadowIndex >= 0)
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float4 L_dist = float4(L, distances.x);
shadow = GetPunctualShadowAttenuation(lightLoopContext.shadowContext, positionWS + offset, N, lightData.shadowIndex, L_dist, posInput.positionSS);
shadow = GetPunctualShadowAttenuation(lightLoopContext.shadowContext, positionWS, N, lightData.shadowIndex, L, distances.x, posInput.positionSS);
#ifdef SHADOWS_SHADOWMASK
// Note: Legacy Unity have two shadow mask mode. ShadowMask (ShadowMask contain static objects shadow and ShadowMap contain only dynamic objects shadow, final result is the minimun of both value)
// and ShadowMask_Distance (ShadowMask contain static objects shadow and ShadowMap contain everything and is blend with ShadowMask based on distance (Global distance setup in QualitySettigns)).

16
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs


m_ShadowMgr = new ShadowManager(shadowSettings, ref scInit, m_Shadowmaps);
// set global overrides - these need to match the override specified in LightLoop/Shadow.hlsl
bool useGlobalOverrides = true;
m_ShadowMgr.SetGlobalShadowOverride( GPUShadowType.Point , ShadowAlgorithm.PCF, ShadowVariant.V4, ShadowPrecision.High, useGlobalOverrides );
m_ShadowMgr.SetGlobalShadowOverride( GPUShadowType.Spot , ShadowAlgorithm.PCF, ShadowVariant.V4, ShadowPrecision.High, useGlobalOverrides );
m_ShadowMgr.SetGlobalShadowOverride( GPUShadowType.Point , ShadowAlgorithm.PCF, ShadowVariant.V1, ShadowPrecision.High, useGlobalOverrides );
m_ShadowMgr.SetGlobalShadowOverride( GPUShadowType.Spot , ShadowAlgorithm.PCF, ShadowVariant.V1, ShadowPrecision.High, useGlobalOverrides );
m_ShadowMgr.SetGlobalShadowOverride( GPUShadowType.Directional , ShadowAlgorithm.PCF, ShadowVariant.V3, ShadowPrecision.High, useGlobalOverrides );
m_ShadowMgr.SetShadowLightTypeDelegate(HDShadowLightType);

static int s_deferredDirectionalShadowKernel;
static int s_deferredDirectionalShadow_Contact_Kernel;
static int s_deferredDirectionalShadow_Normals_Kernel;
static int s_deferredDirectionalShadow_Contact_Normals_Kernel;
static ComputeBuffer s_LightVolumeDataBuffer = null;
static ComputeBuffer s_ConvexBoundsBuffer = null;

s_deferredDirectionalShadowKernel = deferredDirectionalShadowComputeShader.FindKernel("DeferredDirectionalShadow");
s_deferredDirectionalShadow_Contact_Kernel = deferredDirectionalShadowComputeShader.FindKernel("DeferredDirectionalShadow_Contact");
s_deferredDirectionalShadow_Normals_Kernel = deferredDirectionalShadowComputeShader.FindKernel("DeferredDirectionalShadow_Normals");
s_deferredDirectionalShadow_Contact_Normals_Kernel = deferredDirectionalShadowComputeShader.FindKernel("DeferredDirectionalShadow_Contact_Normals");
for (int variant = 0; variant < LightDefinitions.s_NumFeatureVariants; variant++)
{

AdditionalShadowData asd = m_CurrentSunLight.GetComponent<AdditionalShadowData>();
bool enableContactShadows = m_FrameSettings.enableContactShadows && asd.enableContactShadows && asd.contactShadowLength > 0.0f;
int kernel = enableContactShadows ? s_deferredDirectionalShadow_Contact_Kernel : s_deferredDirectionalShadowKernel;
int kernel;
if (enableContactShadows)
kernel = m_FrameSettings.enableForwardRenderingOnly ? s_deferredDirectionalShadow_Contact_Kernel : s_deferredDirectionalShadow_Contact_Normals_Kernel;
else
kernel = m_FrameSettings.enableForwardRenderingOnly ? s_deferredDirectionalShadowKernel : s_deferredDirectionalShadow_Normals_Kernel;
m_ShadowMgr.BindResources(cmd, deferredDirectionalShadowComputeShader, kernel);

cmd.SetComputeIntParam(deferredDirectionalShadowComputeShader, HDShaderIDs._DirectionalContactShadowSampleCount, (int)asd.contactShadowSampleCount);
}
cmd.SetComputeFloatParam(deferredDirectionalShadowComputeShader, HDShaderIDs._DirectionalShadowIndex, (float)m_CurrentSunLightShadowIndex);
cmd.SetComputeIntParam(deferredDirectionalShadowComputeShader, HDShaderIDs._DirectionalShadowIndex, m_CurrentSunLightShadowIndex);
cmd.SetComputeVectorParam(deferredDirectionalShadowComputeShader, HDShaderIDs._DirectionalLightDirection, -m_CurrentSunLight.transform.forward);
cmd.SetComputeTextureParam(deferredDirectionalShadowComputeShader, kernel, HDShaderIDs._DeferredShadowTextureUAV, deferredShadowRT);
cmd.SetComputeTextureParam(deferredDirectionalShadowComputeShader, kernel, HDShaderIDs._MainDepthTexture, depthTexture);

26
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl


float3(1.0, 0.0, 0.0),
float3(0.0, 1.0, 0.0),
float3(0.0, 0.0, 1.0),
float3(1.0, 1.0, 0.0)
float3(1.0, 1.0, 0.0),
float3(1.0, 1.0, 1.0)
float shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, float3(0.0, 1.0, 0.0 ), 0, float3(0.0, 0.0, 0.0), float2(0.0, 0.0));
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres(lightLoopContext.shadowContext, 0, dirShadowSplitSpheres);
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows(positionWS, dirShadowSplitSpheres);
if (shadowSplitIndex == -1)
{
diffuseLighting = float3(0.0, 0.0, 0.0);
}
else
diffuseLighting = float3(0.0, 0.0, 0.0);
if (_DirectionalLightCount > 0)
diffuseLighting = s_CascadeColors[shadowSplitIndex] * shadow;
int shadowIdx = _DirectionalLightDatas[0].shadowIndex;
float shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, float3(0.0, 1.0, 0.0 ), shadowIdx, -_DirectionalLightDatas[0].forward, float2(0.0, 0.0));
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex(lightLoopContext.shadowContext, shadowIdx, positionWS, payloadOffset, alpha);
if (shadowSplitIndex >= 0)
{
diffuseLighting = lerp(s_CascadeColors[shadowSplitIndex], s_CascadeColors[shadowSplitIndex+1], alpha) * shadow;
}
}
}
#endif

18
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/Shadow.hlsl


#define SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL
#define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
#define SHADOW_USE_VIEW_BIAS_SCALING 1 // Enable view bias scaling to mitigate light leaking across edges. Uses the light vector if SHADOW_USE_ONLY_VIEW_BASED_BIASING is defined, otherwise uses the normal.
#define SHADOW_USE_SAMPLE_BIASING 1 // Enable per sample biasing for wide multi-tap PCF filters. Incompatible with SHADOW_USE_ONLY_VIEW_BASED_BIASING.
#define SHADOW_USE_DEPTH_BIAS 0 // Enable clip space z biasing
#include "ShadowContext.hlsl"
// This is an example of how to override the default dynamic resource dispatcher

// example of overriding punctual lights
#ifdef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist )
{
#ifdef SHADOW_DISPATCH_USE_SEPARATE_PUNC_ALGOS
// example for choosing different algos for point and spot lights

[branch]
UNITY_BRANCH
return EvalShadow_PointDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_PointDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
else
{

return EvalShadow_SpotDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_SpotDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
#else
// example for choosing the same algo

return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L, L_dist );
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L, float2 positionSS )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist, float2 positionSS )
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
#endif

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-bigtile.compute


bool canEnter = idxCoarse<(uint) g_iNrVisibLights;
if(canEnter) canEnter = _LightVolumeData[idxCoarse].lightVolume != LIGHTVOLUMETYPE_SPHERE; // don't bother doing edge tests for sphere lights since these have camera aligned bboxes.
[branch]if(canEnter)
UNITY_BRANCH if(canEnter)
{
SFiniteLightBound lgtDat = g_data[idxCoarse];

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-clustered.compute


GroupMemoryBarrierWithGroupSync();
#endif
const int idxCoarse = coarseList[l];
[branch]if (_LightVolumeData[idxCoarse].lightVolume != LIGHTVOLUMETYPE_SPHERE) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes.
UNITY_BRANCH if (_LightVolumeData[idxCoarse].lightVolume != LIGHTVOLUMETYPE_SPHERE) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes.
{
SFiniteLightBound lgtDat = g_data[idxCoarse];

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild.compute


float4 vLinDepths;
{
// Fetch depths and calculate min/max
[unroll]
UNITY_UNROLL
for(int i = 0; i < 4; i++)
{
int idx = i * NR_THREADS + t;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/materialflags.compute


GroupMemoryBarrierWithGroupSync();
uint materialFeatureFlags = g_BaseFeatureFlags; // Contain all lightFeatures or 0 (depends if we enable light classification or not)
[unroll]
UNITY_UNROLL
for(int i = 0; i < 4; i++)
{
int idx = i * NR_THREADS + threadID;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/Resources/VolumetricLighting.compute


tileCoord = WaveReadFirstLane(tileCoord);
}
[branch] if (voxelCoord.x >= (uint)_VBufferResolution.x ||
UNITY_BRANCH if (voxelCoord.x >= (uint)_VBufferResolution.x ||
voxelCoord.y >= (uint)_VBufferResolution.y)
{
return;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VBuffer.hlsl


// TODO: add the proper sampler support.
bool isInBounds = Min3(uv.x, uv.y, d) > 0 && Max3(uv.x, uv.y, d) < 1;
[branch] if (clampToEdge || isInBounds)
UNITY_BRANCH if (clampToEdge || isInBounds)
{
#if 1
// Ignore non-linearity (for performance reasons) at the cost of accuracy.

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/LayeredLit/LayeredLitData.hlsl


// If a top layer doesn't use the full weight, the remaining can be use by the following layer.
float weightsSum = 0.0;
[unroll]
UNITY_UNROLL
for (int i = _LAYER_COUNT - 1; i >= 0; --i)
{
outWeights[i] = min(masks[i], (1.0 - weightsSum));

12
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


float intensity = max(0, attenuation * NdotL); // Warning: attenuation can be greater than 1 due to the inverse square attenuation (when position is close to light)
// Note: We use NdotL here to early out, but in case of clear coat this is not correct. But we are ok with this
[branch] if (intensity > 0.0)
UNITY_BRANCH if (intensity > 0.0)
{
BSDF(V, L, NdotL, posInput.positionWS, preLightData, bsdfData, lighting.diffuse, lighting.specular);

[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
UNITY_BRANCH if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, ClampNdotV(preLightData.NdotV), attenuation * lightData.diffuseScale);

float intensity = max(0, attenuation * NdotL); // Warning: attenuation can be greater than 1 due to the inverse square attenuation (when position is close to light)
// Note: We use NdotL here to early out, but in case of clear coat this is not correct. But we are ok with this
[branch] if (intensity > 0.0)
UNITY_BRANCH if (intensity > 0.0)
{
// Simulate a sphere light with this hack
// Note that it is not correct with our pre-computation of PartLambdaV (mean if we disable the optimization we will not have the

lighting.specular *= intensity * lightData.specularScale;
}
[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
UNITY_BRANCH if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, ClampNdotV(preLightData.NdotV), attenuation * lightData.diffuseScale);

// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;
[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
UNITY_BRANCH if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,

// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;
[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
UNITY_BRANCH if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitDataDisplacement.hlsl


float planeHeight;
// Perform a POM in each direction and modify appropriate texture coordinate
[branch] if (layerTexCoord.triplanarWeights.x >= 0.001)
UNITY_BRANCH if (layerTexCoord.triplanarWeights.x >= 0.001)
{
ppdParam.uv = layerTexCoord.base.uvZY;
float3 viewDirTS = float3(uvZY, abs(V.x));

NdotV += layerTexCoord.triplanarWeights.x * viewDirTS.z;
}
[branch] if (layerTexCoord.triplanarWeights.y >= 0.001)
UNITY_BRANCH if (layerTexCoord.triplanarWeights.y >= 0.001)
{
ppdParam.uv = layerTexCoord.base.uvXZ;
float3 viewDirTS = float3(uvXZ, abs(V.y));

NdotV += layerTexCoord.triplanarWeights.y * viewDirTS.z;
}
[branch] if (layerTexCoord.triplanarWeights.z >= 0.001)
UNITY_BRANCH if (layerTexCoord.triplanarWeights.z >= 0.001)
{
ppdParam.uv = layerTexCoord.base.uvXY;
float3 viewDirTS = float3(uvXY, abs(V.z));

22
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.compute


int2 cacheCoord = pixelCoord - cacheOffset;
bool isInCache = max((uint)cacheCoord.x, (uint)cacheCoord.y) < TEXTURE_CACHE_SIZE_1D;
[branch] if (isInCache)
UNITY_BRANCH if (isInCache)
{
return LoadSampleFromCacheMemory(cacheCoord);
}

uint2 pixelCoord = groupOffset + groupCoord;
int2 cacheOffset = (int2)groupOffset - TEXTURE_CACHE_BORDER;
[branch] if (groupThreadId == 0)
UNITY_BRANCH if (groupThreadId == 0)
{
float stencilRef = STENCILLIGHTINGUSAGE_SPLIT_LIGHTING;

// Wait for the LDS.
GroupMemoryBarrierWithGroupSync();
[branch] if (!processGroup) { return; }
UNITY_BRANCH if (!processGroup) { return; }
float3 centerIrradiance = LOAD_TEXTURE2D(_IrradianceSource, pixelCoord).rgb;
float centerDepth = 0;

// Save some bandwidth by only loading depth values for SSS pixels.
[branch] if (passedStencilTest)
UNITY_BRANCH if (passedStencilTest)
{
centerDepth = LOAD_TEXTURE2D(_DepthTexture, pixelCoord).r;
centerViewZ = LinearEyeDepth(centerDepth, _ZBufferParams);

uint numBorderQuadsPerWave = TEXTURE_CACHE_SIZE_1D / 2 - 1;
uint halfCacheWidthInQuads = TEXTURE_CACHE_SIZE_1D / 4;
[branch] if (quadIndex < numBorderQuadsPerWave)
UNITY_BRANCH if (quadIndex < numBorderQuadsPerWave)
{
// Fetch another texel into the LDS.
uint2 startQuad = halfCacheWidthInQuads * DeinterleaveQuad(waveIndex);

float viewZ2 = 0;
// Save some bandwidth by only loading depth values for SSS pixels.
[branch] if (TestLightingForSSS(irradiance2))
UNITY_BRANCH if (TestLightingForSSS(irradiance2))
{
viewZ2 = LinearEyeDepth(LOAD_TEXTURE2D(_DepthTexture, pixelCoord2).r, _ZBufferParams);
}

GroupMemoryBarrierWithGroupSync();
#endif
[branch] if (!passedStencilTest) { return; }
UNITY_BRANCH if (!passedStencilTest) { return; }
PositionInputs posInput = GetPositionInput(pixelCoord, _ScreenSize.zw);

uint texturingMode = GetSubsurfaceScatteringTexturingMode(profileID);
float3 albedo = ApplySubsurfaceScatteringTexturingMode(texturingMode, sssData.diffuseColor);
[branch] if (distScale == 0 || maxDistInPixels < 1)
UNITY_BRANCH if (distScale == 0 || maxDistInPixels < 1)
{
#if SSS_DEBUG_LOD
StoreResult(pixelCoord, float3(0, 0, 1));

int i, n; // Declare once to avoid the warning from the Unity shader compiler.
[unroll]
UNITY_UNROLL
for (i = 1, n = SSS_N_SAMPLES_FAR_FIELD; i < n; i++)
{
// Integrate over the image or tangent plane in the view space.

totalIrradiance, totalWeight);
}
[branch] if (!useNearFieldKernel)
UNITY_BRANCH if (!useNearFieldKernel)
[unroll]
UNITY_UNROLL
for (i = SSS_N_SAMPLES_FAR_FIELD, n = SSS_N_SAMPLES_NEAR_FIELD; i < n; i++)
{
// Integrate over the image or tangent plane in the view space.

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.shader


// We use the value of 1 instead of 0.5 as an optimization.
float maxDistInPixels = maxDistance * max(pixelsPerCm.x, pixelsPerCm.y);
[branch]
UNITY_BRANCH
if (distScale == 0 || maxDistInPixels < 1)
{
#if SSS_DEBUG_LOD

float3 totalIrradiance = sampleWeight * sampleIrradiance;
float3 totalWeight = sampleWeight;
[unroll]
UNITY_UNROLL
for (int i = 1; i < SSS_BASIC_N_SAMPLES; i++)
{
samplePosition = posInput.positionSS + rotatedDirection * _FilterKernelsBasic[profileID][i].a;

48
TestbedPipelines/Fptl/LightingTemplate.hlsl


ind.diffuse = 0;
ind.specular = 0;
ShadowContext shadowContext = InitShadowContext();
ShadowContext shadowContext = InitShadowContext();
float3 ints = 0;

UnityLight light;
light.dir.xyz = mul((float3x3) g_mViewToWorld, -lightData.lightAxisZ).xyz;
int shadowIdx = asint(lightData.shadowLightIndex);
[branch]
if (shadowIdx >= 0)
{
float shadow = GetDirectionalShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, normalize(light.dir.xyz));
atten *= shadow;
}
int shadowIdx = asint(lightData.shadowLightIndex);
UNITY_BRANCH
if (shadowIdx >= 0)
{
float shadow = GetDirectionalShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, normalize(light.dir.xyz));
atten *= shadow;
}
light.color.xyz = lightData.color.xyz * atten;

const bool bHasCookie = (lgtDat.flags&IS_CIRCULAR_SPOT_SHAPE)==0; // all square spots have cookies
float d0 = 0.65;
float4 angularAtt = float4(1,1,1,smoothstep(0.0, 1.0-d0, 1.0-length(cookCoord)));
[branch]if(bHasCookie)
UNITY_BRANCH if(bHasCookie)
{
cookCoord = cookCoord*0.5 + 0.5;
angularAtt = UNITY_SAMPLE_TEX2DARRAY_LOD(_spotCookieTextures, float3(cookCoord, lgtDat.sliceIndex), 0.0);

UnityLight light;
light.dir.xyz = mul((float3x3) g_mViewToWorld, vL).xyz; //unity_CameraToWorld
int shadowIdx = asint(lgtDat.shadowLightIndex);
[branch]
if (shadowIdx >= 0)
{
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, float4(normalize(light.dir.xyz), dist));
atten *= shadow;
}
int shadowIdx = asint(lgtDat.shadowLightIndex);
UNITY_BRANCH
if (shadowIdx >= 0)
{
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, normalize(light.dir.xyz), dist);
atten *= shadow;
}
light.color.xyz = lgtDat.color.xyz*atten*angularAtt.xyz;

float4 cookieColor = float4(1,1,1,1);
const bool bHasCookie = (lgtDat.flags&HAS_COOKIE_TEXTURE)!=0;
[branch]if(bHasCookie)
UNITY_BRANCH if(bHasCookie)
{
float3 cookieCoord = -float3(dot(vL, lgtDat.lightAxisX.xyz), dot(vL, lgtDat.lightAxisY.xyz), dot(vL, lgtDat.lightAxisZ.xyz)); // negate to make vL a fromLight vector
cookieColor = UNITY_SAMPLE_ABSTRACT_CUBE_ARRAY_LOD(_pointCookieTextures, float4(cookieCoord, lgtDat.sliceIndex), 0.0);

int shadowIdx = asint(lgtDat.shadowLightIndex);
[branch]
if (shadowIdx >= 0)
{
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, float4(vLw, dist));
atten *= shadow;
}
int shadowIdx = asint(lgtDat.shadowLightIndex);
UNITY_BRANCH
if (shadowIdx >= 0)
{
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, vLw, dist);
atten *= shadow;
}
UnityLight light;
light.color.xyz = lgtDat.color.xyz*atten*cookieColor.xyz;

9
TestbedPipelines/Fptl/Shadow.hlsl


#define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL // Define this to provide custom implementations of GetPunctualShadowAttenuation
#define SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL // Define this to provide custom implementations of GetDirectionalShadowAttenuation
#define SHADOW_USE_ONLY_VIEW_BASED_BIASING 1 // don't use the normal for biasing
#include "ShadowContext.hlsl"

#endif
#ifdef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist )
return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L, L_dist );
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L, float2 unPositionSS )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist, float2 unPositionSS )
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
#endif

12
TestbedPipelines/OnTileDeferredPipeline/Shaders/LightingTemplate.hlsl


float4 uvCookie = mul (unity_WorldToLight, float4(wpos,1));
colorCookie = tex2Dlod (_LightTexture0, float4(uvCookie.xy / uvCookie.w, 0, 0));
[branch]if (_useLegacyCookies) {
UNITY_BRANCH if (_useLegacyCookies) {
colorCookie.xyz = 1;
}

atten *= tex2D (_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL;
if (_LightIndexForShadowMatrixArray >= 0)
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, float4(lightDir, dist));
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, lightDir, dist);
// directional light case
#elif defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)

if (_LightIndexForShadowMatrixArray >= 0)
atten *= GetDirectionalShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, 0.0.xxx);
atten *= GetDirectionalShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, lightDir);
[branch]if (_useLegacyCookies) {
UNITY_BRANCH if (_useLegacyCookies) {
colorCookie.xyz = 1;
}
atten *= colorCookie.w;

float atten = tex2D (_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL;
if (_LightIndexForShadowMatrixArray >= 0)
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, float4(lightDir, dist));
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, lightDir, dist);
[branch]if (_useLegacyCookies) {
UNITY_BRANCH if (_useLegacyCookies) {
colorCookie.xyz = 1;
}
atten *= colorCookie.w;

9
TestbedPipelines/OnTileDeferredPipeline/Shaders/Shadow.hlsl


#define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL // Define this to provide custom implementations of GetPunctualShadowAttenuation
#define SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL // Define this to provide custom implementations of GetDirectionalShadowAttenuation
#define SHADOW_USE_ONLY_VIEW_BASED_BIASING 1 // don't use the normal for biasing
#include "ShadowContext.hlsl"

#endif
#ifdef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist )
return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_PunctualDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L, L_dist );
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float4 L, float2 unPositionSS )
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float L_dist, float2 unPositionSS )
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return GetPunctualShadowAttenuation( shadowContext, positionWS, normalWS, shadowDataIndex, L, L_dist );
}
#endif

26
TestbedPipelines/OnTileDeferredPipeline/Shaders/UnityStandardForwardMobile.cginc


# error unsupported shader api
#endif
#include "CoreRP/ShaderLibrary/API/Validate.hlsl"
#include "../../Fptl/Shadow.hlsl"
#include "Shadow.hlsl"
struct VertexOutputForwardNew
{

float atten = 1;
int shadowIdx = gPerLightData[lightIndex].y;
[branch]
UNITY_BRANCH
float shadow = GetDirectionalShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, 0.0.xxx);
float shadow = GetDirectionalShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, -gLightDirection[lightIndex].xyz);
atten *= shadow;
}

const bool bHasCookie = gPerLightData[lightIndex].z >= 0;
[branch]if(bHasCookie)
UNITY_BRANCH if(bHasCookie)
[branch]if(_useLegacyCookies)
UNITY_BRANCH if(_useLegacyCookies)
{
cookieColor.xyz = 1;
}

float4 cookieColor = float4(1,1,1,1);
const bool bHasCookie = gPerLightData[lightIndex].z >= 0;
[branch]if(bHasCookie)
UNITY_BRANCH if(bHasCookie)
{
float4 uvCookie = mul (gLightMatrix[lightIndex], float4(vLw,1));
float3 cookieCoord = -uvCookie.xyz / uvCookie.w;

[branch]if(_useLegacyCookies)
UNITY_BRANCH if(_useLegacyCookies)
[branch]
UNITY_BRANCH
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, float4(vLw, dist));
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, vLw, dist);
atten *= shadow;
}

float d0 = 0.65;
float4 angularAtt = float4(1,1,1,smoothstep(0.0, 1.0-d0, 1.0-length(2*cookCoord-1)));
const bool bHasCookie = gPerLightData[lightIndex].z >= 0;
[branch]if(bHasCookie)
UNITY_BRANCH if(bHasCookie)
[branch]if(_useLegacyCookies)
UNITY_BRANCH if(_useLegacyCookies)
{
angularAtt.xyz = 1;
}

[branch]
UNITY_BRANCH
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, float4(vLw, dist));
float shadow = GetPunctualShadowAttenuation(shadowContext, vPw, 0.0.xxx, shadowIdx, vLw, dist);
atten *= shadow;
}

36
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowClear.shader


Shader "Hidden/ScriptableRenderPipeline/ShadowClear"
{
HLSLINCLUDE
#pragma target 4.5
#pragma only_renderers d3d11 ps4 xboxone vulkan metal
#include "CoreRP/ShaderLibrary/Common.hlsl"
ENDHLSL
SubShader
{
Pass
{
Name "ClearShadow"
ZTest Always
Cull Off
ZWrite On
HLSLPROGRAM
#pragma vertex Vert_0
#pragma fragment Frag
float4 Vert_0( uint vertexID : VERTEXID_SEMANTIC ) : SV_POSITION
{
return GetFullScreenTriangleVertexPosition( vertexID, UNITY_RAW_FAR_CLIP_VALUE );
}
float4 Frag() : SV_Target{ return 0.0.xxxx; }
ENDHLSL
}
}
Fallback Off
}

9
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/Resources/ShadowClear.shader.meta


fileFormatVersion: 2
guid: e3cab24f27741f44d8af1e94d006267c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

24
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalShadowData.cs


using UnityEngine.Experimental.Rendering;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class HDAdditionalShadowData
{
public static void InitDefaultHDAdditionalShadowData(AdditionalShadowData shadowData)
{
// Update bias control for HD
// bias control default value based on empirical experiment
shadowData.viewBiasMin = 0.2f;
shadowData.viewBiasMax = 10.0f;
shadowData.viewBiasScale = 1.0f;
shadowData.normalBiasMin = 0.5f;
shadowData.normalBiasMax = 0.5f;
shadowData.normalBiasScale = 1.0f;
shadowData.sampleBiasScale = false;
shadowData.edgeLeakFixup = true;
shadowData.edgeToleranceNormal = true;
shadowData.edgeTolerance = 1.0f;
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalShadowData.cs.meta


fileFormatVersion: 2
guid: f6ddd04671709d04cba20d06452e9f6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightShaderLibrary.meta


fileFormatVersion: 2
guid: 82878e51519f2c1448345504eda40041
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存