Files
Ipseity-Demo/Assets/_Content/Shaders/Glitch.shader
T

230 lines
9.7 KiB
GLSL

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
}
}
}