2023-03-28 13:24:16 -04:00
#ifndef UNIVERSAL_TERRAIN_LIT_PASSES_INCLUDED
#define UNIVERSAL_TERRAIN_LIT_PASSES_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityGBuffer.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
struct Attributes
{
float4 positionOS : POSITION ;
float3 normalOS : NORMAL ;
float2 texcoord : TEXCOORD0 ;
UNITY_VERTEX_INPUT_INSTANCE_ID
} ;
struct Varyings
{
float4 uvMainAndLM : TEXCOORD0 ; // xy: control, zw: lightmap
# ifndef TERRAIN_SPLAT_BASEPASS
float4 uvSplat01 : TEXCOORD1 ; // xy: splat0, zw: splat1
float4 uvSplat23 : TEXCOORD2 ; // xy: splat2, zw: splat3
# endif
# if defined ( _NORMALMAP ) && ! defined ( ENABLE_TERRAIN_PERPIXEL_NORMAL )
half4 normal : TEXCOORD3 ; // xyz: normal, w: viewDir.x
half4 tangent : TEXCOORD4 ; // xyz: tangent, w: viewDir.y
half4 bitangent : TEXCOORD5 ; // xyz: bitangent, w: viewDir.z
# else
half3 normal : TEXCOORD3 ;
half3 vertexSH : TEXCOORD4 ; // SH
# endif
# ifdef _ADDITIONAL_LIGHTS_VERTEX
half4 fogFactorAndVertexLight : TEXCOORD6 ; // x: fogFactor, yzw: vertex light
# else
half fogFactor : TEXCOORD6 ;
# endif
float3 positionWS : TEXCOORD7 ;
# if defined ( REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR )
float4 shadowCoord : TEXCOORD8 ;
# endif
#if defined(DYNAMICLIGHTMAP_ON)
float2 dynamicLightmapUV : TEXCOORD9 ;
#endif
float4 clipPos : SV_POSITION ;
UNITY_VERTEX_OUTPUT_STEREO
} ;
void InitializeInputData ( Varyings IN , half3 normalTS , out InputData inputData )
{
inputData = ( InputData ) 0 ;
inputData . positionWS = IN . positionWS ;
inputData . positionCS = IN . clipPos ;
# if defined ( _NORMALMAP ) && ! defined ( ENABLE_TERRAIN_PERPIXEL_NORMAL )
half3 viewDirWS = half3 ( IN . normal . w , IN . tangent . w , IN . bitangent . w ) ;
inputData . tangentToWorld = half3x3 ( - IN . tangent . xyz , IN . bitangent . xyz , IN . normal . xyz ) ;
inputData . normalWS = TransformTangentToWorld ( normalTS , inputData . tangentToWorld ) ;
2023-05-07 18:43:11 -04:00
// no need for vertex SH when _NORMALMAP is defined as we will evaluate SH per pixel
2023-03-28 13:24:16 -04:00
half3 SH = 0 ;
# elif defined ( ENABLE_TERRAIN_PERPIXEL_NORMAL )
half3 viewDirWS = GetWorldSpaceNormalizeViewDir ( IN . positionWS ) ;
float2 sampleCoords = ( IN . uvMainAndLM . xy / _TerrainHeightmapRecipSize . zw + 0.5f ) * _TerrainHeightmapRecipSize . xy ;
half3 normalWS = TransformObjectToWorldNormal ( normalize ( SAMPLE_TEXTURE2D ( _TerrainNormalmapTexture , sampler_TerrainNormalmapTexture , sampleCoords ) . rgb * 2 - 1 ) ) ;
half3 tangentWS = cross ( GetObjectToWorldMatrix ( ) . _13_23_33 , normalWS ) ;
inputData . normalWS = TransformTangentToWorld ( normalTS , half3x3 ( - tangentWS , cross ( normalWS , tangentWS ) , normalWS ) ) ;
2023-05-07 18:43:11 -04:00
half3 SH = IN . vertexSH ;
2023-03-28 13:24:16 -04:00
# else
half3 viewDirWS = GetWorldSpaceNormalizeViewDir ( IN . positionWS ) ;
inputData . normalWS = IN . normal ;
half3 SH = IN . vertexSH ;
# endif
inputData . normalWS = NormalizeNormalPerPixel ( inputData . normalWS ) ;
inputData . viewDirectionWS = viewDirWS ;
# if defined ( REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR )
inputData . shadowCoord = IN . shadowCoord ;
# elif defined ( MAIN_LIGHT_CALCULATE_SHADOWS )
inputData . shadowCoord = TransformWorldToShadowCoord ( inputData . positionWS ) ;
# else
inputData . shadowCoord = float4 ( 0 , 0 , 0 , 0 ) ;
# endif
# ifdef _ADDITIONAL_LIGHTS_VERTEX
inputData . fogCoord = InitializeInputDataFog ( float4 ( IN . positionWS , 1.0 ) , IN . fogFactorAndVertexLight . x ) ;
inputData . vertexLighting = IN . fogFactorAndVertexLight . yzw ;
# else
inputData . fogCoord = InitializeInputDataFog ( float4 ( IN . positionWS , 1.0 ) , IN . fogFactor ) ;
# endif
#if defined(DYNAMICLIGHTMAP_ON)
inputData . bakedGI = SAMPLE_GI ( IN . uvMainAndLM . zw , IN . dynamicLightmapUV , SH , inputData . normalWS ) ;
#else
inputData . bakedGI = SAMPLE_GI ( IN . uvMainAndLM . zw , SH , inputData . normalWS ) ;
#endif
inputData . normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV ( IN . clipPos ) ;
inputData . shadowMask = SAMPLE_SHADOWMASK ( IN . uvMainAndLM . zw )
# if defined ( DEBUG_DISPLAY )
# if defined ( DYNAMICLIGHTMAP_ON )
inputData . dynamicLightmapUV = IN . dynamicLightmapUV ;
# endif
# if defined ( LIGHTMAP_ON )
inputData . staticLightmapUV = IN . uvMainAndLM . zw ;
# else
inputData . vertexSH = SH ;
# endif
# endif
}
#ifndef TERRAIN_SPLAT_BASEPASS
void NormalMapMix ( float4 uvSplat01 , float4 uvSplat23 , inout half4 splatControl , inout half3 mixedNormal )
{
# if defined ( _NORMALMAP )
half3 nrm = half ( 0.0 ) ;
nrm + = splatControl . r * UnpackNormalScale ( SAMPLE_TEXTURE2D ( _Normal0 , sampler_Normal0 , uvSplat01 . xy ) , _NormalScale0 ) ;
nrm + = splatControl . g * UnpackNormalScale ( SAMPLE_TEXTURE2D ( _Normal1 , sampler_Normal0 , uvSplat01 . zw ) , _NormalScale1 ) ;
nrm + = splatControl . b * UnpackNormalScale ( SAMPLE_TEXTURE2D ( _Normal2 , sampler_Normal0 , uvSplat23 . xy ) , _NormalScale2 ) ;
nrm + = splatControl . a * UnpackNormalScale ( SAMPLE_TEXTURE2D ( _Normal3 , sampler_Normal0 , uvSplat23 . zw ) , _NormalScale3 ) ;
// avoid risk of NaN when normalizing.
# if HAS_HALF
nrm . z + = half ( 0.01 ) ;
# else
nrm . z + = 1 e - 5 f ;
# endif
mixedNormal = normalize ( nrm . xyz ) ;
# endif
}
void SplatmapMix ( float4 uvMainAndLM , float4 uvSplat01 , float4 uvSplat23 , inout half4 splatControl , out half weight , out half4 mixedDiffuse , out half4 defaultSmoothness , inout half3 mixedNormal )
{
half4 diffAlbedo [ 4 ] ;
diffAlbedo [ 0 ] = SAMPLE_TEXTURE2D ( _Splat0 , sampler_Splat0 , uvSplat01 . xy ) ;
diffAlbedo [ 1 ] = SAMPLE_TEXTURE2D ( _Splat1 , sampler_Splat0 , uvSplat01 . zw ) ;
diffAlbedo [ 2 ] = SAMPLE_TEXTURE2D ( _Splat2 , sampler_Splat0 , uvSplat23 . xy ) ;
diffAlbedo [ 3 ] = SAMPLE_TEXTURE2D ( _Splat3 , sampler_Splat0 , uvSplat23 . zw ) ;
// This might be a bit of a gamble -- the assumption here is that if the diffuseMap has no
// alpha channel, then diffAlbedo[n].a = 1.0 (and _DiffuseHasAlphaN = 0.0)
// Prior to coming in, _SmoothnessN is actually set to max(_DiffuseHasAlphaN, _SmoothnessN)
// This means that if we have an alpha channel, _SmoothnessN is locked to 1.0 and
// otherwise, the true slider value is passed down and diffAlbedo[n].a == 1.0.
defaultSmoothness = half4 ( diffAlbedo [ 0 ] . a , diffAlbedo [ 1 ] . a , diffAlbedo [ 2 ] . a , diffAlbedo [ 3 ] . a ) ;
defaultSmoothness * = half4 ( _Smoothness0 , _Smoothness1 , _Smoothness2 , _Smoothness3 ) ;
#ifndef _TERRAIN_BLEND_HEIGHT // density blending
if ( _NumLayersCount <= 4 )
{
// 20.0 is the number of steps in inputAlphaMask (Density mask. We decided 20 empirically)
half4 opacityAsDensity = saturate ( ( half4 ( diffAlbedo [ 0 ] . a , diffAlbedo [ 1 ] . a , diffAlbedo [ 2 ] . a , diffAlbedo [ 3 ] . a ) - ( 1 - splatControl ) ) * 20.0 ) ;
opacityAsDensity + = 0.001 h * splatControl ; // if all weights are zero, default to what the blend mask says
half4 useOpacityAsDensityParam = { _DiffuseRemapScale0 . w , _DiffuseRemapScale1 . w , _DiffuseRemapScale2 . w , _DiffuseRemapScale3 . w } ; // 1 is off
splatControl = lerp ( opacityAsDensity , splatControl , useOpacityAsDensityParam ) ;
}
#endif
// Now that splatControl has changed, we can compute the final weight and normalize
weight = dot ( splatControl , 1.0 h ) ;
#ifdef TERRAIN_SPLAT_ADDPASS
clip ( weight <= 0.005 h ? - 1.0 h : 1.0 h ) ;
#endif
#ifndef _TERRAIN_BASEMAP_GEN
// Normalize weights before lighting and restore weights in final modifier functions so that the overal
// lighting result can be correctly weighted.
splatControl / = ( weight + HALF_MIN ) ;
#endif
mixedDiffuse = 0.0 h ;
mixedDiffuse + = diffAlbedo [ 0 ] * half4 ( _DiffuseRemapScale0 . rgb * splatControl . rrr , 1.0 h ) ;
mixedDiffuse + = diffAlbedo [ 1 ] * half4 ( _DiffuseRemapScale1 . rgb * splatControl . ggg , 1.0 h ) ;
mixedDiffuse + = diffAlbedo [ 2 ] * half4 ( _DiffuseRemapScale2 . rgb * splatControl . bbb , 1.0 h ) ;
mixedDiffuse + = diffAlbedo [ 3 ] * half4 ( _DiffuseRemapScale3 . rgb * splatControl . aaa , 1.0 h ) ;
NormalMapMix ( uvSplat01 , uvSplat23 , splatControl , mixedNormal ) ;
}
#endif
#ifdef _TERRAIN_BLEND_HEIGHT
void HeightBasedSplatModify ( inout half4 splatControl , in half4 masks [ 4 ] )
{
// heights are in mask blue channel, we multiply by the splat Control weights to get combined height
half4 splatHeight = half4 ( masks [ 0 ] . b , masks [ 1 ] . b , masks [ 2 ] . b , masks [ 3 ] . b ) * splatControl . rgba ;
half maxHeight = max ( splatHeight . r , max ( splatHeight . g , max ( splatHeight . b , splatHeight . a ) ) ) ;
// Ensure that the transition height is not zero.
half transition = max ( _HeightTransition , 1 e - 5 ) ;
// This sets the highest splat to "transition", and everything else to a lower value relative to that, clamping to zero
// Then we clamp this to zero and normalize everything
half4 weightedHeights = splatHeight + transition - maxHeight . xxxx ;
weightedHeights = max ( 0 , weightedHeights ) ;
// We need to add an epsilon here for active layers (hence the blendMask again)
// so that at least a layer shows up if everything's too low.
weightedHeights = ( weightedHeights + 1 e - 6 ) * splatControl ;
// Normalize (and clamp to epsilon to keep from dividing by zero)
half sumHeight = max ( dot ( weightedHeights , half4 ( 1 , 1 , 1 , 1 ) ) , 1 e - 6 ) ;
splatControl = weightedHeights / sumHeight . xxxx ;
}
#endif
void SplatmapFinalColor ( inout half4 color , half fogCoord )
{
color . rgb * = color . a ;
# ifndef TERRAIN_GBUFFER // Technically we don't need fogCoord, but it is still passed from the vertex shader.
# ifdef TERRAIN_SPLAT_ADDPASS
color . rgb = MixFogColor ( color . rgb , half3 ( 0 , 0 , 0 ) , fogCoord ) ;
# else
color . rgb = MixFog ( color . rgb , fogCoord ) ;
# endif
# endif
}
///////////////////////////////////////////////////////////////////////////////
// Vertex and Fragment functions //
///////////////////////////////////////////////////////////////////////////////
// Used in Standard Terrain shader
Varyings SplatmapVert ( Attributes v )
{
Varyings o = ( Varyings ) 0 ;
UNITY_SETUP_INSTANCE_ID ( v ) ;
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO ( o ) ;
TerrainInstancing ( v . positionOS , v . normalOS , v . texcoord ) ;
VertexPositionInputs Attributes = GetVertexPositionInputs ( v . positionOS . xyz ) ;
o . uvMainAndLM . xy = v . texcoord ;
o . uvMainAndLM . zw = v . texcoord * unity_LightmapST . xy + unity_LightmapST . zw ;
# ifndef TERRAIN_SPLAT_BASEPASS
o . uvSplat01 . xy = TRANSFORM_TEX ( v . texcoord , _Splat0 ) ;
o . uvSplat01 . zw = TRANSFORM_TEX ( v . texcoord , _Splat1 ) ;
o . uvSplat23 . xy = TRANSFORM_TEX ( v . texcoord , _Splat2 ) ;
o . uvSplat23 . zw = TRANSFORM_TEX ( v . texcoord , _Splat3 ) ;
# endif
#if defined(DYNAMICLIGHTMAP_ON)
o . dynamicLightmapUV = v . texcoord * unity_DynamicLightmapST . xy + unity_DynamicLightmapST . zw ;
#endif
# if defined ( _NORMALMAP ) && ! defined ( ENABLE_TERRAIN_PERPIXEL_NORMAL )
half3 viewDirWS = GetWorldSpaceNormalizeViewDir ( Attributes . positionWS ) ;
float4 vertexTangent = float4 ( cross ( float3 ( 0 , 0 , 1 ) , v . normalOS ) , 1.0 ) ;
VertexNormalInputs normalInput = GetVertexNormalInputs ( v . normalOS , vertexTangent ) ;
o . normal = half4 ( normalInput . normalWS , viewDirWS . x ) ;
o . tangent = half4 ( normalInput . tangentWS , viewDirWS . y ) ;
o . bitangent = half4 ( normalInput . bitangentWS , viewDirWS . z ) ;
# else
o . normal = TransformObjectToWorldNormal ( v . normalOS ) ;
o . vertexSH = SampleSH ( o . normal ) ;
# endif
half fogFactor = 0 ;
# if ! defined ( _FOG_FRAGMENT )
fogFactor = ComputeFogFactor ( Attributes . positionCS . z ) ;
# endif
# ifdef _ADDITIONAL_LIGHTS_VERTEX
o . fogFactorAndVertexLight . x = fogFactor ;
o . fogFactorAndVertexLight . yzw = VertexLighting ( Attributes . positionWS , o . normal . xyz ) ;
# else
o . fogFactor = fogFactor ;
# endif
o . positionWS = Attributes . positionWS ;
o . clipPos = Attributes . positionCS ;
# if defined ( REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR )
o . shadowCoord = GetShadowCoord ( Attributes ) ;
# endif
return o ;
}
void ComputeMasks ( out half4 masks [ 4 ] , half4 hasMask , Varyings IN )
{
masks [ 0 ] = 0.5 h ;
masks [ 1 ] = 0.5 h ;
masks [ 2 ] = 0.5 h ;
masks [ 3 ] = 0.5 h ;
#ifdef _MASKMAP
masks [ 0 ] = lerp ( masks [ 0 ] , SAMPLE_TEXTURE2D ( _Mask0 , sampler_Mask0 , IN . uvSplat01 . xy ) , hasMask . x ) ;
masks [ 1 ] = lerp ( masks [ 1 ] , SAMPLE_TEXTURE2D ( _Mask1 , sampler_Mask0 , IN . uvSplat01 . zw ) , hasMask . y ) ;
masks [ 2 ] = lerp ( masks [ 2 ] , SAMPLE_TEXTURE2D ( _Mask2 , sampler_Mask0 , IN . uvSplat23 . xy ) , hasMask . z ) ;
masks [ 3 ] = lerp ( masks [ 3 ] , SAMPLE_TEXTURE2D ( _Mask3 , sampler_Mask0 , IN . uvSplat23 . zw ) , hasMask . w ) ;
#endif
masks [ 0 ] * = _MaskMapRemapScale0 . rgba ;
masks [ 0 ] + = _MaskMapRemapOffset0 . rgba ;
masks [ 1 ] * = _MaskMapRemapScale1 . rgba ;
masks [ 1 ] + = _MaskMapRemapOffset1 . rgba ;
masks [ 2 ] * = _MaskMapRemapScale2 . rgba ;
masks [ 2 ] + = _MaskMapRemapOffset2 . rgba ;
masks [ 3 ] * = _MaskMapRemapScale3 . rgba ;
masks [ 3 ] + = _MaskMapRemapOffset3 . rgba ;
}
// Used in Standard Terrain shader
#ifdef TERRAIN_GBUFFER
FragmentOutput SplatmapFragment ( Varyings IN )
#else
half4 SplatmapFragment ( Varyings IN ) : SV_TARGET
#endif
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( IN ) ;
#ifdef _ALPHATEST_ON
ClipHoles ( IN . uvMainAndLM . xy ) ;
#endif
half3 normalTS = half3 ( 0.0 h , 0.0 h , 1.0 h ) ;
#ifdef TERRAIN_SPLAT_BASEPASS
half3 albedo = SAMPLE_TEXTURE2D ( _MainTex , sampler_MainTex , IN . uvMainAndLM . xy ) . rgb ;
half smoothness = SAMPLE_TEXTURE2D ( _MainTex , sampler_MainTex , IN . uvMainAndLM . xy ) . a ;
half metallic = SAMPLE_TEXTURE2D ( _MetallicTex , sampler_MetallicTex , IN . uvMainAndLM . xy ) . r ;
half alpha = 1 ;
half occlusion = 1 ;
#else
half4 hasMask = half4 ( _LayerHasMask0 , _LayerHasMask1 , _LayerHasMask2 , _LayerHasMask3 ) ;
half4 masks [ 4 ] ;
ComputeMasks ( masks , hasMask , IN ) ;
float2 splatUV = ( IN . uvMainAndLM . xy * ( _Control_TexelSize . zw - 1.0f ) + 0.5f ) * _Control_TexelSize . xy ;
half4 splatControl = SAMPLE_TEXTURE2D ( _Control , sampler_Control , splatUV ) ;
half alpha = dot ( splatControl , 1.0 h ) ;
#ifdef _TERRAIN_BLEND_HEIGHT
// disable Height Based blend when there are more than 4 layers (multi-pass breaks the normalization)
if ( _NumLayersCount <= 4 )
HeightBasedSplatModify ( splatControl , masks ) ;
#endif
half weight ;
half4 mixedDiffuse ;
half4 defaultSmoothness ;
SplatmapMix ( IN . uvMainAndLM , IN . uvSplat01 , IN . uvSplat23 , splatControl , weight , mixedDiffuse , defaultSmoothness , normalTS ) ;
half3 albedo = mixedDiffuse . rgb ;
half4 defaultMetallic = half4 ( _Metallic0 , _Metallic1 , _Metallic2 , _Metallic3 ) ;
half4 defaultOcclusion = half4 ( _MaskMapRemapScale0 . g , _MaskMapRemapScale1 . g , _MaskMapRemapScale2 . g , _MaskMapRemapScale3 . g ) +
half4 ( _MaskMapRemapOffset0 . g , _MaskMapRemapOffset1 . g , _MaskMapRemapOffset2 . g , _MaskMapRemapOffset3 . g ) ;
half4 maskSmoothness = half4 ( masks [ 0 ] . a , masks [ 1 ] . a , masks [ 2 ] . a , masks [ 3 ] . a ) ;
defaultSmoothness = lerp ( defaultSmoothness , maskSmoothness , hasMask ) ;
half smoothness = dot ( splatControl , defaultSmoothness ) ;
half4 maskMetallic = half4 ( masks [ 0 ] . r , masks [ 1 ] . r , masks [ 2 ] . r , masks [ 3 ] . r ) ;
defaultMetallic = lerp ( defaultMetallic , maskMetallic , hasMask ) ;
half metallic = dot ( splatControl , defaultMetallic ) ;
half4 maskOcclusion = half4 ( masks [ 0 ] . g , masks [ 1 ] . g , masks [ 2 ] . g , masks [ 3 ] . g ) ;
defaultOcclusion = lerp ( defaultOcclusion , maskOcclusion , hasMask ) ;
half occlusion = dot ( splatControl , defaultOcclusion ) ;
#endif
InputData inputData ;
InitializeInputData ( IN , normalTS , inputData ) ;
SETUP_DEBUG_TEXTURE_DATA ( inputData , IN . uvMainAndLM . xy , _BaseMap ) ;
#if defined(_DBUFFER)
half3 specular = half3 ( 0.0 h , 0.0 h , 0.0 h ) ;
ApplyDecal ( IN . clipPos ,
albedo ,
specular ,
inputData . normalWS ,
metallic ,
occlusion ,
smoothness ) ;
#endif
#ifdef TERRAIN_GBUFFER
BRDFData brdfData ;
InitializeBRDFData ( albedo , metallic , /* specular */ half3 ( 0.0 h , 0.0 h , 0.0 h ) , smoothness , alpha , brdfData ) ;
// Baked lighting.
half4 color ;
Light mainLight = GetMainLight ( inputData . shadowCoord , inputData . positionWS , inputData . shadowMask ) ;
MixRealtimeAndBakedGI ( mainLight , inputData . normalWS , inputData . bakedGI , inputData . shadowMask ) ;
color . rgb = GlobalIllumination ( brdfData , inputData . bakedGI , occlusion , inputData . positionWS , inputData . normalWS , inputData . viewDirectionWS ) ;
color . a = alpha ;
SplatmapFinalColor ( color , inputData . fogCoord ) ;
// Dynamic lighting: emulate SplatmapFinalColor() by scaling gbuffer material properties. This will not give the same results
// as forward renderer because we apply blending pre-lighting instead of post-lighting.
// Blending of smoothness and normals is also not correct but close enough?
brdfData . albedo . rgb * = alpha ;
brdfData . diffuse . rgb * = alpha ;
brdfData . specular . rgb * = alpha ;
brdfData . reflectivity * = alpha ;
inputData . normalWS = inputData . normalWS * alpha ;
smoothness * = alpha ;
return BRDFDataToGbuffer ( brdfData , inputData , smoothness , color . rgb , occlusion ) ;
#else
half4 color = UniversalFragmentPBR ( inputData , albedo , metallic , /* specular */ half3 ( 0.0 h , 0.0 h , 0.0 h ) , smoothness , occlusion , /* emission */ half3 ( 0 , 0 , 0 ) , alpha ) ;
SplatmapFinalColor ( color , inputData . fogCoord ) ;
return half4 ( color . rgb , 1.0 h ) ;
#endif
}
// Shadow pass
// Shadow Casting Light geometric parameters. These variables are used when applying the shadow Normal Bias and are set by UnityEngine.Rendering.Universal.ShadowUtils.SetupShadowCasterConstantBuffer in com.unity.render-pipelines.universal/Runtime/ShadowUtils.cs
// For Directional lights, _LightDirection is used when applying shadow Normal Bias.
// For Spot lights and Point lights, _LightPosition is used to compute the actual light direction because it is different at each shadow caster geometry vertex.
float3 _LightDirection ;
float3 _LightPosition ;
struct AttributesLean
{
float4 position : POSITION ;
float3 normalOS : NORMAL ;
float2 texcoord : TEXCOORD0 ;
UNITY_VERTEX_INPUT_INSTANCE_ID
} ;
struct VaryingsLean
{
float4 clipPos : SV_POSITION ;
float2 texcoord : TEXCOORD0 ;
UNITY_VERTEX_OUTPUT_STEREO
} ;
VaryingsLean ShadowPassVertex ( AttributesLean v )
{
VaryingsLean o = ( VaryingsLean ) 0 ;
UNITY_SETUP_INSTANCE_ID ( v ) ;
TerrainInstancing ( v . position , v . normalOS , v . texcoord ) ;
float3 positionWS = TransformObjectToWorld ( v . position . xyz ) ;
float3 normalWS = TransformObjectToWorldNormal ( v . normalOS ) ;
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
float3 lightDirectionWS = normalize ( _LightPosition - positionWS ) ;
#else
float3 lightDirectionWS = _LightDirection ;
#endif
float4 clipPos = TransformWorldToHClip ( ApplyShadowBias ( positionWS , normalWS , lightDirectionWS ) ) ;
#if UNITY_REVERSED_Z
clipPos . z = min ( clipPos . z , UNITY_NEAR_CLIP_VALUE ) ;
#else
clipPos . z = max ( clipPos . z , UNITY_NEAR_CLIP_VALUE ) ;
#endif
o . clipPos = clipPos ;
o . texcoord = v . texcoord ;
return o ;
}
half4 ShadowPassFragment ( VaryingsLean IN ) : SV_TARGET
{
#ifdef _ALPHATEST_ON
ClipHoles ( IN . texcoord ) ;
#endif
return 0 ;
}
// Depth pass
VaryingsLean DepthOnlyVertex ( AttributesLean v )
{
VaryingsLean o = ( VaryingsLean ) 0 ;
UNITY_SETUP_INSTANCE_ID ( v ) ;
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO ( o ) ;
TerrainInstancing ( v . position , v . normalOS ) ;
o . clipPos = TransformObjectToHClip ( v . position . xyz ) ;
o . texcoord = v . texcoord ;
return o ;
}
half4 DepthOnlyFragment ( VaryingsLean IN ) : SV_TARGET
{
#ifdef _ALPHATEST_ON
ClipHoles ( IN . texcoord ) ;
#endif
#ifdef SCENESELECTIONPASS
// We use depth prepass for scene selection in the editor, this code allow to output the outline correctly
return half4 ( _ObjectId , _PassValue , 1.0 , 1.0 ) ;
#endif
return 0 ;
}
#endif