#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.geomNormalWS * (1.0 + _ShadowNormalBias); #endif } // 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)) { 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