123 lines
6.2 KiB
HLSL
123 lines
6.2 KiB
HLSL
#ifndef UTS_SHADOW_EVALUATION
|
|
#define UTS_SHADOW_EVALUATION
|
|
|
|
float3 UtsGetShadowNormal(UtsBSDFData bsdfData)
|
|
{
|
|
#if _MATERIAL_TYPE_FACE
|
|
return normalize(mul(UNITY_MATRIX_M, float4(0.0, 0.0, 1.0, 0.0))).xyz;
|
|
#else
|
|
return bsdfData.normalWS * (1.0 + _ShadowNormalBias);
|
|
#endif
|
|
}
|
|
|
|
float3 SampleSDFTexture(float3 L, float2 uv, out float angle)
|
|
{
|
|
// TODO: Move sdf sample result to UtsBSDFData to avoid sampleing in a loop
|
|
float2 right_uv = float2(1 - uv.x, uv.y);
|
|
float3 left_SDFTex = SAMPLE_TEXTURE2D(_SDFShadingMap, sampler_SDFShadingMap, uv).rgb;
|
|
float3 right_SDFTex = SAMPLE_TEXTURE2D(_SDFShadingMap, sampler_SDFShadingMap, right_uv).rgb;
|
|
|
|
float2 leftVector = normalize(mul(UNITY_MATRIX_M, float4(1.0, 0.0, 0.0, 0.0)).xz);
|
|
float2 forwardVector = normalize(mul(UNITY_MATRIX_M, float4(0.0, 0.0, 1.0, 0.0)).xz);
|
|
|
|
float2 lightDirection = normalize(L.xz);
|
|
angle = saturate(dot(forwardVector, lightDirection) * -1.0 + _SDFShadowLevel);
|
|
bool isRightSide = dot(lightDirection, leftVector) > 0;
|
|
|
|
return isRightSide ? right_SDFTex : left_SDFTex;
|
|
}
|
|
|
|
float GetHairShadow(PositionInputs posInput, float3 L)
|
|
{
|
|
float shadow = 1.0;
|
|
|
|
// Push the face fragment view space position towards the light for a little bit
|
|
float hairShadowOpacity = saturate(Remap(length(posInput.positionWS), float2(_HairShadowFadeOutDistance, _HairShadowFadeInDistance), float2(0, 1)));
|
|
|
|
if (hairShadowOpacity > 0.0)
|
|
{
|
|
float3 viewLightDir = TransformWorldToViewDir(L);
|
|
float shadowLengthY = _HairShadowDistance * 5.0 * max(0.5, posInput.linearDepth * _HairShadowDistanceScaleFactor) / posInput.linearDepth;
|
|
float2 shadowLength = float2(shadowLengthY * 2.0f, shadowLengthY);
|
|
|
|
float3 cameraDirOS = normalize(TransformWorldToObject(GetCameraPositionWS()));
|
|
float cameraDirFactor = 1.0 - smoothstep(0.1, 0.9, cameraDirOS.y);
|
|
// shadowLength.y *= cameraDirFactor;
|
|
|
|
// TODO: sample point is still shifting when fov change.
|
|
float2 samplingPoint = (posInput.positionSS + shadowLength * viewLightDir.xy) * _ScreenSize.zw; // Use 1080p as the reference resolution to achieve consistent shadow lengths across various screen resolutions.
|
|
|
|
float2 scaledUVs = samplingPoint * _RTHandleScale.xy; // We have to including the scaling factor for our shadow map since we are not going to allocate new texture if the rendering resolution changed.
|
|
float hairShadow = SAMPLE_TEXTURE2D_SHADOW(_HairShadowTex, s_linear_clamp_compare_sampler, float3(scaledUVs, posInput.deviceDepth + _HairShadowDepthBias)).r;
|
|
shadow = lerp(1.0 - hairShadowOpacity, 1.0, hairShadow);
|
|
}
|
|
|
|
return shadow;
|
|
}
|
|
|
|
// distances = {d, d^2, 1/d, d_proj}, where d_proj = dot(lightToSample, light.forward).
|
|
SHADOW_TYPE UtsEvaluateShadow_Punctual(LightLoopContext lightLoopContext, PositionInputs posInput, LightData light, BuiltinData builtinData, float3 N, float3 L, float4 distances)
|
|
{
|
|
#ifndef LIGHT_EVALUATION_NO_SHADOWS
|
|
float shadow = 1.0;
|
|
float shadowMask = 1.0;
|
|
float NdotL = dot(N, L); // Disable contact shadow and shadow mask when facing away from light (i.e transmission)
|
|
|
|
#ifdef SHADOWS_SHADOWMASK
|
|
// shadowMaskSelector.x is -1 if there is no shadow mask
|
|
// Note that we override shadow value (in case we don't have any dynamic shadow)
|
|
shadow = shadowMask = (light.shadowMaskSelector.x >= 0.0 && NdotL > 0.0) ? dot(BUILTIN_DATA_SHADOW_MASK, light.shadowMaskSelector) : 1.0;
|
|
#endif
|
|
|
|
#if defined(SCREEN_SPACE_SHADOWS_ON) && !defined(_SURFACE_TYPE_TRANSPARENT) && defined(_RECEIVE_SCREEN_SPACE_SHADOW_ON)
|
|
if ((light.screenSpaceShadowIndex & SCREEN_SPACE_SHADOW_INDEX_MASK) != INVALID_SCREEN_SPACE_SHADOW)
|
|
{
|
|
shadow = GetScreenSpaceShadow(posInput, light.screenSpaceShadowIndex);
|
|
shadow = lerp(shadowMask, shadow, light.shadowDimmer);
|
|
}
|
|
else
|
|
#endif
|
|
if ((light.shadowIndex >= 0) && (light.shadowDimmer > 0) && IsNonZeroBSDF(L, N))
|
|
{
|
|
shadow = GetPunctualShadowAttenuation(lightLoopContext.shadowContext, posInput.positionSS, posInput.positionWS + L * _ShadowDistanceBias, N, light.shadowIndex, L, distances.x, light.lightType == GPULIGHTTYPE_POINT, light.lightType != GPULIGHTTYPE_PROJECTOR_BOX);
|
|
|
|
#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)).
|
|
// HDRenderPipeline change this behavior. Only ShadowMask mode is supported but we support both blend with distance AND minimun of both value. Distance is control by light.
|
|
// The following code do this.
|
|
// The min handle the case of having only dynamic objects in the ShadowMap
|
|
// The second case for blend with distance is handled with ShadowDimmer. ShadowDimmer is define manually and by shadowDistance by light.
|
|
// With distance, ShadowDimmer become one and only the ShadowMask appear, we get the blend with distance behavior.
|
|
shadow = light.nonLightMappedOnly ? min(shadowMask, shadow) : shadow;
|
|
#endif
|
|
|
|
shadow = lerp(shadowMask, shadow, light.shadowDimmer);
|
|
}
|
|
|
|
// Transparents have no contact shadow information
|
|
#if !defined(_SURFACE_TYPE_TRANSPARENT) && !defined(LIGHT_EVALUATION_NO_CONTACT_SHADOWS)
|
|
{
|
|
// In certain cases (like hair) we allow to force the contact shadow sample.
|
|
#ifdef LIGHT_EVALUATION_CONTACT_SHADOW_DISABLE_NDOTL
|
|
const bool allowContactShadow = true;
|
|
#else
|
|
const bool allowContactShadow = NdotL > 0.0;
|
|
#endif
|
|
|
|
shadow = min(shadow, allowContactShadow ? GetContactShadow(lightLoopContext, light.contactShadowMask, light.isRayTracedContactShadow) : 1.0);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG_DISPLAY
|
|
if (_DebugShadowMapMode == SHADOWMAPDEBUGMODE_SINGLE_SHADOW && light.shadowIndex == _DebugSingleShadowIndex)
|
|
g_DebugShadowAttenuation = shadow;
|
|
#endif
|
|
return shadow;
|
|
#else // LIGHT_EVALUATION_NO_SHADOWS
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
#endif
|