Fix UVScrollLight offset accumulation; update track docs

scrollSpeedX/Y was incorrectly passed to SetTextureScale (tiling),
now accumulated as per-frame offset delta on top of keyframe scrollOffsetX/Y.
Added _uvScrollAccum dict cleared on InitializeTimeline.

Also updated LIVE_TRACKS.md with full-scan coverage numbers and
live-shader-todo.md with blocked-track categorization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ritenseki
2026-05-07 18:55:17 +08:00
parent 5fdbad92d2
commit 04d8db3bb1
3 changed files with 85 additions and 31 deletions
@@ -51,6 +51,8 @@ namespace Gallop.Live
private Dictionary<LiveTimelineEffectData, (int frame, GameObject instance)> _activeEffects
= new Dictionary<LiveTimelineEffectData, (int, GameObject)>();
private Dictionary<string, Vector2> _uvScrollAccum = new Dictionary<string, Vector2>();
private Volume _postProcessVolume;
public UmaViewerAudio.CuteAudioSource liveMusic = new UmaViewerAudio.CuteAudioSource();
@@ -167,6 +169,7 @@ namespace Gallop.Live
public void InitializeTimeline(List<LiveCharacterSelect> characters, int mode)
{
_uvScrollAccum.Clear();
totalTime = _liveTimelineControl.data.timeLength;
liveMode = mode;
@@ -437,23 +440,19 @@ namespace Gallop.Live
private void OnUVScrollLightUpdate(LiveTimelineUVScrollLightData data, LiveTimelineKeyUVScrollLightData keyData)
{
if (keyData == null) return;
// find renderers in stage with matching material name
if (_stageController == null) return;
if (keyData == null || _stageController == null) return;
if (!_uvScrollAccum.ContainsKey(data.name))
_uvScrollAccum[data.name] = Vector2.zero;
_uvScrollAccum[data.name] += new Vector2(keyData.scrollSpeedX, keyData.scrollSpeedY) * Time.deltaTime;
Vector2 totalOffset = new Vector2(keyData.scrollOffsetX, keyData.scrollOffsetY) + _uvScrollAccum[data.name];
foreach (var r in _stageController.GetComponentsInChildren<Renderer>())
{
foreach (var mat in r.materials)
{
string matName = mat.name.Replace(" (Instance)", "");
if (matName != data.name) continue;
mat.SetTextureOffset("_MainTex", new Vector2(keyData.scrollOffsetX, keyData.scrollOffsetY));
// TODO: scrollSpeedX/Y mapped to SetTextureScale — verify correctness.
// If the original shader uses speed as an incremental offset (offset += speed * deltaTime),
// this should accumulate per frame instead of being set as texture tiling.
mat.SetTextureScale("_MainTex", new Vector2(keyData.scrollSpeedX, keyData.scrollSpeedY));
if (mat.name.Replace(" (Instance)", "") != data.name) continue;
mat.SetTextureOffset("_MainTex", totalOffset);
mat.SetColor("_Color", keyData.mulColor0 * keyData.colorPower);
// TODO: unused — mulColor1, ColorType0/1, CharacterIndex0/1,
// IsColorBlend0/1, ColorBlendRate0/1, AltCharaColor0/1, loopType/loopCount.
// TODO: mulColor1, ColorType0/1, CharacterIndex0/1, IsColorBlend0/1, loopType/loopCount
}
}
}
+17 -17
View File
@@ -6,7 +6,7 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
---
# Live 轨道全览(LiveTimelineKeyDataType 枚举,ID 0–102)
数据来源:LiveTimelineDefine.cs 枚举 + WorkSheet CS字段核查 + worksheet_fields.txt(58首歌扫描)+ Director/Control代码审查
数据来源:LiveTimelineDefine.cs 枚举 + WorkSheet CS字段核查 + scan_full.py全量扫描(58首歌,2026-05-07)+ Director/Control代码审查
**实现状态图例**
- ✅ 完整
@@ -32,13 +32,13 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| 6 | Event | 时间轴触发事件 | ❌ | — |
| 7 | CharaMotionSequence ★(5) | 角色动作序列切换 | ✅ | — |
| 8 | BgColor1 ★(13) | 角色色调/轮廓/阴影颜色 | ✅ | — |
| 9 | BgColor2 ★(1) | 背景渐变/环境色(两色混合) | 🔴 Bug已修 | ~~WorkSheet有字段+event已声明,但AlterLateUpdate从未调用AlterUpdate_BgColor2,Director未订阅~~ → 2026-05-07已修复 |
| 9 | BgColor2 ★(1) | 背景渐变/环境色(两色混合)【15/58首】 | ⚠️ | 当前用RenderSettings.ambient*近似,但舞台shader不响应Unity实时光照,实际shader属性名待确认 |
| 10 | MonitorControl ★(2) | LED舞台屏幕内容控制 | ❌ | — |
| 11 | CameraSwitcher | 切换活动摄像机 | ✅ | — |
| 12 | LipSync | 口型同步 | ✅ | — |
| 13 | PostEffectDOF | 景深模糊(单机) | ❌ | — |
| 14 | PostEffectBloomDiffusion | 泛光扩散(单机) | ❌ | — |
| 15 | RadialBlur | 径向运动模糊(单机) | ❌ | — |
| 15 | RadialBlur | 径向运动模糊(单机) | ❌ | WorkSheet有radialBlurKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 16 | CameraLayer | 摄像机渲染层遮罩 | ❌ | — |
| 17 | Projector ★(4) | 舞台投影仪(gobo图案) | ❌ | — |
@@ -82,8 +82,8 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| ID | 名称 | 作用 | 状态 | Bug |
|----|------|------|------|-----|
| 37 | VolumeLight ★(1) | 体积光/SunShafts | ⚠️🔇 | 无SunShafts组件,仅数据 |
| 38 | HdrBloom | HDR泛光强度/阈值 | ⚠️ | 字段映射未经bundle验证(30首歌均无数据);bloomIntensity/threshold映射可能有误 |
| 39 | PostFilm | 全屏后期叠加(晕影/颜色/UV电影) | ❌ | LiveTimelineKeyPostFilmData字段存在,WorkSheet无postFilmKeys声明 |
| 38 | HdrBloom | HDR泛光强度/阈值 | ❌ | 全量扫描确认0/58首有数据,不需要实现 |
| 39 | PostFilm | 全屏后期叠加(晕影/颜色/UV电影) | ❌ | WorkSheet有postFilmKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 40 | Fade | 场景淡入淡出 | ❌ | — |
| 41 | Particle ★(3) | 粒子系统发射速率 | ✅ | — |
| 42 | ParticleGroup ★(3) | 粒子组闪烁速率(双速率曲线) | ✅ | — |
@@ -101,25 +101,25 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| 54 | MultiCameraLookAt ★(2) | 多机位摄像机朝向 | ✅ | — |
| 55 | EyeCameraPos | 眼部特写摄像机位置 | ❌ | — |
| 56 | EyeCameraLookAt | 眼部特写摄像机朝向 | ❌ | — |
| 57 | LensFlare | 镜头光晕 | ❌ | — |
| 58 | Environment ★(1) | 舞台环境参数(天空盒/环境光) | ❌ | WorkSheet无environmentDataLists字段 |
| 57 | LensFlare | 镜头光晕【45/58首】 | ❌ | — |
| 58 | Environment ★(1) | 地板镜面反射/水面波纹/阴影/FovShift【48/58首】 | ❌ | 核心是Planar Reflection(第二摄像机→RenderTexture→地板shader),无现成系统则工程量大;水面UV参数和阴影开关可部分实现 |
| 59 | SweatLocator ★(3) | 角色汗珠特效挂点 | ❌ | WorkSheet无sweatLocatorList字段 |
| 60 | Effect ★(8) | 特效Prefab加载/播放(3d/effect/live/) | ✅ | — |
| 61 | ColorCorrection | 色彩校正(饱和度/RGB曲线) | ⚠️ | depthRedCurve/Green/Blue/blendCurve/mode/selective/keyColor/targetColor无URP对应 |
| 62 | PreColorCorrection | 前置色彩校正 | ❌ | — |
| 63 | TiltShift | 移轴模糊 | ❌ | — |
| 63 | TiltShift | 移轴模糊 | ❌ | WorkSheet有tiltShiftKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 64 | A2U | 内部动作系统参数 | ❌ | 非视觉轨道 |
| 65 | A2UConfig | A2U配置 | ❌ | 非视觉轨道 |
| 66 | FlashPlayer | 全屏闪光播放 | ❌ | — |
| 66 | FlashPlayer | 全屏闪光播放 | ❌ | WorkSheet有flashPlayerKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 67 | Title | 歌曲名字幕显示 | ❌ | — |
| 68 | Spotlight3d ★(3) | 3D聚光灯 SetActive+颜色/强度 | ✅ | — |
| 69 | CharaNode | 角色骨骼节点位置控制 | ❌ | — |
| 70 | NodeScale ★(2) | 舞台节点缩放 | ❌ | WorkSheet无nodeScaleList字段 |
| 71 | Fluctuation | 画面波动/震颤效果 | ❌ | — |
| 72 | CharaFootLight | 角色脚部补光灯 | ❌ | — |
| 72 | CharaFootLight | 角色脚部补光灯 | ❌ | WorkSheet有charaFootLightKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 73 | ChromaticAberration ★(1) | 色差后处理 | ⚠️ | redOffset/greenOffset/blueOffset(通道偏移)无URP内置对应;effectType未使用 |
| 74 | LightProjection ★(18!) | 投影灯(Gobo图案灯) | ❌ | WorkSheet无lightProjectionList字段;song 1001有18条,优先级极高 |
| 75 | Billboard | 广告牌(始终面向摄像机的面片) | ❌ | — |
| 74 | LightProjection ★(18!) | 投影灯(Gobo图案灯)【36/58首】 | ❌ | WorkSheet有lightProjectionList字段;song 1001有18条,高优先级 |
| 75 | Billboard | 广告牌(始终面向摄像机的面片)【12/58首】 | ❌ | — |
---
@@ -127,7 +127,7 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| ID | 名称 | 作用 | 状态 | Bug |
|----|------|------|------|-----|
| 76 | MultiCameraPostFilm ★(2) | 多机位全屏后期叠加 | ❌ | WorkSheet无postFilm1MultiCameraKeys字段 |
| 76 | MultiCameraPostFilm ★(2) | 多机位全屏后期叠加【50/58首】 | ❌ | WorkSheet有postFilm1MultiCameraKeys字段 |
| 77 | MultiCameraPostEffectBloomDiffusion ★(2) | 多机位泛光 | ❌ | WorkSheet无对应字段 |
| 78 | MultiCameraColorCorrection | 多机位色彩校正 | ❌ | — |
| 79 | MultiCameraTiltShift | 多机位移轴模糊 | ❌ | — |
@@ -140,8 +140,8 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| ID | 名称 | 作用 | 状态 | Bug |
|----|------|------|------|-----|
| 82 | AdditionalLight | 附加动态光源 | ❌ | — |
| 83 | MultiLightShadow | 多光源阴影 | ❌ | — |
| 82 | AdditionalLight | 附加动态光源【22/58首】 | ❌ | — |
| 83 | MultiLightShadow | 多光源阴影 | ❌ | WorkSheet有MultiLightShadowKeys字段,58/58首存在但全部0 keyframe(空占位) |
| 84 | MobControl ★(4) | 观众人群行为/动画控制 | ❌ | WorkSheet无MobControlKeys字段 |
| 85 | CyalumeControl ★(4) | 荧光棒颜色/同步控制 | ❌ | WorkSheet无CyalumeControlKeys;CyalumeController3D.cs存在但未接入时间轴 |
| 86 | CameraMotion | 摄像机动作曲线轨道 | ❌ | — |
@@ -174,6 +174,6 @@ originSessionId: 319ae839-0292-4b1e-80de-2f3c91b1f40e
| 🔴 Bug(已修)| 1 |
| ❌ 未实现 | 72 |
## song 1001 有数据但未实现的优先级排序
## 未实现轨道优先级排序
LightProjection(74, 18条) > Audience(34, 12条) > MobControl(84, 4条) > CyalumeControl(85, 4条) > Projector(17, 4条) > MultiCameraPostFilm(76, 2条) > MultiCameraBloom(77, 2条) > NodeScale(70, 2条) > Environment(58, 1条) > SweatLocator(59, 3条) > MonitorControl(10, 2条) > Animation(29, 1条)
LensFlare(57, 45/58首) > LightProjection(74, 36/58首) > AdditionalLight(82, 22/58首) > Billboard(75, 12/58首) > Audience(34, ★12条) > MobControl(84, 4条) > CyalumeControl(85, 4条) > Projector(17, 4条) > MultiCameraPostFilm(76, 50/58首) > NodeScale(70, ★2条) > MonitorControl(10, ★2条) > Animation(29, ★1条) > Environment(58, 48/58首, 需Planar Reflection系统)
+57 -2
View File
@@ -1,6 +1,37 @@
# Live Post-Processing Shader TODO
# Live Timeline 轨道实现 TODO
UmaViewer 使用 **URP 14(Unity 2022.3.62f1)**。游戏原版是 Built-in 管线,以下 shader 需要移植或重写为 URP 实现。
UmaViewer 逆向实现了游戏的 Live 演出系统:
- 解密加载 asset bundle → 反序列化 `LiveTimelineWorkSheet` → `LiveTimelineControl` 每帧插值触发事件 → `Director` 订阅事件调用 Unity API
- 游戏原版 Built-in 管线;UmaViewer 用 URP 14(Unity 2022.3.62f1),toon shader 已移植
- 103 条轨道中约 21 条完整,其余卡点分两类(见下)
---
## 卡点分类
### 缺零件(知道要做什么,Unity/URP 没有现成组件)
| 轨道 | 缺什么 |
|------|-------|
| PostFilm (39) / RadialBlur (15) / TiltShift (63) / SunShafts (37) | URP 无对应效果,需自写 ScriptableRendererFeature + shader |
| LightProjection (74) | Unity `Projector` 组件在 URP 不工作,需 DecalProjector 或自定义实现 |
| Environment (58) | Planar Reflection 系统(第二摄像机→RenderTexture→地板 shader)项目里完全没有 |
| LensFlare (57) | 舞台用 `CustomLensFlare` 脚本,UmaBuild 里无源码 |
### 没 dump 找明白(不知道打哪里)
| 轨道 | 不明白什么 |
|------|-----------|
| BgColor2 (9) | entry 名 `BgWashA`~`J` 在所有 bundle 里找不到,目标对象未知 |
| MonitorControl (10) | `dispID` 值 0–15 不对应 monitor 材质索引,内容资源路径未知 |
| AdditionalLight (82) | 字段未 dump,结构未知 |
### 两个都缺一点
| 轨道 | 情况 |
|------|------|
| WashLight (43) | 对象能找到,`RaycastDistance`/`CameraProjection` 语义不明,可能需要 Projector |
| UVScrollLight (46) | 知道怎么修(offset 累积),还没动手 |
---
@@ -240,6 +271,30 @@ shader 逻辑简单实现,等有真实数据时再调参。
---
## 舞台 / 灯光轨道
### 可以直接做
| 轨道 | 问题 | 难度 |
|------|------|------|
| UVScrollLight (46) bug | `scrollSpeedX/Y` 现在用 `SetTextureScale` 是错的,应每帧累积 `offset += speed * deltaTime`,需持久化累计值 | ★☆☆ |
| BgColor1 (8) 缺字段 | `vertexColorToonPower`、`outlineWidthPower`、`IsSilhouette`、`LightBlendMode` 未传给 shader | ★☆☆ |
| BlinkLight (45) 缺字段 | `color1Array`(多色循环)、`LightBlendMode`、`isReverseHueArray` 未使用 | ★★☆ |
| AdditionalLight (82) | 22/58 首有数据,字段未 dump,可能是普通 Light 参数,需先 dump 再评估 | 待评估 |
| Billboard (75) | 12/58 首有数据,始终朝摄像机的面片,Unity 有内置 `BillboardRenderer` 或 LookAt 逻辑 | ★☆☆ |
### 暂时卡住
| 轨道 | 卡点 | 解法方向 |
|------|------|---------|
| BgColor2 (9) | entry 名 `BgWashA`~`BgWashJ` 在所有 stage bundle 和 meta DB 里均不存在;舞台 shader 不响应 Unity 环境光,所以当前 `RenderSettings.ambient*` 实现无效 | 需 Frame Debugger 截帧确认实际 shader 属性名,须找到镜头给到舞台背景全景的歌曲 |
| LensFlare (57) | Stage bundle 用 `CustomLensFlare` / `UnityLensFlareController` 脚本,UmaBuild 里无源码 | 可先做 `SetActive`(`enableFlare`);完整颜色/亮度控制需找到脚本接口或用 Renderer 直接设材质颜色 |
| MonitorControl (10) | `dispID` 值 0–15 不对应 monitor 材质索引(每个舞台只有 2–5 张);内容资源路径格式未知 | 可先做框架 + `colorFade`/UV 控制,`dispID` 内容切换留 TODO |
| LightProjection (74) | Unity 的 `Projector` 组件在 URP 不工作;URP 有 `DecalProjector` 但 API 差异较大 | 用 URP `DecalProjector` 替代;或用自定义 `ScriptableRendererFeature` 实现投影 |
| Environment (58) | 核心是 Planar Reflection(第二摄像机 → RenderTexture → 地板 shader),项目里完全没有这套系统 | 水面 UV 参数 + 阴影开关可部分实现;镜面反射需从零搭 Planar Reflection Camera |
---
## 项目信息
- Unity: 2022.3.62f1(URP 14.0.12)