diff --git a/Assets/Scripts/umamusume/Gallop/Live/StageController.cs b/Assets/Scripts/umamusume/Gallop/Live/StageController.cs index 12df663..0e06060 100644 --- a/Assets/Scripts/umamusume/Gallop/Live/StageController.cs +++ b/Assets/Scripts/umamusume/Gallop/Live/StageController.cs @@ -2,6 +2,7 @@ using Gallop.Live.Cutt; using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Rendering; namespace Gallop.Live @@ -106,6 +107,9 @@ namespace Gallop.Live } } + // 光柱/闪光类 shader 的混合状态被 bundle 材质里的 URP Lit 属性表压成了不透明,先修回来。 + RestoreAuthoredBlendState(); + // 舞台自带 Animation 的播放(原版由缺失的 AnimationObjectController 负责)。 StageAnimationPlayer.Setup(this); @@ -113,6 +117,85 @@ namespace Gallop.Live StageMissingScriptCensus.Dump(this); } + /// + /// 把材质的 `_SrcBlend`/`_DstBlend` 恢复成 **shader 自己声明的默认值**。 + /// + /// 为什么必须做:Gallop 的光柱类 shader 把混合状态写成 `Blend [_SrcBlend] [_DstBlend]`, + /// 也就是从材质属性里读。而 live10149 的 **26/26 个材质**存的都是 + /// `_SrcBlend=One, _DstBlend=Zero`(= 不透明覆盖),并且每一个的 float 表里都齐刷刷带着 + /// `_WorkflowMode`/`_Surface`/`_ClearCoatMask`/`_Smoothness`/`_Blend` —— 那是 **URP Lit 的 + /// 属性表**,整批盖上去的,One/Zero 正是 URP Lit 的不透明预设,不是作者意图。 + /// + /// 作者意图是可查的:全库 499 个 shader 里有 16 个声明了这两个属性,其中 **14 个的 + /// 声明默认值是 `One/One`(加法混合)** —— LightBlinkBlend、LightBlend、StageBeamLight + /// 三兄弟、StageLightBlink{Cutoff,Fadeout}、StageProjectorBlend 三兄弟、 + /// MirrorBallProjector 等,全是发光/投影的那一批。 + /// + /// 后果:加法混合下 `_BlinkLightColor` 为黑 = 什么都不加 = 光柱不可见;被压成不透明后, + /// 同一个黑色就变成一堵实心黑墙。ground wash light 扫动时那几片「转来转去的黑楔子」 + /// 就是这么来的,`LIVE_TRACKS.md` 里「小灯泡渲染成黑块」多半也是同一根因。 + /// + /// 这个修法是自限的:对本来就该不透明的 shader,声明默认值就是 One/Zero,写回去等于没动。 + /// ⚠ 只改 shader **确实声明了**的属性 —— 材质存档表不可信,shader 才是准。 + /// + private void RestoreAuthoredBlendState() + { + var done = new HashSet(); + var changed = new List(); + + foreach (var r in GetComponentsInChildren(true)) + { + foreach (var mat in r.sharedMaterials) + { + if (mat == null || mat.shader == null || !done.Add(mat)) continue; + + string before = null, after = null; + foreach (string prop in kBlendProps) + { + if (!TryGetShaderDefaultFloat(mat.shader, prop, out float authored)) continue; + float current = mat.GetFloat(prop); + if (Mathf.Approximately(current, authored)) continue; + + before = $"{before}{prop}={current} "; + after = $"{after}{prop}={authored} "; + mat.SetFloat(prop, authored); + } + + if (after != null) + changed.Add($"{mat.name}[{mat.shader.name}] {before}→ {after}"); + } + } + + if (changed.Count == 0) + { + Debug.Log($"[StageBlend] {done.Count} 个材质的混合状态与 shader 声明一致,无需修正"); + return; + } + + Debug.Log($"[StageBlend] {changed.Count}/{done.Count} 个材质的 _SrcBlend/_DstBlend 与 shader 声明不符," + + $"已恢复成 shader 的默认值:\n " + string.Join("\n ", changed)); + } + + private static readonly string[] kBlendProps = { "_SrcBlend", "_DstBlend" }; + + /// shader 声明的默认值。材质没有这个属性、或类型不是 Float/Range 时返回 false。 + private static bool TryGetShaderDefaultFloat(Shader shader, string propName, out float value) + { + value = 0f; + int count = shader.GetPropertyCount(); + for (int i = 0; i < count; i++) + { + if (shader.GetPropertyName(i) != propName) continue; + + var type = shader.GetPropertyType(i); + if (type != ShaderPropertyType.Float && type != ShaderPropertyType.Range) return false; + + value = shader.GetPropertyDefaultFloatValue(i); + return true; + } + return false; + } + public void UpdateObject(ref ObjectUpdateInfo updateInfo) { if (updateInfo.data == null)