Universial render pipeline shadow calc
https://cyangamedev.wordpress.com/2020/09/22/custom-lighting/
real SampleShadowmapFiltered(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData samplingData) | |
{ | |
real attenuation; | |
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_SWITCH) | |
// 4-tap hardware comparison | |
real4 attenuation4; | |
attenuation4.x = SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + samplingData.shadowOffset0.xyz); | |
attenuation4.y = SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + samplingData.shadowOffset1.xyz); | |
attenuation4.z = SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + samplingData.shadowOffset2.xyz); | |
attenuation4.w = SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + samplingData.shadowOffset3.xyz); | |
attenuation = dot(attenuation4, 0.25); | |
#else | |
float fetchesWeights[9]; | |
float2 fetchesUV[9]; | |
SampleShadow_ComputeSamples_Tent_5x5(samplingData.shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV); | |
attenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[0].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[1].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[2].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[3].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[4].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[5].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[6].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[7].xy, shadowCoord.z)); | |
attenuation += fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[8].xy, shadowCoord.z)); | |
#endif | |
return attenuation; | |
} | |
real SampleShadowmap(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData samplingData, half4 shadowParams, bool isPerspectiveProjection = true) | |
{ | |
// Compiler will optimize this branch away as long as isPerspectiveProjection is known at compile time | |
if (isPerspectiveProjection) | |
shadowCoord.xyz /= shadowCoord.w; | |
real attenuation; | |
real shadowStrength = shadowParams.x; | |
// TODO: We could branch on if this light has soft shadows (shadowParams.y) to save perf on some platforms. | |
#ifdef _SHADOWS_SOFT | |
attenuation = SampleShadowmapFiltered(TEXTURE2D_SHADOW_ARGS(ShadowMap, sampler_ShadowMap), shadowCoord, samplingData); | |
#else | |
// 1-tap hardware comparison | |
attenuation = SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz); | |
#endif | |
attenuation = LerpWhiteTo(attenuation, shadowStrength); | |
// Shadow coords that fall out of the light frustum volume must always return attenuation 1.0 | |
// TODO: We could use branch here to save some perf on some platforms. | |
return BEYOND_SHADOW_FAR(shadowCoord) ? 1.0 : attenuation; | |
} | |
half ComputeCascadeIndex(float3 positionWS) | |
{ | |
float3 fromCenter0 = positionWS - _CascadeShadowSplitSpheres0.xyz; | |
float3 fromCenter1 = positionWS - _CascadeShadowSplitSpheres1.xyz; | |
float3 fromCenter2 = positionWS - _CascadeShadowSplitSpheres2.xyz; | |
float3 fromCenter3 = positionWS - _CascadeShadowSplitSpheres3.xyz; | |
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3)); | |
half4 weights = half4(distances2 < _CascadeShadowSplitSphereRadii); | |
weights.yzw = saturate(weights.yzw - weights.xyz); | |
return 4 - dot(weights, half4(4, 3, 2, 1)); | |
} | |
float4 TransformWorldToShadowCoord(float3 positionWS) | |
{ | |
#ifdef _MAIN_LIGHT_SHADOWS_CASCADE | |
half cascadeIndex = ComputeCascadeIndex(positionWS); | |
#else | |
half cascadeIndex = 0; | |
#endif | |
return mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); | |
} | |
half MainLightRealtimeShadow(float4 shadowCoord) | |
{ | |
#if !defined(MAIN_LIGHT_CALCULATE_SHADOWS) | |
return 1.0h; | |
#endif | |
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData(); | |
half4 shadowParams = GetMainLightShadowParams(); | |
return SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), shadowCoord, shadowSamplingData, shadowParams, false); | |
} | |
half AdditionalLightRealtimeShadow(int lightIndex, float3 positionWS) | |
{ | |
#if !defined(ADDITIONAL_LIGHT_CALCULATE_SHADOWS) | |
return 1.0h; | |
#endif | |
ShadowSamplingData shadowSamplingData = GetAdditionalLightShadowSamplingData(); | |
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA | |
lightIndex = _AdditionalShadowsIndices[lightIndex]; | |
// We have to branch here as otherwise we would sample buffer with lightIndex == -1. | |
// However this should be ok for platforms that store light in SSBO. |
댓글
댓글 쓰기