Shader "Custom/TiltShift" { SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } ZTest Always ZWrite Off Cull Off Blend Off HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" float _TiltShift_CenterOffset; float _TiltShift_FocusWidth; float _TiltShift_FalloffRange; float _TiltShift_MaxBlurRadius; int _TiltShift_SampleCount; // _BlitTexture and _BlitTexture_TexelSize are provided by Blit.hlsl // _BlitTexture_TexelSize: (1/w, 1/h, w, h) // sampler_LinearClamp is provided by GlobalSamplers.hlsl (included via Blit.hlsl) // Returns blur radius in pixels for a given vertical UV coordinate. float ComputeBlurRadius(float uvY) { float dist = abs(uvY - 0.5 + _TiltShift_CenterOffset); float halfFocus = _TiltShift_FocusWidth * 0.5; float range = max(_TiltShift_FalloffRange, 0.001); return smoothstep(halfFocus, halfFocus + range, dist) * _TiltShift_MaxBlurRadius; } // Gaussian blur in an arbitrary direction. // direction: offset per sample step in UV space (already multiplied by texelSize) float4 GaussianBlur(float2 uv, float2 stepUV) { int n = max(1, _TiltShift_SampleCount); float4 color = 0; float totalWeight = 0; [loop] for (int i = -n; i <= n; i++) { // t in [-1, 1]; weight peaks at centre and falls near edges. float t = float(i) / float(n); float weight = exp(-4.5 * t * t); float2 sampleUV = uv + stepUV * float(i); color += SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, sampleUV, 0) * weight; totalWeight += weight; } return color / totalWeight; } float4 HorizontalBlur(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord; float radius = ComputeBlurRadius(uv.y); if (radius < 0.5) return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0); // stepUV: one step in the horizontal direction, spread over [−radius, +radius] pixels int n = max(1, _TiltShift_SampleCount); float2 stepUV = float2((radius / float(n)) * _BlitTexture_TexelSize.x, 0.0); return GaussianBlur(uv, stepUV); } float4 VerticalBlur(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float2 uv = input.texcoord; float radius = ComputeBlurRadius(uv.y); if (radius < 0.5) return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0); int n = max(1, _TiltShift_SampleCount); float2 stepUV = float2(0.0, (radius / float(n)) * _BlitTexture_TexelSize.y); return GaussianBlur(uv, stepUV); } ENDHLSL // Pass 0 — Horizontal blur Pass { Name "TiltShift_H" HLSLPROGRAM #pragma vertex Vert #pragma fragment HorizontalBlur ENDHLSL } // Pass 1 — Vertical blur Pass { Name "TiltShift_V" HLSLPROGRAM #pragma vertex Vert #pragma fragment VerticalBlur ENDHLSL } } }