Shader "Custom/HeatHaze" { Properties { [Header(Global)] _Weight ("Global Weight", Range(0, 1)) = 0.0 [Header(Distortion)] _Intensity ("Distortion Intensity", Range(0, 0.05)) = 0.02 _Speed ("Distortion Speed", Range(0, 5)) = 1.0 _Scale ("Noise Scale", Range(0, 20)) = 6.0 [Header(Heat Blur)] _BlurAmount ("Blur Amount", Range(0, 1)) = 0.6 _BlurSamples ("Blur Sample Spread", Range(0, 0.02)) = 0.005 [Header(Heat Color)] _HeatTint ("Heat Tint Color", Color) = (1.0, 0.45, 0.1, 1) _HeatTintStrength ("Tint Strength", Range(0, 1)) = 0.4 [Header(Heat Vignette)] _VignetteStrength ("Vignette Strength", Range(0, 1)) = 0.5 _VignettePower ("Vignette Power", Range(0.5, 5)) = 2.0 } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" } ZWrite Off ZTest Always Cull Off Pass { Name "HeatHazePass" HLSLPROGRAM #pragma vertex Vert #pragma fragment Frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" float _Weight; float _Intensity; float _Speed; float _Scale; float _BlurAmount; float _BlurSamples; float4 _HeatTint; float _HeatTintStrength; float _VignetteStrength; float _VignettePower; // ─── NOISE ─────────────────────────────────────────────── float SmoothNoise(float2 p) { float2 i = floor(p); float2 f = frac(p); f = f * f * (3.0 - 2.0 * f); float a = frac(sin(dot(i, float2(127.1, 311.7))) * 43758.5453); float b = frac(sin(dot(i + float2(1,0), float2(127.1, 311.7))) * 43758.5453); float c = frac(sin(dot(i + float2(0,1), float2(127.1, 311.7))) * 43758.5453); float d = frac(sin(dot(i + float2(1,1), float2(127.1, 311.7))) * 43758.5453); return lerp(lerp(a, b, f.x), lerp(c, d, f.x), f.y); } // ─── BLUR ──────────────────────────────────────────────── half3 RadialBlur(float2 uv, float strength) { half3 col = 0; float spread = _BlurSamples * strength; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2( spread, 0)).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2(-spread, 0)).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2( 0, spread)).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2( 0, -spread)).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2( spread, spread) * 0.7071).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2(-spread, spread) * 0.7071).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2( spread, -spread) * 0.7071).rgb; col += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + float2(-spread, -spread) * 0.7071).rgb; return col / 8.0; } // ─── FRAGMENT ──────────────────────────────────────────── half4 Frag(Varyings input) : SV_Target { float2 uv = input.texcoord; // Early exit — no effect at weight zero if (_Weight <= 0.001) return SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv); float t = _Time.y * _Speed; // ── 1. Distortion ───────────────────────────────────── float n1 = SmoothNoise(uv * _Scale + float2( t * 0.7, t * 0.3)); float n2 = SmoothNoise(uv * _Scale * 1.7 + float2(-t * 0.4, t * 0.6)); // Heat rises — distortion stronger at the bottom float heightMask = 1.0 - uv.y; float2 distort = float2(n1 - 0.5, n2 - 0.5) * _Intensity * heightMask * _Weight; float2 distortedUV = uv + distort; // ── 2. Base sample + blur ───────────────────────────── half3 sharp = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, distortedUV).rgb; half3 blurred = RadialBlur(distortedUV, 1.0); half3 col = lerp(sharp, blurred, _BlurAmount * heightMask * _Weight); // ── 3. Heat color tint ──────────────────────────────── half3 tint = _HeatTint.rgb; col = lerp(col, col * tint * 1.5, _HeatTintStrength * heightMask * _Weight); // ── 4. Heat vignette ────────────────────────────────── float2 vigUV = abs(uv - 0.5) * 2.0; float vignette = pow(max(vigUV.x, vigUV.y), _VignettePower); col = lerp(col, col * tint * 2.0, vignette * _VignetteStrength * _Weight); return half4(col, 1.0); } ENDHLSL } } }