浏览代码

Added smooth cascade transitions to cascaded shadowmaps.

/RenderPassXR_Sandbox
uygar 7 年前
当前提交
178ae77f
共有 3 个文件被更改,包括 150 次插入26 次删除
  1. 11
      Assets/ScriptableRenderPipeline/Core/Shadow/AdditionalShadowData.cs
  2. 31
      Assets/ScriptableRenderPipeline/Core/Shadow/Shadow.cs
  3. 134
      Assets/ScriptableRenderPipeline/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl

11
Assets/ScriptableRenderPipeline/Core/Shadow/AdditionalShadowData.cs


[HideInInspector, SerializeField]
private float[] shadowCascadeRatios = new float[3] { 0.05f, 0.2f, 0.3f };
[HideInInspector, SerializeField]
private float[] shadowCascadeBorders = new float[4] { 0.2f, 0.2f, 0.2f, 0.2f };
[HideInInspector, SerializeField]
private int shadowAlgorithm;
[HideInInspector, SerializeField]
private int shadowVariant;

private ShadowData[] shadowDatas = new ShadowData[0];
public int cascadeCount { get { return shadowCascadeCount; } }
public void GetShadowCascades(out int cascadeCount, out float[] cascadeRatios) { cascadeCount = shadowCascadeCount; cascadeRatios = shadowCascadeRatios; }
public void GetShadowCascades(out int cascadeCount, out float[] cascadeRatios, out float[] cascadeBorders) { cascadeCount = shadowCascadeCount; cascadeRatios = shadowCascadeRatios; cascadeBorders = shadowCascadeBorders; }
public void GetShadowAlgorithm(out int algorithm, out int variant, out int precision) { algorithm = shadowAlgorithm; variant = shadowVariant; precision = shadowPrecision; }
public void SetShadowAlgorithm(int algorithm, int variant, int precision, int format, int[] data)
{

#pragma warning restore 414
UnityEditor.SerializedProperty m_ShadowCascadeCount;
UnityEditor.SerializedProperty m_ShadowCascadeRatios;
UnityEditor.SerializedProperty m_ShadowCascadeBorders;
public static void SetRegistry( ShadowRegistry registry ) { m_ShadowRegistry = registry; }

m_ShadowDatas = serializedObject.FindProperty( "shadowDatas" );
m_ShadowCascadeCount = serializedObject.FindProperty( "shadowCascadeCount" );
m_ShadowCascadeRatios = serializedObject.FindProperty( "shadowCascadeRatios" );
m_ShadowCascadeBorders = serializedObject.FindProperty( "shadowCascadeBorders" );
}
public override void OnInspectorGUI()
{

int newcnt = m_ShadowCascadeCount.intValue <= 0 ? 1 : (m_ShadowCascadeCount.intValue > kMaxCascades ? kMaxCascades : m_ShadowCascadeCount.intValue);
m_ShadowCascadeCount.intValue = newcnt;
m_ShadowCascadeRatios.arraySize = newcnt-1;
m_ShadowCascadeBorders.arraySize = newcnt;
}
for (int i = 0; i < m_ShadowCascadeBorders.arraySize; i++)
{
UnityEditor.EditorGUILayout.Slider( m_ShadowCascadeBorders.GetArrayElementAtIndex( i ), 0.0f, 1.0f, new GUIContent( "Transition " + i ) );
}
UnityEditor.EditorGUI.indentLevel--;
}

31
Assets/ScriptableRenderPipeline/Core/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];
protected float[] m_TmpBorders = new float[((k_MaxCascadesInShader+3)/4)*4];
protected ShadowAlgoVector m_SupportedAlgorithms = new ShadowAlgoVector( 0, false );
protected Material m_DebugMaterial = null;

int cascadeCnt = 0;
float[] cascadeRatios = null;
float[] cascadeBorders = null;
if( sr.shadowType == GPUShadowType.Directional )
{
AdditionalShadowData asd = lights[sr.index].light.GetComponent<AdditionalShadowData>();

asd.GetShadowCascades( out cascadeCnt, out cascadeRatios );
asd.GetShadowCascades( out cascadeCnt, out cascadeRatios, out cascadeBorders );
}

}
// read
float texelSizeX = 1.0f, texelSizeY = 1.0f;
CachedEntry ce = m_EntryCache[ceIdx];
// modify
Matrix4x4 vp;

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 );
m_TmpSplits[key.faceIdx] = ce.current.splitData.cullingSphere;
if( ce.current.splitData.cullingSphere.w != float.NegativeInfinity )
{
int face = (int)key.faceIdx;
texelSizeX = 2.0f / ce.current.proj.m00;
texelSizeY = 2.0f / ce.current.proj.m11;
m_TmpScales[face] = Mathf.Max( texelSizeX, texelSizeY );
m_TmpBorders[face] = cascadeBorders[face];
}
}
else
vp = Matrix4x4.identity; // should never happen, though

// 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 : 0;
uint payloadSize = sr.shadowType == GPUShadowType.Directional ? (k_MaxCascadesInShader + ((uint)m_TmpScales.Length / 4) + ((uint)m_TmpBorders.Length / 4)) : 0;
payloadSize += ShadowUtils.ExtractAlgorithm( sr.shadowAlgorithm ) == ShadowAlgorithm.PCF ? 1u : 0;
return payloadSize;
}

{
sp.Set( m_TmpSplits[i] );
payload[payloadOffset] = sp;
}
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++;
}
for( int i = 0; i < m_TmpBorders.Length; i += 4 )
{
sp.Set( m_TmpBorders[i+0], m_TmpBorders[i+1], m_TmpBorders[i+2], m_TmpBorders[i+3] );
payload[payloadOffset] = sp;
payloadOffset++;
}
}
ShadowAlgorithm algo; ShadowVariant vari; ShadowPrecision prec;

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 = 100.0f * l.shadowNormalBias;
sd.normalBias = 2.0f * l.shadowNormalBias;
shadowIndices.AddUnchecked( (int) shadowDatas.Count() );

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


}
// function called by spot, point and directional eval routines to calculate shadow coordinates
float3 EvalShadow_GetTexcoords( ShadowData sd, float3 positionWS )
float3 EvalShadow_GetTexcoords( ShadowData sd, float3 positionWS, out float3 posNDC, bool clampToRect )
float4 posCS = mul( float4( positionWS, 1.0 ), sd.worldToShadow );
float4 posCS = mul(float4(positionWS, 1.0), sd.worldToShadow);
float3 posNDC = posCS.xyz / posCS.w;
posNDC = posCS.xyz / posCS.w;
posTC.xy = clampToRect ? clamp( posTC.xy, sd.texelSizeRcp.zw*0.5, 1.0.xx - sd.texelSizeRcp.zw*0.5 ) : posTC.xy;
}
float3 EvalShadow_GetTexcoords( ShadowData sd, float3 positionWS )
{
float3 ndc;
return EvalShadow_GetTexcoords( sd, positionWS, ndc, false );
}
int EvalShadow_GetCubeFaceID( float3 dir )

//
// Directional shadows (cascaded shadow map)
//
int EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4] )
#define kMaxShadowCascades 4
int EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4], out float relDistance )
{
float3 fromCenter0 = positionWS.xyz - dirShadowSplitSpheres[0].xyz;
float3 fromCenter1 = positionWS.xyz - dirShadowSplitSpheres[1].xyz;

weights.yzw = saturate( weights.yzw - weights.xyz );
int idx = int( 4.0 - dot( weights, float4( 4.0, 3.0, 2.0, 1.0 ) ) );
relDistance = distances2[idx] / dirShadowSplitSphereSqRadii[idx];
int EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4] )
{
float relDist;
return EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDist );
}
uint EvalShadow_LoadSplitSpheres( ShadowContext shadowContext, int index, out float4 splitSpheres[4] )
{
uint offset = GetPayloadOffset( shadowContext.shadowDatas[index] );

float EvalShadow_CascadedDepth( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float3 L )
{
ShadowData sd = shadowContext.shadowDatas[index];
// normal based bias
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp.zw, sd.normalBias );
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres );
float relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
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;
float orig_payloadOffset = payloadOffset;
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias );
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS );
float3 posNDC;
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
// sample the texture
uint texIdx, sampIdx;
float slice;

UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
float shadow = 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 );
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, texIdx, sampIdx );
}
}
shadow = lerp( shadow, shadow1, alpha );
return shadow;
ShadowData sd = shadowContext.shadowDatas[index]; \
/* normal based bias */ \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp.zw, sd.normalBias ); \
\
float4 dirShadowSplitSpheres[4]; \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
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; \
float orig_payloadOffset = payloadOffset; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
return SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
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 )
正在加载...
取消
保存