Files
aibis-dream/Assets/Shader/HuoshanMemory.shader
T

226 lines
9.4 KiB
Plaintext

Shader "AibisDream/HuoshanMemory"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_Color("Tint", Color) = (1,1,1,1)
_Saturation("Saturation", Range(0, 2)) = 1
_Brightness("Brightness", Range(0, 2)) = 1
_Contrast("Contrast", Range(0, 2)) = 1
_Vignette("Vignette", Range(0, 1)) = 0
_Noise("Noise", Range(0, 1)) = 0
_SimGlitch("Simulation Glitch", Range(0, 1)) = 0
_HorizontalTear("Horizontal Tear", Range(0, 1)) = 0
_Impact("Transient Memory Impact", Range(0, 1)) = 0
_Damage("Accumulated Memory Damage", Range(0, 1)) = 0
_Overdrive("Slot Machine Overdrive", Range(0, 1)) = 0
_TearSeed("Tear Seed", Range(0, 1)) = 0
_ColorTint("Memory Color Tint", Color) = (1,1,1,1)
_CalmCenter("Calm Center", Vector) = (0.5,0.5,0,0)
_CalmRadius("Calm Radius", Range(0, 1.5)) = 0
_CalmFeather("Calm Feather", Range(0.001, 1)) = 0.2
_EffectStrength("Effect Strength", Range(0, 1)) = 0
_Opacity("Opacity", Range(0, 1)) = 0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderType" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
"IgnoreProjector" = "True"
"CanUseSpriteAtlas" = "True"
}
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
Name "HuoshanMemory"
Tags { "LightMode" = "Universal2D" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
float4 _Color;
float _Saturation;
float _Brightness;
float _Contrast;
float _Vignette;
float _Noise;
float _SimGlitch;
float _HorizontalTear;
float _Impact;
float _Damage;
float _Overdrive;
float _TearSeed;
float4 _ColorTint;
float4 _CalmCenter;
float _CalmRadius;
float _CalmFeather;
float _EffectStrength;
float _Opacity;
CBUFFER_END
float hash21(float2 p)
{
float3 p3 = frac(float3(p.xyx) * 0.1031);
p3 += dot(p3, p3.yzx + 33.33);
return frac((p3.x + p3.y) * p3.z);
}
Varyings vert(Attributes input)
{
Varyings output;
output.positionHCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = TRANSFORM_TEX(input.uv, _MainTex);
output.color = input.color * _Color;
return output;
}
half4 frag(Varyings input) : SV_Target
{
float2 centered = (input.uv - _CalmCenter.xy);
float calmDistance = length(centered);
float calmMask = 1.0 - smoothstep(
_CalmRadius,
_CalmRadius + max(0.001, _CalmFeather),
calmDistance);
calmMask *= step(0.001, _CalmRadius);
float effect = saturate(_EffectStrength) * (1.0 - calmMask);
// Small persistent simulation disturbance, independent of the impact path.
float sim = saturate(_SimGlitch) * (1.0 - calmMask * 0.85);
float impact = saturate(_Impact);
float damage = saturate(_Damage);
float overdrive = saturate(_Overdrive);
float distortion = saturate(max(effect, damage * 0.72 + impact * 0.84 + overdrive));
distortion *= 1.0 - calmMask;
// Each large word punches the memory closer before tearing it into horizontal slices.
float zoom = 1.0 + impact * 0.10 + overdrive * 0.035;
float2 sampleUV = (input.uv - 0.5) / zoom + 0.5;
float rowCount = lerp(22.0, 68.0, overdrive);
float row = floor(input.uv.y * rowCount);
float timeStep = floor(
_Time.y * lerp(9.0, 31.0, overdrive) +
_TearSeed * 97.0);
float rowNoise = hash21(float2(row + _TearSeed * 43.0, timeStep));
float tearThreshold = lerp(
0.91,
0.36,
saturate(damage * 0.55 + impact * 0.75 + overdrive));
float tearGate = step(tearThreshold, rowNoise);
float tearDirection =
hash21(float2(row * 1.71 + _TearSeed * 19.0, timeStep * 0.83)) * 2.0 - 1.0;
float tearAmount =
_HorizontalTear * 0.08 +
damage * 0.026 +
impact * 0.060 +
overdrive * 0.082;
sampleUV.x += tearDirection * tearGate * tearAmount * distortion;
// Subtle continuous UV wobble plus an occasional narrow-row slip.
sampleUV.x += sin((input.uv.y * 18.0 + _Time.y * 0.8) * 6.28318) * 0.0012 * sim;
sampleUV.y += sin((input.uv.x * 13.0 - _Time.y * 0.55) * 6.28318) * 0.0007 * sim;
float simSlot = floor(_Time.y * 0.9 + _TearSeed * 7.0);
float simGate = step(0.62, hash21(float2(simSlot, 3.7)));
float simRow = floor(input.uv.y * 34.0);
float simRowPick = step(0.90, hash21(float2(simRow + simSlot * 13.0, 11.3)));
float simJitterDir = hash21(float2(simSlot * 1.37, simRow)) * 2.0 - 1.0;
sampleUV.x += simJitterDir * simGate * simRowPick * 0.0035 * sim;
sampleUV.y = (sampleUV.y - 0.5) *
(1.0 + impact * 0.016 + overdrive * 0.025) + 0.5;
sampleUV = saturate(sampleUV);
half4 original = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
float chromaOffset =
(damage * 0.0035 + impact * 0.009 + overdrive * 0.016) *
lerp(0.35, 1.0, tearGate);
half red = SAMPLE_TEXTURE2D(
_MainTex,
sampler_MainTex,
saturate(sampleUV + float2(chromaOffset, 0))).r;
half4 displaced = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, sampleUV);
half blue = SAMPLE_TEXTURE2D(
_MainTex,
sampler_MainTex,
saturate(sampleUV - float2(chromaOffset, 0))).b;
float3 memorySample = float3(red, displaced.g, blue);
float luminance = dot(memorySample, float3(0.2126, 0.7152, 0.0722));
float3 graded = lerp(luminance.xxx, memorySample, _Saturation);
graded = (graded - 0.5) * _Contrast + 0.5;
graded *= _Brightness;
graded *= _ColorTint.rgb;
// At the hit, collapse the busy memory into a near-uniform ink field so the
// white center word owns the frame. A little luminance remains as a ghost contour.
float flatten = saturate(impact * 0.82 + overdrive * 0.68);
float3 inkColor = float3(0.012, 0.035, 0.065);
float3 inkMemory = inkColor + luminance.xxx * lerp(0.13, 0.04, overdrive);
graded = lerp(graded, inkMemory, flatten);
float vignetteDistance = length(input.uv - 0.5) * 1.4142;
float vignette = 1.0 - smoothstep(0.38, 1.0, vignetteDistance) * _Vignette;
graded *= lerp(1.0, vignette, distortion);
float noiseValue = hash21(floor(input.uv * float2(640, 360)) + floor(_Time.y * 24.0));
float signedNoise = (noiseValue - 0.5) *
(_Noise * effect + damage * 0.08 + overdrive * 0.16);
graded += signedNoise.xxx;
float dropoutRow = floor(input.uv.y * lerp(9.0, 21.0, overdrive));
float dropoutNoise = hash21(float2(
dropoutRow + _TearSeed * 61.0,
floor(_Time.y * lerp(7.0, 24.0, overdrive))));
float dropoutGate = step(lerp(1.05, 0.78, overdrive), dropoutNoise);
float dropoutLevel = lerp(
0.18,
1.55,
hash21(float2(dropoutRow * 3.17, timeStep)));
graded *= lerp(1.0, dropoutLevel, dropoutGate * overdrive * 0.72);
// The simulation path only opens a light amount of grading/distortion.
float3 finalColor = lerp(original.rgb, graded, max(distortion, sim * 0.45));
return half4(
finalColor * input.color.rgb,
original.a * input.color.a * _Opacity);
}
ENDHLSL
}
}
Fallback "Sprites/Default"
}