浏览代码

Added dithering to cascade transitions. There are now two functions to choose from, to either blend between cascades doing two fetches, or dither doing just one fetch.

Added functions to query the world space position of a shadowmap sample.
/RenderPassXR_Sandbox
uygar 7 年前
当前提交
876f9979
共有 9 个文件被更改,包括 440 次插入73 次删除
  1. 12
      Assets/ScriptableRenderPipeline/Core/Shadow/Shadow.cs
  2. 2
      Assets/ScriptableRenderPipeline/Core/Shadow/ShadowBase.cs
  3. 12
      Assets/ScriptableRenderPipeline/Core/Shadow/ShadowBase.cs.hlsl
  4. 56
      Assets/ScriptableRenderPipeline/Core/Shadow/ShadowUtilities.cs
  5. 2
      Assets/ScriptableRenderPipeline/Fptl/ShadowDispatch.hlsl
  6. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/ShadowDispatch.hlsl
  7. 2
      Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/Shadow.hlsl
  8. 406
      Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl
  9. 19
      Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/ShadowTexFetch.hlsl

12
Assets/ScriptableRenderPipeline/Core/Shadow/Shadow.cs


float texelSizeX = 1.0f, texelSizeY = 1.0f;
CachedEntry ce = m_EntryCache[ceIdx];
// modify
Matrix4x4 vp;
Matrix4x4 vp, invvp;
vp = ShadowUtils.ExtractPointLightMatrix( lights[sr.index], key.faceIdx, 2.0f, out ce.current.view, out ce.current.proj, out ce.current.lightDir, out ce.current.splitData );
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 );
vp = ShadowUtils.ExtractSpotLightMatrix( lights[sr.index], out ce.current.view, out ce.current.proj, 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 );
vp = ShadowUtils.ExtractDirectionalLightMatrix( lights[sr.index], key.faceIdx, cascadeCnt, cascadeRatios, nearPlaneOffset, width, height, out ce.current.view, out ce.current.proj, 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 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 )
{

}
}
else
vp = Matrix4x4.identity; // should never happen, though
vp = invvp = Matrix4x4.identity; // should never happen, though
if (cameraRelativeRendering)
{
Vector3 camPosWS = camera.transform.position;

m_EntryCache[ceIdx] = ce;
sd.worldToShadow = vp.transpose; // apparently we need to transpose matrices that are sent to HLSL
sd.shadowToWorld = invvp.transpose;
sd.textureSize = new Vector4( m_Width, m_Height, ce.current.viewport.width, ce.current.viewport.height );
sd.texelSizeRcp = new Vector4( m_WidthRcp, m_HeightRcp, 1.0f / ce.current.viewport.width, 1.0f / ce.current.viewport.height );
sd.PackShadowmapId( m_TexSlot, m_SampSlot, ce.current.slice );
sd.PackShadowType( sr.shadowType, sanitizedAlgo );

2
Assets/ScriptableRenderPipeline/Core/Shadow/ShadowBase.cs


{
// 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 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 uint id; // packed texture id, sampler id and slice idx
public uint shadowType; // determines the shadow algorithm, i.e. which map to sample and how to interpret the data

12
Assets/ScriptableRenderPipeline/Core/Shadow/ShadowBase.cs.hlsl


//
// This file was automatically generated from Assets/ScriptableRenderPipeline/Core/Shadow/ShadowBase.cs. Please don't edit by hand.
// This file was automatically generated from Assets/ScriptableRenderPipeline/core/Shadow/ShadowBase.cs. Please don't edit by hand.
//
#ifndef SHADOWBASE_CS_HLSL

struct ShadowData
{
float4x4 worldToShadow;
float4x4 shadowToWorld;
float4 textureSize;
float4 texelSizeRcp;
uint id;
uint shadowType;

{
return value.worldToShadow;
}
float4x4 GetShadowToWorld(ShadowData value)
{
return value.shadowToWorld;
}
}
float4 GetTextureSize(ShadowData value)
{
return value.textureSize;
}
float4 GetTexelSizeRcp(ShadowData value)
{

56
Assets/ScriptableRenderPipeline/Core/Shadow/ShadowUtilities.cs


}
public class ShadowUtils
{
public static Matrix4x4 ExtractSpotLightMatrix( VisibleLight vl, out Matrix4x4 view, out Matrix4x4 proj, out Vector4 lightDir, out ShadowSplitData splitData )
public static void InvertView( ref Matrix4x4 view, out Matrix4x4 invview )
{
invview = Matrix4x4.zero;
invview.m00 = view.m00; invview.m01 = view.m10; invview.m02 = view.m20;
invview.m10 = view.m01; invview.m11 = view.m11; invview.m12 = view.m21;
invview.m20 = view.m02; invview.m21 = view.m12; invview.m22 = view.m22;
invview.m33 = 1.0f;
invview.m03 = -(invview.m00 * view.m03 + invview.m01 * view.m13 + invview.m02 * view.m23);
invview.m13 = -(invview.m10 * view.m03 + invview.m11 * view.m13 + invview.m12 * view.m23);
invview.m23 = -(invview.m20 * view.m03 + invview.m21 * view.m13 + invview.m22 * view.m23);
}
public static void InvertOrthographic( ref Matrix4x4 proj, ref Matrix4x4 view, out Matrix4x4 vpinv )
{
Matrix4x4 invview;
InvertView( ref view, out invview );
Matrix4x4 invproj = Matrix4x4.zero;
invproj.m00 = 1.0f / proj.m00;
invproj.m11 = 1.0f / proj.m11;
invproj.m22 = 1.0f / proj.m22;
invproj.m33 = 1.0f;
invproj.m03 = proj.m03 * invproj.m00;
invproj.m13 = proj.m13 * invproj.m11;
invproj.m23 = - proj.m23 * invproj.m22;
vpinv = invview * invproj;
}
public static void InvertPerspective( ref Matrix4x4 proj, ref Matrix4x4 view, out Matrix4x4 vpinv )
{
Matrix4x4 invview;
InvertView(ref view, out invview);
Matrix4x4 invproj = Matrix4x4.zero;
invproj.m00 = 1.0f / proj.m00;
invproj.m03 = proj.m02 * invproj.m00;
invproj.m11 = 1.0f / proj.m11;
invproj.m13 = proj.m12 * invproj.m11;
invproj.m22 = 0.0f;
invproj.m23 = -1.0f;
invproj.m33 = proj.m22 / proj.m23;
invproj.m32 = invproj.m33 / proj.m22;
vpinv = invview * invproj;
}
public static Matrix4x4 ExtractSpotLightMatrix( VisibleLight vl, out Matrix4x4 view, out Matrix4x4 proj, out Matrix4x4 vpinverse, out Vector4 lightDir, out ShadowSplitData splitData )
{
splitData = new ShadowSplitData();
splitData.cullingSphere.Set( 0.0f, 0.0f, 0.0f, float.NegativeInfinity );

float fov = vl.spotAngle;
proj = Matrix4x4.Perspective(fov, 1.0f, znear, zfar);
// and the compound
InvertPerspective( ref proj, ref view, out vpinverse );
public static Matrix4x4 ExtractPointLightMatrix( VisibleLight vl, uint faceIdx, float fovBias, out Matrix4x4 view, out Matrix4x4 proj, out Vector4 lightDir, out ShadowSplitData splitData )
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 )
{
Debug.Assert( faceIdx <= (uint) CubemapFace.NegativeZ, "Tried to extract cubemap face " + faceIdx + "." );

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 );
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 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 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();

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;
}

2
Assets/ScriptableRenderPipeline/Fptl/ShadowDispatch.hlsl


SamplerComparisonState compSamp = shadowContext.compSamplers[0];
uint algo = GPUSHADOWALGORITHM_PCF_9TAP;
return EvalShadow_CascadedDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_CascadedDepth_Blend( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
}
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float2 unPositionSS )

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/ShadowDispatch.hlsl


SamplerComparisonState compSamp = shadowContext.compSamplers[SHADOW_DISPATCH_DIR_SMP];
uint algo = SHADOW_DISPATCH_DIR_ALG;
return EvalShadow_CascadedDepth( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_CascadedDepth_Blend( shadowContext, algo, tex, compSamp, positionWS, normalWS, shadowDataIndex, L );
}
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float2 unPositionSS )

2
Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/Shadow.hlsl


// directional light shadows
float GetDirectionalShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L )
{
return EvalShadow_CascadedDepth( shadowContext, positionWS, normalWS, shadowDataIndex, L );
return EvalShadow_CascadedDepth_Blend( shadowContext, positionWS, normalWS, shadowDataIndex, L );
}
float GetDirectionalShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int shadowDataIndex, float3 L, float2 unPositionSS )
{

406
Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl


return EvalShadow_GetTexcoords( sd, positionWS, ndc, false );
}
uint2 EvalShadow_GetTexcoords( ShadowData sd, float3 positionWS, out float2 closestSampleNDC )
{
float4 posCS = mul( float4( positionWS, 1.0 ), sd.worldToShadow );
float2 posNDC = posCS.xy / posCS.w;
// calc TCs
float2 posTC = posNDC * 0.5 + 0.5;
closestSampleNDC = (floor(posTC * sd.textureSize.zw) + 0.5) * sd.texelSizeRcp.zw * 2.0 - 1.0.xx;
return (posTC * sd.scaleOffset.xy + sd.scaleOffset.zw) * sd.textureSize.xy;
}
int EvalShadow_GetCubeFaceID( float3 dir )
{
// TODO: Use faceID intrinsic on console

float 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);
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
}
#define EvalShadow_PunctualDepth_( _samplerType ) \

return offset + 4;
}
float EvalShadow_CascadedDepth( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float3 L )
float EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float3 L )
{
// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];

return shadow;
}
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
uint orig_payloadOffset = payloadOffset; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
\
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
shadowSplitIndex++; \
float shadow1 = 1.0; \
if( shadowSplitIndex < kMaxShadowCascades ) \
{ \
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex - 1]; \
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex].xyz ); \
float3 wposDir = normalize( -splitSphere.xyz + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
shadow1 = shadow; \
\
[branch] \
if( alpha > 0.0 ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false ); \
/* sample the texture */ \
UnpackShadowmapId( sd.id, slice ); \
\
if( all( abs( posNDC.xy ) <= (1.0 - sd.texelSizeRcp.zw * 0.5) ) ) \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \
return shadow; \
}
EvalShadow_CascadedDepth_( SamplerComparisonState )
EvalShadow_CascadedDepth_( SamplerState )
#undef EvalShadow_CascadedDepth_
float EvalShadow_hash12( float2 pos )
{
float3 p3 = frac( pos.xyx * float3( 443.8975, 397.2973, 491.1871 ) );
p3 += dot( p3, p3.yzx + 19.19 );
return frac( (p3.x + p3.y) * p3.z );
}
float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float3 L )
{
// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
float relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
if( shadowSplitIndex < 0 )
return 1.0;
float4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
float4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
float border = borders[shadowSplitIndex];
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
uint orig_payloadOffset = payloadOffset; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
\
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
shadowSplitIndex++; \
float shadow1 = 1.0; \
if( shadowSplitIndex < kMaxShadowCascades ) \
{ \
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex - 1]; \
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex].xyz ); \
float3 wposDir = normalize( -splitSphere.xyz + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
shadow1 = shadow; \
\
[branch] \
if( alpha > 0.0 ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false ); \
/* sample the texture */ \
UnpackShadowmapId( sd.id, slice ); \
\
if( all( abs( posNDC.xy ) <= (1.0 - sd.texelSizeRcp.zw * 0.5) ) ) \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \
return shadow; \
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// normal based bias
float3 orig_pos = positionWS;
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
// get shadowmap texcoords
float3 posNDC;
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
if( shadowSplitIndex < (kMaxShadowCascades-1) )
{
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex];
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex+1].xyz );
float3 wposDir = normalize( -splitSphere.xyz + positionWS );
float cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
if( step( EvalShadow_hash12( posTC.xy ), alpha ) )
{
shadowSplitIndex++;
sd = shadowContext.shadowDatas[index + 2 + shadowSplitIndex];
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex+1] * sd.texelSizeRcp.zw, sd.normalBias );
posTC = EvalShadow_GetTexcoords( sd, positionWS );
}
}
// sample the texture
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
uint shadowType, shadowAlgorithm;
UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha );
}
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
if( shadowSplitIndex < (kMaxShadowCascades-1) ) \
{ \
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex]; \
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex+1].xyz ); \
float3 wposDir = normalize( -splitSphere.xyz + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
\
if( step( EvalShadow_hash12( posTC.xy ), alpha ) ) \
{ \
sd = shadowContext.shadowDatas[index + 2 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex+1] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
} \
} \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha ); \
//------------------------------------------------------------------------------------------------------------------------------------
float3 EvalShadow_GetClosestSample_Point( ShadowContext shadowContext, float3 positionWS, int index, float3 L )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
// load the right shadow data for the current face
int faceIndex = EvalShadow_GetCubeFaceID( L ) + 1;
sd = shadowContext.shadowDatas[index + faceIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Point( ShadowContext shadowContext, Texture2DArray tex, float3 positionWS, int index, float3 L )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
// load the right shadow data for the current face
int faceIndex = EvalShadow_GetCubeFaceID( L ) + 1;
sd = shadowContext.shadowDatas[index + faceIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
float slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Spot( ShadowContext shadowContext, float3 positionWS, int index )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Spot( ShadowContext shadowContext, Texture2DArray tex, float3 positionWS, int index )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
float slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Punctual( ShadowContext shadowContext, float3 positionWS, int index, float3 L )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
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;
sd = shadowContext.shadowDatas[index + faceIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Punctual( ShadowContext shadowContext, Texture2DArray tex, float3 positionWS, int index, float3 L )
{
// get the algorithm
ShadowData sd = shadowContext.shadowDatas[index];
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;
sd = shadowContext.shadowDatas[index + faceIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
float slice;
UnpackShadowmapId(sd.id, slice);
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Cascade( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float4 L )
{
// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
float relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
if( shadowSplitIndex < 0 )
return 1.0;
float4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
float4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LoadShadow_T2DA( shadowContext, texIdx, texelIdx, slice );
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}

19
Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/ShadowTexFetch.hlsl


// Shader model >= 5.1
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_COMP( _Tex2DArraySlots , _SamplerCompSlots ) float4 SampleCompShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, float3 tcs, float slice ) { return SAMPLE_TEXTURE2D_ARRAY_SHADOW( ctxt.tex2DArray[texIdx], ctxt.compSamplers[sampIdx], tcs, slice ); }
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_SAMP( _Tex2DArraySlots , _SamplerSlots ) float4 SampleShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, float2 tcs, float slice, float lod = 0.0 ) { return SAMPLE_TEXTURE2D_ARRAY_LOD( ctxt.tex2DArray[texIdx], ctxt.samplers[sampIdx], tcs, slice, lod ); }
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ) float4 LoadShadow_T2DA( ShadowContext ctxt, uint texIdx, uint2 tcs, uint slice, uint lod = 0 ) { return LOAD_TEXTURE2D_ARRAY_LOD( ctxt.tex2DArray[texIdx], tcs, slice, lod ).x; }
# define SHADOW_DEFINE_SAMPLING_FUNC_TCA_COMP( _TexCubeArraySlots, _SamplerCompSlots ) float4 SampleCompShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, float4 tcs, float cubeIdx ) { return SAMPLE_TEXTURECUBE_ARRAY_SHADOW( ctxt.texCubeArray[texIdx], ctxt.compSamplers[sampIdx], tcs, cubeIdx );}
# define SHADOW_DEFINE_SAMPLING_FUNC_TCA_SAMP( _TexCubeArraySlots, _SamplerSlots ) float4 SampleShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, float3 tcs, float cubeIdx, float lod = 0.0 ) { return SAMPLE_TEXTURECUBE_ARRAY_LOD( ctxt.texCubeArray[texIdx], ctxt.samplers[sampIdx], tcs, cubeIdx, lod ); }

return res; \
}
# define SHADOW_DEFINE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ) \
float LoadShadow_T2DA( ShadowContext ctxt, uint texIdx, uint2 tcs, uint slice, uint lod = 0 ) \
{ \
float res = 1.0; \
[unroll] for( uint i = 0; i < _Tex2DArraySlots; i++ ) \
{ \
[branch] if( i == texIdx ) \
{ \
res = LOAD_TEXTURE2D_ARRAY_LOD( ctxt.tex2DArray[i], tcs, slice, lod ).x; \
break; \
} \
} \
return res; \
}
# define SHADOW_DEFINE_SAMPLING_FUNC_TCA_COMP( _TexCubeArraySlots, _SamplerCompSlots ) \
float4 SampleCompShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, float4 tcs, float cubeIdx ) \
{ \

// helper macro to suppress code generation if _cnt is 0
#define SHADOW_DECLARE_SAMPLING_FUNC_T2DA_COMP( _Tex2DArraySlots , _SamplerCompSlots ) float4 SampleCompShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, float3 tcs, float slice );
#define SHADOW_DECLARE_SAMPLING_FUNC_T2DA_SAMP( _Tex2DArraySlots , _SamplerSlots ) float4 SampleShadow_T2DA( ShadowContext ctxt, uint texIdx, uint sampIdx, float2 tcs, float slice, float lod = 0.0 );
#define SHADOW_DECLARE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ) float4 LoadShadow_T2DA( ShadowContext ctxt, uint texIdx, uint2 tcs, uint slice, uint lod = 0 );
#define SHADOW_DECLARE_SAMPLING_FUNC_TCA_COMP( _TexCubeArraySlots, _SamplerCompSlots ) float4 SampleCompShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, float4 tcs, float cubeIdx );
#define SHADOW_DECLARE_SAMPLING_FUNC_TCA_SAMP( _TexCubeArraySlots, _SamplerSlots ) float4 SampleShadow_TCA( ShadowContext ctxt, uint texIdx, uint sampIdx, float3 tcs, float cubeIdx, float lod = 0.0 );

#define SHADOW_DEFINE_SAMPLING_FUNCS( _Tex2DArraySlots, _TexCubeArraySlots, _SamplerCompSlots, _SamplerSlots ) \
SHADOW_CHECK( _Tex2DArraySlots , SHADOW_CHECK_ALT( _SamplerCompSlots, SHADOW_DEFINE_SAMPLING_FUNC_T2DA_COMP( _Tex2DArraySlots, _SamplerCompSlots ), SHADOW_DECLARE_SAMPLING_FUNC_T2DA_COMP( _Tex2DArraySlots, _SamplerCompSlots ) ) ) \
SHADOW_CHECK( _Tex2DArraySlots , SHADOW_CHECK_ALT( _SamplerSlots , SHADOW_DEFINE_SAMPLING_FUNC_T2DA_SAMP( _Tex2DArraySlots, _SamplerSlots ), SHADOW_DECLARE_SAMPLING_FUNC_T2DA_SAMP( _Tex2DArraySlots, _SamplerSlots ) ) ) \
SHADOW_CHECK_ALT( _Tex2DArraySlots , SHADOW_DEFINE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ), SHADOW_DECLARE_SAMPLING_FUNC_T2DA_LOAD( _Tex2DArraySlots ) ) \
SHADOW_CHECK( _TexCubeArraySlots, SHADOW_CHECK_ALT( _SamplerCompSlots, SHADOW_DEFINE_SAMPLING_FUNC_TCA_COMP(_TexCubeArraySlots, _SamplerCompSlots ), SHADOW_DECLARE_SAMPLING_FUNC_TCA_COMP(_TexCubeArraySlots, _SamplerCompSlots ) ) ) \
SHADOW_CHECK( _TexCubeArraySlots, SHADOW_CHECK_ALT( _SamplerSlots , SHADOW_DEFINE_SAMPLING_FUNC_TCA_SAMP(_TexCubeArraySlots, _SamplerSlots ), SHADOW_DECLARE_SAMPLING_FUNC_TCA_SAMP(_TexCubeArraySlots, _SamplerSlots ) ) )
正在加载...
取消
保存