From c16e9d06eeb1dee5bc524bb9f19cedabc939d0f8 Mon Sep 17 00:00:00 2001 From: bottlefish <781230111@qq.com> Date: Sat, 25 Jul 2026 23:26:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(huoshan):=20=E4=BF=AE=E5=A4=8D=E8=AE=B0?= =?UTF-8?q?=E5=BF=86=E6=B7=A1=E5=85=A5=E8=A2=ABnoise=E9=81=AE=E6=8C=A1?= =?UTF-8?q?=E5=B9=B6=E6=81=A2=E5=A4=8D=E6=9D=90=E8=B4=A8=E5=A4=B1=E7=9C=9F?= =?UTF-8?q?=E4=BA=A4=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 进记忆前保留 glitch_transition noise,begin 时透明淡出并改由 HuoshanMemory 材质承接轻微失真;记忆渲染进 HuoshanScreen 以进入 VolFx 合成。 Co-authored-by: Cursor --- Assets/Scenes/HuoShanFixScene.unity | 6 +- .../HuoShan/Language/LanguageYarnCommand.cs | 3 +- .../LogReleasePresentationController.cs | 38 ++- Assets/Shader/HuoshanMemory.hlsl | 225 +++++++++++++++++ Assets/Shader/HuoshanMemory.hlsl.meta | 7 + Assets/Shader/HuoshanMemory.shader | 233 ++---------------- Assets/Yarn/FP/FP_Huoshan1/Stage6.yarn | 8 +- 7 files changed, 292 insertions(+), 228 deletions(-) create mode 100644 Assets/Shader/HuoshanMemory.hlsl create mode 100644 Assets/Shader/HuoshanMemory.hlsl.meta diff --git a/Assets/Scenes/HuoShanFixScene.unity b/Assets/Scenes/HuoShanFixScene.unity index b8963fa01..643fb13ef 100644 --- a/Assets/Scenes/HuoShanFixScene.unity +++ b/Assets/Scenes/HuoShanFixScene.unity @@ -15877,9 +15877,9 @@ MonoBehaviour: sunsetMemory: {fileID: 21300000, guid: 4d9b651ad3ad15941a4a49bb381c5a2d, type: 3} privateOfficeMemory: {fileID: 21300000, guid: 56e0c1ba37badb94d8fa982258ade9e7, type: 3} memoryMaterial: {fileID: 2100000, guid: f99b647eb8e7425fb1f0e32590dfc77d, type: 2} - simGlitchLight: 0.2 - simGlitchMedium: 0.26 - simGlitchHeavy: 0.32 + simGlitchLight: 0.28 + simGlitchMedium: 0.36 + simGlitchHeavy: 0.44 faceFadeDuration: 1 memoryFadeDuration: 0.55 memoryExitDuration: 0.45 diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs index f5860f178..d30d41ec2 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs @@ -182,7 +182,8 @@ namespace AibisDream.MiniGame.Language /// /// 记忆淡入(非阻塞):透明度在 fadeDuration 内显现,画面同时按 pushSpeed 持续推近; /// targetOpacity 是本次淡入的目标透明度。horizontalSpeed 为旧 Yarn 兼容参数,基础层不再横移。 - /// 争夺段的 jolt / tear / impact 仍会叠加。 + /// 进记忆前可用 glitch_transition 铺 noise;begin 时会把 noise 淡出,改由记忆材质 + /// _SimGlitch / Analog 承接轻微失真。preserveGlitch 已忽略。争夺段 jolt/tear/impact 仍叠加。 /// [YarnCommand("expression_memory_begin")] public static void ExpressionMemoryBegin( diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs index 324ae765f..7ad13027b 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs @@ -342,9 +342,8 @@ namespace AibisDream.MiniGame.Language state = PresentationState.Memory; // 兜底:跳过 face_fade_in 直进记忆时,目标字仍切到演出白。 particleManager?.ApplyPresentationResolvedVisuals(presentationResolvedColor); - // 记忆失真全部走 HuoshanMemory 材质;清掉 noise 叠层残留。 + // preserveGlitch 已弃用:进记忆后失真只走 HuoshanMemory 材质,不再保留 noise 叠层。 _ = preserveGlitch; - SilenceNoiseOverlayIfPresent(); SpriteRenderer incoming = activeMemoryRenderer == memoryRendererA ? memoryRendererB : memoryRendererA; SpriteRenderer outgoing = activeMemoryRenderer; @@ -365,6 +364,10 @@ namespace AibisDream.MiniGame.Language float resolvedFadeDuration = fadeDuration > 0f ? Mathf.Max(0.01f, fadeDuration) : memoryFadeDuration; + + // 进记忆前的 glitch_transition noise → 透明叠层后淡出; + // 记忆材质 _SimGlitch / Analog 随透明度一起浮现,完成交接。 + ReleaseNoiseOverlayIntoMemory(resolvedFadeDuration); SetMemoryOpacity(incoming, 0f); TweenMemoryOpacity( incoming, @@ -2080,11 +2083,37 @@ namespace AibisDream.MiniGame.Language if (glitchController == null) return; + // OpaqueBackground 即使 Intensity=0 仍会写满不透明黑底。 + // 记忆阶段切到 TransparentOverlay,避免盖住画面。 + glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay); glitchController.Intensity = 0f; glitchController.SetAmbientNoise(0f, 320f, 0f); glitchController.ClearCalmField(true); } + /// + /// 进记忆交接:把进场前的 noise 从「不透明黑底」切成透明叠层并淡出, + /// 让记忆材质自身的 _SimGlitch / Analog 接上失真,而不是突然掐断或继续盖住画面。 + /// + private void ReleaseNoiseOverlayIntoMemory(float memoryFadeDuration) + { + if (glitchController == null) + return; + + glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay); + glitchController.SetAmbientNoise(0f, 320f, 0f); + glitchController.ClearCalmField(true); + + float releaseDuration = Mathf.Clamp(memoryFadeDuration * 0.35f, 0.12f, 0.55f); + if (glitchController.Intensity <= 0.001f) + { + glitchController.Intensity = 0f; + return; + } + + glitchController.TransitionTo(0f, releaseDuration); + } + private void ResetNoiseOverlayForGlitchTransition() { if (glitchController == null) @@ -2322,6 +2351,11 @@ namespace AibisDream.MiniGame.Language { GameObject obj = new GameObject(objectName); obj.transform.SetParent(runtimeRoot, false); + // 与粒子 / 屏幕同属 HuoshanScreen,进入 VolFx huoshan 合成; + // 留在 Default 会被 sortingOrder 10 的不透明 noise 盖住。 + int huoshanScreen = LayerMask.NameToLayer("HuoshanScreen"); + if (huoshanScreen >= 0) + obj.layer = huoshanScreen; SpriteRenderer renderer = obj.AddComponent(); renderer.sharedMaterial = memoryMaterial; renderer.sortingOrder = 0; diff --git a/Assets/Shader/HuoshanMemory.hlsl b/Assets/Shader/HuoshanMemory.hlsl new file mode 100644 index 000000000..095423148 --- /dev/null +++ b/Assets/Shader/HuoshanMemory.hlsl @@ -0,0 +1,225 @@ +#ifndef HUOSHAN_MEMORY_INCLUDED +#define HUOSHAN_MEMORY_INCLUDED + +#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; + float _AnalogGlitch; + float _AnalogScale; + float _AnalogChroma; +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; + + // 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.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.0065 * sim; + + sampleUV.y = (sampleUV.y - 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 + sim * 0.0028) * + lerp(0.35, 1.0, max(tearGate, sim * 0.55)); + 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 + sim * 0.045); + 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); + + // 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, + original.a * input.color.a * _Opacity); +} + +#endif // HUOSHAN_MEMORY_INCLUDED diff --git a/Assets/Shader/HuoshanMemory.hlsl.meta b/Assets/Shader/HuoshanMemory.hlsl.meta new file mode 100644 index 000000000..5c47b23b2 --- /dev/null +++ b/Assets/Shader/HuoshanMemory.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b7e4c2a91f0d4e6a8c3d5f1a2b9e7c04 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Shader/HuoshanMemory.shader b/Assets/Shader/HuoshanMemory.shader index 0220dfbaa..04ede4358 100644 --- a/Assets/Shader/HuoshanMemory.shader +++ b/Assets/Shader/HuoshanMemory.shader @@ -53,227 +53,22 @@ Shader "AibisDream/HuoshanMemory" #pragma vertex vert #pragma fragment frag #pragma target 3.0 + #include "HuoshanMemory.hlsl" + ENDHLSL + } - #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + // VolFx huoshan(LayerMask=HuoshanScreen)只抽 SRPDefaultUnlit / UniversalForward*, + // 没有这一 pass 时记忆进不了电视合成层。 + Pass + { + Name "HuoshanMemoryUnlit" + Tags { "LightMode" = "SRPDefaultUnlit" } - 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; - float _AnalogGlitch; - float _AnalogScale; - float _AnalogChroma; - 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; - - // 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.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.0065 * sim; - - sampleUV.y = (sampleUV.y - 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 + sim * 0.0028) * - lerp(0.35, 1.0, max(tearGate, sim * 0.55)); - 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 + sim * 0.045); - 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); - - // 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, - original.a * input.color.a * _Opacity); - } + HLSLPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + #include "HuoshanMemory.hlsl" ENDHLSL } } diff --git a/Assets/Yarn/FP/FP_Huoshan1/Stage6.yarn b/Assets/Yarn/FP/FP_Huoshan1/Stage6.yarn index 6f7363f08..5f67071dc 100644 --- a/Assets/Yarn/FP/FP_Huoshan1/Stage6.yarn +++ b/Assets/Yarn/FP/FP_Huoshan1/Stage6.yarn @@ -98,7 +98,7 @@ me: 火山! #line:034a446 hs: 好啦好啦,我不闹了。 #line:0607264 <> <> -<> +// 进记忆后勿再调 glitch_transition:失真改由记忆材质承接;再调会盖住画面。 <> sellerA: 火火火火火火山,帽子又卖卖卖不出去啦? // 嘲笑落点:补一记记忆抖动 @@ -207,8 +207,10 @@ hs: …还要说么? #line:03686b3 me: 当然。 #line:0ba8b5d hs: 能不说吗… me: 不能。 +<> +<> <> -<> +// 进记忆后勿再调 glitch_transition:失真改由记忆材质承接;再调会盖住画面。 <> me: 劝你多少次了,咱们就该一起投递首都的岗位。 me: 到时候,我们还一块,天天去喝酒。 @@ -334,7 +336,7 @@ me: 说呀! #line:09d7762 hs: …… #line:0a5286d <> <> -<> +// 进记忆后勿再调 glitch_transition:失真改由记忆材质承接;再调会盖住画面。 <> yl: 你怎么总是在关键时刻掉链子? hs: 英理,你听我解释……