Shader "Custom/Glitch" { Properties { [Toggle] _IsActive ("Active", Float) = 1.0 [Header(Fracture)] _FractureAmount ("Fracture Amount", Range(0,1)) = 0.0 _CellScale ("Cell Scale", Float) = 8.0 _CellDisplace ("Cell Displacement", Range(0,0.1)) = 0.05 _CellRotation ("Cell Rotation", Range(0,1)) = 0.3 [Header(Depth Echoes)] _EchoCount ("Echo Count", Range(0,8)) = 4.0 _EchoScale ("Echo Scale", Range(0,0.15)) = 0.06 _EchoOpacity ("Echo Opacity", Range(0,1)) = 0.4 _EchoSpread ("Echo Spread", Range(0,0.5)) = 0.15 [Header(Chromatic Aberration)] _ChromaAmount ("Chromatic Aberration", Range(0,0.05)) = 0.01 [Header(Edge Darkening)] _EdgeDarken ("Edge Darken", Range(0,1)) = 0.5 _EdgePower ("Edge Power", Float) = 2.0 [Header(Glitch Lines)] _GlitchStrength ("Glitch Line Strength", Range(0,1)) = 0.3 _GlitchScale ("Glitch Line Scale", Float) = 40.0 } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" } ZWrite Off ZTest Always Cull Off Pass { Name "CorridorFracturePass" 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 _IsActive; float _FractureAmount; float _CellScale; float _CellDisplace; float _CellRotation; float _EchoCount; float _EchoScale; float _EchoOpacity; float _EchoSpread; float _ChromaAmount; float _EdgeDarken; float _EdgePower; float _GlitchStrength; float _GlitchScale; // ─── NOISE / HASH ───────────────────────────────────────── float2 Hash22(float2 p) { p = float2(dot(p, float2(127.1, 311.7)), dot(p, float2(269.5, 183.3))); return frac(sin(p) * 43758.5453); } float Hash11(float p) { return frac(sin(p * 127.1) * 43758.5453); } 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); } // ─── VORONOI ────────────────────────────────────────────── // Retourne (distance au point le plus proche, id de la cellule) float2 Voronoi(float2 uv, float scale) { float2 scaledUV = uv * scale; float2 i = floor(scaledUV); float2 f = frac(scaledUV); float minDist = 8.0; float2 minCell = float2(0, 0); for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { float2 neighbor = float2(x, y); float2 cellId = i + neighbor; float2 cellPoint = Hash22(cellId) + neighbor; float dist = length(cellPoint - f); if (dist < minDist) { minDist = dist; minCell = cellId; } } } return float2(minDist, Hash11(minCell.x * 73.1 + minCell.y * 191.7)); } // ─── ROTATION UV ───────────────────────────────────────── float2 RotateUV(float2 uv, float2 center, float angle) { float2 d = uv - center; float s = sin(angle); float c = cos(angle); return center + float2(d.x * c - d.y * s, d.x * s + d.y * c); } // ─── SAMPLE AVEC CHROMATIC ABERRATION ──────────────────── half3 SampleChroma(float2 uv, float strength) { float2 dir = (uv - 0.5) * strength; half r = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv + dir).r; half g = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv).g; half b = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv - dir).b; return half3(r, g, b); } // ─── FRAGMENT ──────────────────────────────────────────── half4 Frag(Varyings input) : SV_Target { float2 uv = input.texcoord; if (!_IsActive) return SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv); // Rien à faire si fracture = 0 if (_FractureAmount <= 0.001) return SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, uv); float t = _FractureAmount; // ── 1. Cellules Voronoi ─────────────────────────────── // L'échelle des cellules augmente avec t : plus on avance, // plus les fragments sont nombreux et petits. float dynamicScale = _CellScale * (1.0 + t * 3.0); float2 voronoi = Voronoi(uv, dynamicScale); float cellDist = voronoi.x; float cellId = voronoi.y; // Déplacement UV par cellule — s'amplifie avec t float2 cellOffset = (Hash22(float2(cellId * 17.3, cellId * 31.7)) - 0.5) * _CellDisplace * t * 2.0; // Rotation par cellule — s'amplifie avec t float cellAngle = (cellId - 0.5) * _CellRotation * t * 3.14159 * 0.5; float2 fracturedUV = RotateUV(uv + cellOffset, uv, cellAngle); fracturedUV = clamp(fracturedUV, 0.0, 1.0); // ── 2. Glitch lines verticales ──────────────────────── // Des bandes verticales se décalent aléatoirement. float glitchNoise = SmoothNoise(float2(uv.y * _GlitchScale, floor(_Time.y * 8.0))); float glitchMask = step(1.0 - t * _GlitchStrength, glitchNoise); float glitchShift = (Hash11(floor(uv.y * _GlitchScale)) - 0.5) * 0.05 * t; fracturedUV.x += glitchShift * glitchMask; // ── 3. Sample de base avec chromatic aberration ─────── float chromaStrength = _ChromaAmount * t; half3 col = SampleChroma(fracturedUV, chromaStrength); // ── 4. Échos en profondeur ──────────────────────────── // Chaque écho est une copie de l'image contractée vers le centre, // simulant une répétition infinie du couloir. int echoCount = (int)ceil(_EchoCount * t); echoCount = clamp(echoCount, 0, 8); for (int i = 1; i <= echoCount; i++) { float fi = (float)i; float echoT = fi / (float)echoCount; // Contraction vers le centre — chaque écho est plus petit float scale = 1.0 - fi * _EchoScale; float2 echoUV = (uv - 0.5) * scale + 0.5; // Décalage latéral alterné pour l'effet de dédoublement float side = (frac(fi * 0.5) > 0.25) ? 1.0 : -1.0; echoUV.x += side * _EchoSpread * echoT * t; echoUV = clamp(echoUV, 0.0, 1.0); // Opacité décroissante pour les échos lointains float echoAlpha = _EchoOpacity * (1.0 - echoT) * t; half3 echoCol = SampleChroma(echoUV, chromaStrength * 0.5); col = lerp(col, echoCol, echoAlpha * 0.4); } // ── 5. Assombrissement des bords de cellule ─────────── // Les fissures entre cellules sont sombres. float crackMask = 1.0 - smoothstep(0.0, 0.15 * (1.0 - t * 0.5), cellDist); col *= 1.0 - crackMask * _EdgeDarken * t; // ── 6. Vignette de bord d'écran ─────────────────────── float2 vigUV = uv * (1.0 - uv.yx); float vignette = pow(vigUV.x * vigUV.y * 15.0, _EdgePower * (1.0 + t)); col *= saturate(vignette); return half4(col, 1.0); } ENDHLSL } } }