You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
6.9 KiB
139 lines
6.9 KiB
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"
|
|
// DeclareDepthTexture provides TEXTURE2D_X_FLOAT(_CameraDepthTexture) and SampleSceneDepth().
|
|
// Include unconditionally; it is only sampled in DEPTH_MODE branches.
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
|
|
|
|
// ── Mode selection ──────────────────────────────────────────────────────────
|
|
// DEPTH_MODE: Scheimpflug-based (uses depth buffer). Default: screen-space.
|
|
#pragma multi_compile_local _ DEPTH_MODE
|
|
|
|
// ── Shared parameters ───────────────────────────────────────────────────────
|
|
float _TiltShift_MaxBlurRadius; // max blur in pixels
|
|
int _TiltShift_SampleCount; // samples per side per pass
|
|
|
|
// ── Screen-space mode ───────────────────────────────────────────────────────
|
|
float _TiltShift_CenterOffset; // vertical offset of sharp band (UV units, +up)
|
|
float _TiltShift_FocusWidth; // full height of sharp band as fraction of screen
|
|
float _TiltShift_FalloffRange; // blur fade-in distance in UV units
|
|
|
|
// ── Depth mode (Scheimpflug / tilt plane) ───────────────────────────────────
|
|
// _CameraDepthTexture and _ZBufferParams are provided by URP / DeclareDepthTexture.hlsl.
|
|
|
|
float _TiltShift_FocusDistance; // world-space depth of the focal plane centre
|
|
float _TiltShift_TiltFactor; // world-space depth shift per UV unit of screen height
|
|
// positive → top focuses farther (typical bird's-eye)
|
|
float _TiltShift_FocusBand; // half-width of the sharp zone in world units
|
|
float _TiltShift_DepthFalloff; // blur ramp width in world units
|
|
|
|
// ── Blur radius computation ─────────────────────────────────────────────────
|
|
|
|
float ComputeBlurRadius(float2 uv)
|
|
{
|
|
#if defined(DEPTH_MODE)
|
|
// ----------------------------------------------------------------
|
|
// Scheimpflug tilt-plane CoC
|
|
// SampleSceneDepth uses TEXTURE2D_X_FLOAT + point-clamp (from DeclareDepthTexture.hlsl).
|
|
// ----------------------------------------------------------------
|
|
float rawDepth = SampleSceneDepth(uv);
|
|
float eyeDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
|
|
|
|
// Depth of the focus plane at this screen row:
|
|
// uv.y = 0 → bottom, uv.y = 1 → top (OpenGL-style; URP handles flip internally)
|
|
float focusAtY = _TiltShift_FocusDistance + _TiltShift_TiltFactor * (uv.y - 0.5);
|
|
|
|
float distToPlane = abs(eyeDepth - focusAtY);
|
|
float band = max(_TiltShift_FocusBand, 0.001);
|
|
float falloff = max(_TiltShift_DepthFalloff, 0.001);
|
|
return smoothstep(band, band + falloff, distToPlane) * _TiltShift_MaxBlurRadius;
|
|
#else
|
|
// ----------------------------------------------------------------
|
|
// Screen-space approximation (no depth buffer needed)
|
|
// ----------------------------------------------------------------
|
|
float dist = abs(uv.y - 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;
|
|
#endif
|
|
}
|
|
|
|
// ── Separable Gaussian blur ─────────────────────────────────────────────────
|
|
|
|
// stepUV = one sample offset in UV space (direction × pixelSize)
|
|
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 ∈ [−1, 1]; gaussian shaped so weight → ~0 at the extremes
|
|
float t = float(i) / float(n);
|
|
float weight = exp(-4.5 * t * t);
|
|
color += SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv + stepUV * float(i), 0) * weight;
|
|
totalWeight += weight;
|
|
}
|
|
|
|
return color / totalWeight;
|
|
}
|
|
|
|
// ── Fragment shaders ────────────────────────────────────────────────────────
|
|
|
|
float4 HorizontalBlur(Varyings input) : SV_Target
|
|
{
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
|
float2 uv = input.texcoord;
|
|
float radius = ComputeBlurRadius(uv);
|
|
if (radius < 0.5)
|
|
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0);
|
|
|
|
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);
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|