In TerrainLitPasses.hlsl
InputData inputData;
InitializeInputData(IN, normalTS, inputData);
#if defined(_TEXEL_SNAP)
// --- Texel snap: snap world position BEFORE GI / shadow sampling so lighting and shadows use snapped position
float2 uvForSnap = IN.uvSplat01.xy; // base/control UV for snapping
float4 texelSize = _Splat0_TexelSize; //_Control_TexelSize; // control/splat texel-size uniform (use other _SplatN_TexelSize if desired)
ApplyTexelSnapWS(inputData.positionWS, uvForSnap, inputData, texelSize);
#endif
SetupTerrainDebugTextureData(inputData, IN.uvMainAndLM.xy);
Add this in TerrainDetailLitInput.hlsl
half4 _MainTex_TexelSize;
Made TexelSnapUtils.hlsl
// Generic world-space texel snap helper.
// worldPos: original world position for the fragment/pixel
// uv: the UV to snap to (caller decides which texture's UV to use)
// tex: the Texture2D to derive texel size from (pass the texture property, e.g. _BaseMap)
// inputData: the InputData used by lighting; this will be mutated to use snapped position.
void ApplyTexelSnapWS(float3 worldPos, float2 uv, inout InputData inputData, float4 texelSize)
{
#ifdef _TEXEL_SNAP
float3 snappedPos;
TexelSnap_float(worldPos, float4(uv, 0, 0), texelSize, snappedPos);
// Replace the position used by lighting and recompute dependent values
inputData.positionWS = snappedPos;
inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(inputData.positionWS);
// Ensure shadow sampling uses snapped position
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)
inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
#else
inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
// NOTE: fogCoord, baked GI inputs, probe sampling, etc. may also depend on positionWS.
// Recompute them in the caller if you require them to match the snapped position.
#endif
}