From 042785e3dcfd8adbc6ad63d69fc7aad8fa13f99a Mon Sep 17 00:00:00 2001 From: bottlefish <781230111@qq.com> Date: Sat, 25 Jul 2026 15:57:10 +0800 Subject: [PATCH] =?UTF-8?q?art(huoshan):=20=E8=B0=83=E6=95=B4=E8=AE=B0?= =?UTF-8?q?=E5=BF=86shader=E8=A1=A8=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- Assets/Materials/M_HuoshanMemory.mat | 3 + Assets/Shader/HuoshanMemory.shader | 83 +++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/Assets/Materials/M_HuoshanMemory.mat b/Assets/Materials/M_HuoshanMemory.mat index 1936a8bfc..fecc661a7 100644 --- a/Assets/Materials/M_HuoshanMemory.mat +++ b/Assets/Materials/M_HuoshanMemory.mat @@ -29,6 +29,9 @@ Material: m_Offset: {x: 0, y: 0} m_Ints: [] m_Floats: + - _AnalogChroma: 0.5 + - _AnalogGlitch: 0.25 + - _AnalogScale: 1.6 - _Brightness: 1 - _CalmFeather: 0.2 - _CalmRadius: 0 diff --git a/Assets/Shader/HuoshanMemory.shader b/Assets/Shader/HuoshanMemory.shader index 38a4b4d4c..0220dfbaa 100644 --- a/Assets/Shader/HuoshanMemory.shader +++ b/Assets/Shader/HuoshanMemory.shader @@ -21,6 +21,12 @@ Shader "AibisDream/HuoshanMemory" _CalmFeather("Calm Feather", Range(0.001, 1)) = 0.2 _EffectStrength("Effect Strength", Range(0, 1)) = 0 _Opacity("Opacity", Range(0, 1)) = 0 + + // 屏幕故障(HuoshanScreenGlitch)的减弱版,只有三个旋钮,其余系数内部推导。 + [Header(Analog Signal Layer)] + _AnalogGlitch("Analog Layer Amount", Range(0, 1)) = 0.25 + _AnalogScale("Analog Scale", Range(0.25, 6)) = 1.6 + _AnalogChroma("Analog Chroma Tint", Range(0, 2)) = 0.5 } SubShader @@ -87,6 +93,9 @@ Shader "AibisDream/HuoshanMemory" float _CalmFeather; float _EffectStrength; float _Opacity; + float _AnalogGlitch; + float _AnalogScale; + float _AnalogChroma; CBUFFER_END float hash21(float2 p) @@ -148,24 +157,24 @@ Shader "AibisDream/HuoshanMemory" 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))); + // Persistent simulation wobble: light enough for ambient, readable on still frames. + sampleUV.x += sin((input.uv.y * 18.0 + _Time.y * 0.8) * 6.28318) * 0.0024 * sim; + sampleUV.y += sin((input.uv.x * 13.0 - _Time.y * 0.55) * 6.28318) * 0.0014 * sim; + float simSlot = floor(_Time.y * 1.15 + _TearSeed * 7.0); + float simGate = step(0.55, 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 simRowPick = step(0.86, 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.x += simJitterDir * simGate * simRowPick * 0.0065 * sim; sampleUV.y = (sampleUV.y - 0.5) * - (1.0 + impact * 0.016 + overdrive * 0.025) + 0.5; + (1.0 + impact * 0.016 + overdrive * 0.025 + sim * 0.008) + 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); + (damage * 0.0035 + impact * 0.009 + overdrive * 0.016 + sim * 0.0028) * + lerp(0.35, 1.0, max(tearGate, sim * 0.55)); half red = SAMPLE_TEXTURE2D( _MainTex, sampler_MainTex, @@ -196,7 +205,7 @@ Shader "AibisDream/HuoshanMemory" 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); + (_Noise * effect + damage * 0.08 + overdrive * 0.16 + sim * 0.045); graded += signedNoise.xxx; float dropoutRow = floor(input.uv.y * lerp(9.0, 21.0, overdrive)); @@ -210,8 +219,56 @@ Shader "AibisDream/HuoshanMemory" 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)); + // Simulation stays on the memory sprite itself — no external noise overlay. + float3 finalColor = lerp(original.rgb, graded, max(distortion, sim * 0.62)); + + // ── 轻量模拟信号层:和屏幕故障(HuoshanScreenGlitch)同源的减弱版, + // 只做轻微色偏 + 扫描线 + 颗粒,不改变画面结构。密度按屏幕像素计, + // 记忆图缩放到多大都是同一种颗粒度。Calm 区(要读字的地方)自动让位。 + float analog = saturate(_AnalogGlitch) * (1.0 - calmMask * 0.85); + if (analog > 0.001) + { + float analogScale = max(0.25, _AnalogScale); + float analogRibbonPx = 90.0 * analogScale; + float analogScanPx = 8.0 * analogScale; + float analogGrainPx = 3.0 * analogScale; + float analogRowPx = 14.0 * analogScale; + + float2 analogTexel = float2( + max(fwidth(input.uv.x), 1e-7), + max(fwidth(input.uv.y), 1e-7)); + float2 analogPixel = input.uv / analogTexel; + + float analogLuma = dot(finalColor, float3(0.299, 0.587, 0.114)); + float analogRow = floor(analogPixel.y / analogRowPx); + float analogRowPhase = + (hash21(float2(analogRow, floor(_Time.y * 12.0))) - 0.5) * 1.4; + + float analogRibbon = + analogPixel.x * 6.2831853 / analogRibbonPx + + sin(input.uv.y * 12.0 + _Time.y * 1.3) * 1.8 + + analogRowPhase + - _Time.y * 1.6; + + // 以 0 为中心:只染色不提亮,保证"轻轻叠一点点"。 + float3 analogPhase = 6.2831853 * ( + (analogLuma + sin(analogRibbon) * 0.35) * 1.1 + + float3(0.0, 1.0, 2.0) * 0.14 + + 0.62); + finalColor += 0.5 * cos(analogPhase) + * analog * _AnalogChroma * (0.5 + analogLuma); + + float analogScanFade = saturate((analogScanPx - 1.6) / 1.4); + float analogScanWave = + 0.5 + 0.5 * sin(analogPixel.y * 6.2831853 / analogScanPx); + finalColor *= lerp(1.0, analogScanWave, + saturate(0.35 * analog * analogScanFade)); + + float analogGrain = hash21( + floor(analogPixel / analogGrainPx) + + floor(_Time.y * 24.0) * 0.137) - 0.5; + finalColor += analogGrain * 0.09 * analog; + } return half4( finalColor * input.color.rgb,