Shader "Unheimlich/UI/HallucinationSketchBleed_V2" { Properties { [PerRendererData] _MainTex ("Sprite / Video Texture", 2D) = "white" {} _Color ("Tint", Color) = (1, 1, 1, 1) [Header(Global Control)] _Intensity ("Global Intensity", Range(0, 1)) = 0.65 _VideoPreserve ("Video Preserve", Range(0, 1)) = 0.72 _Darken ("Darken", Range(0, 1)) = 0.12 _Contrast ("Contrast", Range(0.5, 2.0)) = 1.12 [Header(Sketch Lines)] _EdgeStrength ("Edge Strength", Range(0, 2)) = 1.15 _HatchStrength ("Hatch Strength", Range(0, 1)) = 0.55 _HatchScale ("Hatch Scale", Range(40, 420)) = 180 _HatchThickness ("Hatch Thickness", Range(0.005, 0.09)) = 0.032 _DarkAreaHatching ("Dark Area Hatching", Range(0, 1)) = 0.75 [Header(Animated Scribble)] _ScribbleStrength ("Scribble Strength", Range(0, 1)) = 0.45 _ScribbleScale ("Scribble Scale", Range(10, 160)) = 48 _ScribbleSpeed ("Scribble Speed", Range(0, 30)) = 9 _ScribbleBleed ("Scribble Bleed", Range(0, 0.04)) = 0.012 [Header(Controlled Distortion)] _Distortion ("UV Distortion", Range(0, 0.04)) = 0.008 _Bleed ("Chromatic Bleed", Range(0, 0.025)) = 0.006 _JitterAmount ("Jitter Amount", Range(0, 0.02)) = 0.004 _JitterSpeed ("Jitter Speed", Range(0, 30)) = 8 [Header(Grain)] _GrainStrength ("Grain Strength", Range(0, 1)) = 0.12 [Header(UI)] _StencilComp ("Stencil Comparison", Float) = 8 _Stencil ("Stencil ID", Float) = 0 _StencilOp ("Stencil Operation", Float) = 0 _StencilWriteMask ("Stencil Write Mask", Float) = 255 _StencilReadMask ("Stencil Read Mask", Float) = 255 _ColorMask ("Color Mask", Float) = 15 [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" } Stencil { Ref [_Stencil] Comp [_StencilComp] Pass [_StencilOp] ReadMask [_StencilReadMask] WriteMask [_StencilWriteMask] } Cull Off Lighting Off ZWrite Off ZTest [unity_GUIZTestMode] Blend SrcAlpha OneMinusSrcAlpha ColorMask [_ColorMask] Pass { Name "HallucinationSketchBleed_V2" CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_local _ UNITY_UI_CLIP_RECT #pragma multi_compile_local _ UNITY_UI_ALPHACLIP #include "UnityCG.cginc" #include "UnityUI.cginc" sampler2D _MainTex; float4 _MainTex_ST; float4 _MainTex_TexelSize; fixed4 _Color; float4 _ClipRect; float _Intensity; float _VideoPreserve; float _Darken; float _Contrast; float _EdgeStrength; float _HatchStrength; float _HatchScale; float _HatchThickness; float _DarkAreaHatching; float _ScribbleStrength; float _ScribbleScale; float _ScribbleSpeed; float _ScribbleBleed; float _Distortion; float _Bleed; float _JitterAmount; float _JitterSpeed; float _GrainStrength; struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 uv : TEXCOORD0; float4 worldPosition : TEXCOORD1; }; float Hash(float2 p) { return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453123); } float Noise(float2 p) { float2 i = floor(p); float2 f = frac(p); float a = Hash(i); float b = Hash(i + float2(1.0, 0.0)); float c = Hash(i + float2(0.0, 1.0)); float d = Hash(i + float2(1.0, 1.0)); float2 u = f * f * (3.0 - 2.0 * f); return lerp(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } float Luminance(float3 col) { return dot(col, float3(0.299, 0.587, 0.114)); } float PencilBand(float value, float thickness) { float bandDistance = abs(frac(value) - 0.5); return 1.0 - smoothstep(thickness, thickness + 0.018, bandDistance); } float GetEdge(float2 uv) { float2 texel = _MainTex_TexelSize.xy; float l = Luminance(tex2D(_MainTex, uv - float2(texel.x, 0)).rgb); float r = Luminance(tex2D(_MainTex, uv + float2(texel.x, 0)).rgb); float d = Luminance(tex2D(_MainTex, uv - float2(0, texel.y)).rgb); float u = Luminance(tex2D(_MainTex, uv + float2(0, texel.y)).rgb); float edge = abs(r - l) + abs(u - d); return saturate(edge * 5.0 * _EdgeStrength); } float SketchHatching(float2 uv, float luminance, float edge, float noiseValue) { float darkMask = saturate((1.0 - luminance) * _DarkAreaHatching); float contourMask = saturate(edge * 1.4); float mask = saturate(darkMask + contourMask); float t = _Time.y * _ScribbleSpeed; float2 animatedUv = uv; animatedUv.x += (Noise(uv * 22.0 + t * 0.35) - 0.5) * 0.012; animatedUv.y += (Noise(uv * 19.0 - t * 0.27) - 0.5) * 0.012; float h1 = PencilBand((animatedUv.x + animatedUv.y * 0.72 + noiseValue * 0.08) * _HatchScale, _HatchThickness); float h2 = PencilBand((animatedUv.x * 0.63 - animatedUv.y + noiseValue * 0.12) * (_HatchScale * 0.67), _HatchThickness * 0.9); float h3 = PencilBand((animatedUv.x * 1.18 + animatedUv.y * 0.28 + noiseValue * 0.2) * (_HatchScale * 0.38), _HatchThickness * 0.75); float hatch = saturate(h1 * 0.65 + h2 * 0.4 + h3 * 0.25); return hatch * mask; } float AnimatedScribble(float2 uv, float luminance, float edge) { float t = _Time.y * _ScribbleSpeed; float2 p = uv * _ScribbleScale; float n1 = Noise(p + float2(t * 0.75, -t * 0.25)); float n2 = Noise(p * 1.7 + float2(-t * 0.35, t * 0.55)); float n3 = Noise(p * 3.1 + t); float unstable = abs(n1 - n2); float brokenLines = 1.0 - smoothstep(0.08, 0.22, unstable); float darkMask = saturate(1.0 - luminance); float edgeMask = saturate(edge * 1.7); float mask = saturate(darkMask * 0.55 + edgeMask); float flicker = step(0.42, n3); return brokenLines * mask * flicker; } v2f vert(appdata_t v) { v2f o; o.worldPosition = v.vertex; o.vertex = UnityObjectToClipPos(o.worldPosition); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = v.color * _Color; return o; } fixed4 frag(v2f i) : SV_Target { float intensity = saturate(_Intensity); float2 uv = i.uv; float time = _Time.y; float globalNoise = Noise(uv * 18.0 + time * _JitterSpeed); float jitterPhase = floor(time * _JitterSpeed); float2 frameJitter; frameJitter.x = Hash(float2(jitterPhase, 1.7)) - 0.5; frameJitter.y = Hash(float2(jitterPhase, 9.2)) - 0.5; uv += frameJitter * _JitterAmount * intensity; float2 wobble; wobble.x = sin(uv.y * 18.0 + time * 4.0) * 0.5 + globalNoise - 0.5; wobble.y = cos(uv.x * 14.0 - time * 3.1) * 0.5 + Noise(uv * 28.0 - time) - 0.5; uv += wobble * _Distortion * intensity; float edge = GetEdge(uv); float2 bleedOffset = float2(_Bleed * intensity, 0.0); float2 scribbleBleedOffset = float2(_ScribbleBleed * edge * intensity, _ScribbleBleed * 0.35 * intensity); fixed4 baseCol = tex2D(_MainTex, uv); fixed4 redCol = tex2D(_MainTex, uv + bleedOffset + scribbleBleedOffset); fixed4 blueCol = tex2D(_MainTex, uv - bleedOffset - scribbleBleedOffset); fixed4 videoCol; videoCol.r = redCol.r; videoCol.g = baseCol.g; videoCol.b = blueCol.b; videoCol.a = baseCol.a; float luminance = Luminance(videoCol.rgb); float hatch = SketchHatching(i.uv, luminance, edge, globalNoise); float scribble = AnimatedScribble(i.uv, luminance, edge); float grain = Hash(floor(i.uv * 1100.0 + time * 80.0)); float3 sketchCol = videoCol.rgb; sketchCol = saturate((sketchCol - 0.5) * _Contrast + 0.5); sketchCol *= 1.0 - (_Darken * intensity); float hatchAmount = hatch * _HatchStrength * intensity; float scribbleAmount = scribble * _ScribbleStrength * intensity; sketchCol = lerp(sketchCol, sketchCol * 0.22, hatchAmount); sketchCol = lerp(sketchCol, sketchCol * 0.06, scribbleAmount); sketchCol += (grain - 0.5) * _GrainStrength * intensity; float preserve = saturate(_VideoPreserve); float3 finalRgb = lerp(sketchCol, videoCol.rgb, preserve * (1.0 - intensity * 0.35)); fixed4 col; col.rgb = saturate(finalRgb); col.a = videoCol.a; col *= i.color; #ifdef UNITY_UI_CLIP_RECT col.a *= UnityGet2DClipping(i.worldPosition.xy, _ClipRect); #endif #ifdef UNITY_UI_ALPHACLIP clip(col.a - 0.001); #endif return col; } ENDCG } } }