docs: settle the mirror ball rotation question with dumped data
Chased the lead that MirrorBallProjector's shader might cross-validate the ball's rotation
speed. It does — by showing there was never an unknown constant to recover.
* All four MirrorBallProjector instances on live10149 carry MirrorBallIsLoopRotation = 0,
MirrorBallLoopRotationSpeed = 0, MirrorBallLoopRotationValue = 0. The shader's own
loop-rotation path is switched off on this stage, so it is not the rotation source.
* The source is the clip StageAnimationPlayer already plays. Its six quaternion curves
(mirrorball_a_000 and b_000..004) give a constant -179.50 deg/s about Y — the same figure
at every one of the seven keys — 2.0 s per loop, last key -359 deg so the loop seam does
not repeat a frame. The ball speed in our build is therefore already correct.
The general lesson is recorded too: "the value is 0" and "the value is unknown" are different
findings, and this one was filed as the latter for weeks. Check the enable flag before
declaring a constant unrecoverable.
What genuinely is blocked here is narrower than "the script's behaviour": the shader wants
_MirrorBallPosWS / _MirrorBallScale / _MirrorBallRotateValue, the component holds no reference
to any ball, all four projectors sit at the origin sharing one material, and the balls are at
six scattered positions. The object-to-object binding lives in the method body. The Blocked
section now says that instead of using this field as its example.
Two other things fell out of the same dump pass:
* LensFlare is not a "build a system from scratch" item at all. CustomLensFlare's Flare
points at Gallop.RenderPipeline.LensFlareData — a ScriptableObject in the same assembly,
so rebuildable by signature — whose fields are a verbatim copy of Unity's legacy Flare
(TextureLayout, Texture, ElementArray[ImageIndex/Position/Size/Color/UseLightColor/
Rotate/Zoom/Fade], UseFog). That means the semantics are Unity's own and not blocked by
IL2CPP, and URP ships LensFlareComponentSRP as the target. 199+5 objects carry it, and
the stage has no legacy LensFlare component anywhere. Promoted to the next thing to do.
* ShaderParamController, previously ranked "cheapest", is a no-op: its only two entries are
_AmbientColor and _CharaColor, both (1,1,1,1). Struck from the list rather than left as
bait.
The stale-saved-properties warning gains a worked example, because mtl_env_live10149_
projector001 is a good one: 40+ saved entries against 22 real ones, including _IsLoopYRotation
and _LoopYRotationSpeed, which are older spellings of properties that do exist — a near-miss
that reads as a discovery.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzXXkLzVC8pNA3JjyUGMbq
This commit is contained in:
@@ -111,6 +111,8 @@ pf = obj.read_typetree()["m_ParsedForm"] # m_Name, m_PropInfo.m_Props
|
||||
|
||||
⚠️ A material's `m_SavedProperties` in the bundle lists properties it no longer has — it retains entries from whatever shader it was authored against. `Material.HasProperty()` asks the *current shader*. Always enumerate the shader, never trust the bundle's saved-property table.
|
||||
|
||||
Worked example — `mtl_env_live10149_projector001` (shader `Gallop/3D/MirrorAndShadow/MirrorBallProjector`, 22 real properties) saves 40+, including Standard-shader leftovers (`_Glossiness`, `_Metallic`, `_Parallax`, `_Mode`, `_UVSec`) **and** four plausible-looking ghosts the current shader never declares: `_IsLoopYRotation`, `_LoopYRotationSpeed`, `_MirrorBallProjectionIntensity`, `_MirrorBallRotateWS`. Two of those are older spellings of properties that *do* exist (`_MirrorBallIsLoopRotation`, `_MirrorBallLoopRotationSpeed`) — exactly the kind of near-miss that reads as a discovery. Note also that where a component field and a saved property disagree (`MirrorBallFallOffPower` = 1.0 on the component vs `_MirrorBallFalloffPower` = 2.0 in the material), the component wins at runtime: these controllers push their own fields into the material.
|
||||
|
||||
**Track group names are not always GameObject names.** Four separate silent failures were traced to this in one session, so check the mapping before assuming a track is unimplemented:
|
||||
- a whitelist filter in the dispatcher dropped 92% of BgColor1's keys (`validBgColorNames`)
|
||||
- `StageObjectMap` dedupes by name, so a crowd of 66 same-named objects only ever got its first member
|
||||
@@ -150,18 +152,31 @@ MonoBehaviour 实例脚本为空。**但这些脚本是可以「接管」的**
|
||||
|
||||
签名清单(`Assets/Scripts/` 下任意位置均可,只要在 umamusume 程序集内):
|
||||
|
||||
| namespace | 类 | live10149 实例数 | 状态 |
|
||||
| namespace | 类 | live10149 实例数 | 状态 / 已 dump 到的字段 |
|
||||
|---|---|---|---|
|
||||
| `Gallop.Live` | `AnimationObjectController` | 282 | ❌(动画播放已由 `StageAnimationPlayer` 顶上,见下)|
|
||||
| `Gallop.Live` | `UnityLensFlareController` | 205 | ❌ |
|
||||
| `Gallop.Live` | `UnityLensFlareController` | 205 | ❌ 只有 1 个字段 `_enableAngleDegree`(0),本体不在这里 |
|
||||
| `Gallop.Live` | `BillboardController` | 164 | ✅ 已建(字段已读到,朝向行为待定)|
|
||||
| `Gallop.Live` | `WashLightController` | 27 | ❌ |
|
||||
| `Gallop.Live` | `LightProjection` | 4 | ❌ |
|
||||
| `Gallop.RenderPipeline` | `CustomLensFlare` | 200 | ❌ |
|
||||
| `Gallop.RenderPipeline` | `MirrorBallProjector` | 4 | ❌ |
|
||||
| `Gallop.RenderPipeline` | `CustomProjector` | 4 | ❌ |
|
||||
| `Gallop.Live` | `WashLightController` | 27 | ❌ 24 个字段全是具体数值 + 两张投影贴图(`_projectionTexture`/`_cameraProjectionTexture`),缺的是 URP 下的投影实现 |
|
||||
| `Gallop.Live` | `LightProjection` | 4 | ❌ 只有 `_projectionType`(1) |
|
||||
| `Gallop.RenderPipeline` | `CustomLensFlare` | 200 | ❌ **数据最完整、最值得做的一个**,见下 |
|
||||
| `Gallop.RenderPipeline` | `MirrorBallProjector` | 4 | ❌ 字段已 dump 但**运行时绑定不可见**,见 Blocked |
|
||||
| `Gallop.RenderPipeline` | `CustomProjector` | 4 | ❌ 就是一套 legacy `Projector` 参数(near .1 / far 60 / fov 30 / aspect 1 + `Material`)|
|
||||
| `Gallop` | `MirrorReflection` | 1 | ✅ 已建并实现(平面镜反射,见下)|
|
||||
| `Gallop.Live.ShaderParam` | `ShaderParamController` | 1 | ❌ |
|
||||
| `Gallop.Live.ShaderParam` | `ShaderParamController` | 1 | ⚠ **不值得做**:实测只有 `_AmbientColor`/`_CharaColor` 两个向量,值都是 (1,1,1,1),实现出来是空操作 |
|
||||
|
||||
**LensFlare 这条线数据是齐的**(这也是目前性价比最高的一块):
|
||||
|
||||
- `CustomLensFlare` 字段:`Flare`(PPtr) / `Brightness` / `FadeSpeed` / `Color` / `IgnoreLayers` / `IsDirectional`。
|
||||
- `Flare` 指向的**不是** Unity 内置 `Flare` 资产,而是 `Gallop.RenderPipeline.LensFlareData`
|
||||
这个 ScriptableObject(同样在 umamusume 程序集里,照样可以按签名重建)。
|
||||
路径形如 `sourceresources/3d/env/live/common/lensflare/flare013/flares/flare013_00`。
|
||||
- 它的字段是 Unity legacy Flare 的逐字翻版:
|
||||
`TextureLayout` / `Texture` / `ElementArray[{ImageIndex, Position, Size, Color, UseLightColor,
|
||||
Rotate, Zoom, Fade}]` / `UseFog`。**所以语义不受 IL2CPP 阻塞** —— 这些是 Unity 自己的概念。
|
||||
- live10149 上 199 个物件同时挂 `CustomLensFlare` + `UnityLensFlareController` + MeshRenderer,
|
||||
另有 5 个只挂 `UnityLensFlareController`。舞台上**没有任何 legacy `LensFlare` 组件**,
|
||||
原版是自己画的。URP 侧对应物是 `LensFlareComponentSRP` + `LensFlareDataSRP`。
|
||||
|
||||
字段名必须和 TypeTree 逐字一致(大小写敏感),dump 一下即可。
|
||||
这条同样适用于任何其它 bundle 里的 MonoBehaviour。
|
||||
@@ -195,13 +210,35 @@ MonoBehaviour 实例脚本为空。**但这些脚本是可以「接管」的**
|
||||
|
||||
因此以下**永远拿不到标准答案**,只能靠交叉验证或承认未知:
|
||||
|
||||
- **所有枚举的语义** —— `_rotationType`(0/2)、`LightBlendMode`、`CmnColorType0/1`、
|
||||
- **游戏自己定义的枚举语义** —— `_rotationType`(0/2)、`LightBlendMode`、`CmnColorType0/1`、
|
||||
BlinkLight 的 `pattern`、`ColorType` 等。字段值读得到,含义读不到。
|
||||
- **脚本的行为本身** —— 重建签名只能拿到**数据**,拿不到原方法体。
|
||||
例:`MirrorBallLoopRotationSpeed` 的值可读,但原版怎么用它不可读。
|
||||
⚠ 但**先分清是谁的枚举**:`LensFlareData.TextureLayout` 长得像这一类,其实是 Unity
|
||||
legacy `Flare` 资产的 `FlareTextureLayout`,语义在 Unity 侧公开,不受此限。
|
||||
- **对象之间的运行时绑定** —— 重建签名只能拿到**数据**,拿不到原方法体,所以「这个组件
|
||||
跑起来去找谁」是不可见的。实例:`MirrorBallProjector` 的 shader 需要
|
||||
`_MirrorBallPosWS`/`_MirrorBallScale`/`_MirrorBallRotateValue`,而组件里**没有任何指向
|
||||
灯球的引用字段**,4 个 projector 全在原点、共用同一个材质,灯球却散布在 6 个位置。
|
||||
绑定关系只存在于方法体里。
|
||||
- **速度/系数一类的常量** —— 如果原版在代码里对动画做了调速,那个倍率无从得知。
|
||||
(注意这条不要滥用:镜面球转速一度被记成此类,实测其实完全确定,见下。)
|
||||
- 未随包发布的 shader(PostFilm 的定义性 shader 就在 app 二进制里)。
|
||||
|
||||
**已被实测消解的「未知」(2026-08-07)**
|
||||
|
||||
「灯球转速」曾被列为拿不到的常量。实测结论是它根本不存在这个未知:
|
||||
|
||||
- live10149 的 4 个 `MirrorBallProjector` 实例**全部** `MirrorBallIsLoopRotation = 0`、
|
||||
`MirrorBallLoopRotationSpeed = 0`、`MirrorBallLoopRotationValue = 0` ——
|
||||
shader 自带的 loop-rotation 通路在这个舞台上是**关掉的**,不是转速来源。
|
||||
- 真正在转的是 clip `anm_env_live10149_blinklight_mirrorball_flarelight_loop_000`:
|
||||
6 条 quaternion 曲线(`mirrorball_a_000` + `b_000..004`),7 个关键帧,
|
||||
**恒定 −179.50°/s 绕 Y**(每个关键帧算出来都是这个数),2.0 s 一圈,wrapMode = Loop。
|
||||
末帧 −359° 而不是 −360°,是为了循环接缝不重复一帧。
|
||||
- 这条 clip 正好是 `StageAnimationPlayer` 已接管的单-clip 唯一解之一,
|
||||
所以**我们的构建里灯球转速本来就是对的**,不需要任何猜测常数。
|
||||
|
||||
教训:把「值是 0」当成「值未知」是两回事。dump 之前先看一眼开关字段。
|
||||
|
||||
### ⚠ 现象描述不是 ground truth
|
||||
|
||||
字段值、shader 属性表是硬数据;**「哪个物件看起来不对」不是** —— 文档里的现象描述往往
|
||||
|
||||
+10
-2
@@ -101,7 +101,15 @@ Toon shader 已移植,卡住的主要是全屏后处理和几个逆向未完
|
||||
| `Gallop.MirrorReflection` | ✅ 已建并实现。第二摄像机 + 反射矩阵 + 斜投影 → RT → `_ReflectionTex`。**顺带解决了长期的「舞台地板发白」** —— `mirror_a` 的 `_ReflectionTex` 从没被赋值,Unity 代入白贴图 × 默认 `_ReflectionRate = 1.0` |
|
||||
| `Gallop.Live.BillboardController` | ⚠️ 已建,字段可读(`[StageScripts]` 丢失数 892→728),但 `_rotationType` 枚举语义随 IL2CPP 元数据一起拿不到,行为未实现 |
|
||||
| `Gallop.Live.AnimationObjectController` | ⚠️ 未建;其最直接的后果(283 个 `Animation` 一个都不播)已由 `StageAnimationPlayer` 顶上:只接管单 clip 的唯一解情形,按 `currentLiveTime` 采样而不是 `Animation.Play()`,暂停/拖动进度条都跟随 |
|
||||
| 其余 7 个 | ❌ 未建,见 `CLAUDE.md` 清单 |
|
||||
| `Gallop.RenderPipeline.CustomLensFlare` (+`LensFlareData`) | ❌ 未建,但**数据齐全、语义不受 IL2CPP 阻塞**——`LensFlareData` 是 Unity legacy Flare 的逐字翻版,URP 侧有 `LensFlareComponentSRP` 对应。199+5 个物件,星芒在原版截图里很显眼。**下一个该做的就是它** |
|
||||
| `Gallop.RenderPipeline.MirrorBallProjector` | ❌ 字段已 dump,但 4 个 projector 全在原点、共用一个材质、没有任何指向灯球的引用字段——绑定关系只在方法体里。**卡住,不是没做** |
|
||||
| `Gallop.Live.ShaderParam.ShaderParamController` | ⚠️ 实测是空操作(两个向量都是 (1,1,1,1)),从待办里划掉 |
|
||||
| 其余 5 个 | ❌ 未建,见 `CLAUDE.md` 清单 |
|
||||
|
||||
> **镜面球转速不再是悬案。** live10149 的 4 个 `MirrorBallProjector` 全部
|
||||
> `MirrorBallIsLoopRotation = 0` / `LoopRotationSpeed = 0`,shader 的 loop-rotation 通路是
|
||||
> 关的;真正在转的是 clip(恒定 **−179.50°/s 绕 Y**,2.0 s 一圈,7 帧算出来都是这个数),
|
||||
> 而这条 clip `StageAnimationPlayer` 已经在按 `currentLiveTime` 播了 —— 转速本来就是对的。
|
||||
|
||||
### 内部系统
|
||||
| 轨道 | 状态 |
|
||||
@@ -120,7 +128,7 @@ Toon shader 已移植,卡住的主要是全屏后处理和几个逆向未完
|
||||
| PostFilm (39) / RadialBlur (15) / TiltShift (63) / SunShafts (37) | URP 无对应,需自写 ScriptableRendererFeature + shader → 见 `live-shader-todo.md` |
|
||||
| LightProjection (74) | `Projector` 组件在 URP 不工作,需 DecalProjector 或自定义(36/58 首)|
|
||||
| Environment (58) | 轨道本身仍未接。但 Planar Reflection **已经不是从零** —— `Gallop.MirrorReflection` 已实现整条第二摄像机→RT→镜面 shader 的路径,轨道要做的是把 `mirrorReflectionRate` 这类关键帧接到它上面(48/58 首)|
|
||||
| LensFlare (57) | 舞台用 `CustomLensFlare`(`Gallop.RenderPipeline`,200 实例)。~~UmaBuild 无源码~~ —— **这句是错的**:按签名建类就能拿到它的序列化字段(见上一节),拿不到的只有方法体。可先做 SetActive(45/58 首)|
|
||||
| LensFlare (57) | ~~UmaBuild 无源码~~ **这句是错的,而且这条已经不缺零件了**:`CustomLensFlare` 的 `Flare` 指向 `Gallop.RenderPipeline.LensFlareData`(同程序集的 ScriptableObject,可按签名重建),字段是 Unity legacy Flare 的逐字翻版(`ElementArray[{ImageIndex, Position, Size, Color, UseLightColor, Rotate, Zoom, Fade}]`),URP 有 `LensFlareComponentSRP`/`LensFlareDataSRP` 对应。剩下的是**翻译工作**,不是逆向工作(45/58 首)|
|
||||
|
||||
### 没 dump 找明白(不知道打哪里)
|
||||
|
||||
|
||||
+8
-1
@@ -251,7 +251,14 @@ FacialToon(47, **6341 keys/59首**) > MonitorControl(10, 3911/55首,dispID 语
|
||||
|
||||
### 第四优先:要从零搭渲染系统 ★★★
|
||||
|
||||
LightProjection(74, 3793/37首,URP 下 Projector 不工作) > Environment(58, 1375/49首,注意还有独立的 `MirrorReflectionDataList`;**Planar Reflection 本身已不用从零搭** —— `Gallop.MirrorReflection` 已实现,缺的是把轨道关键帧接上去) > LensFlare(57, 993/45首,可先做 SetActive 层;`CustomLensFlare` 的字段可按签名重建拿到)
|
||||
**LensFlare(57, 993/45首) 应当从这一档移到第一档** —— 2026-08-07 dump 确认它不需要「从零搭」:`CustomLensFlare` 的 `Flare` 指向 `Gallop.RenderPipeline.LensFlareData`(可按签名重建的 ScriptableObject),字段是 Unity legacy Flare 的逐字翻版,URP 侧有 `LensFlareComponentSRP` 现成对应。
|
||||
|
||||
LightProjection(74, 3793/37首,URP 下 Projector 不工作) > Environment(58, 1375/49首,注意还有独立的 `MirrorReflectionDataList`;**Planar Reflection 本身已不用从零搭** —— `Gallop.MirrorReflection` 已实现,缺的是把轨道关键帧接上去)
|
||||
|
||||
> `MirrorBallProjector` 不在此列但值得记一笔:它是**卡住**而不是没做。shader 需要
|
||||
> `_MirrorBallPosWS`/`_MirrorBallScale`/`_MirrorBallRotateValue`,而组件里没有任何指向灯球的
|
||||
> 引用字段,4 个 projector 全在原点且共用一个材质 —— 绑定关系只存在于拿不到的方法体里。
|
||||
> 顺带:灯球转速已不是未知(clip 恒定 −179.50°/s,见 `LIVE_DEV_MAP.md`)。
|
||||
|
||||
### 不该做
|
||||
|
||||
|
||||
Reference in New Issue
Block a user