diff options
| -rw-r--r-- | docs/维护说明.md | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/docs/维护说明.md b/docs/维护说明.md index 6978a9a..4635b6d 100644 --- a/docs/维护说明.md +++ b/docs/维护说明.md @@ -1,6 +1,6 @@ # 维护说明 -结论先行:主分支保持 0 警告 0 错误 + Desktop 75/75、Kernel 79/79 全绿;性能基线 +结论先行:主分支保持 0 警告 0 错误 + Desktop 79/79、Kernel 79/79 全绿;性能基线 final_digest 固定 953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C。 本文记录模块职责、不变量与逐字可复制的验收命令。 @@ -45,10 +45,33 @@ final_digest 固定 953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F `avatarMoving`(比较前后位置);NPC 用 `npcSpriteSpecAtTarget`(目标向量 ≥0.5px 视为移动)。 - 世界图集 `Assets/jiangnan-world.png`:800×32,25 格。水面 3 帧在 slot 1/13/21, 炊烟 3 帧在 slot 22/23/24。 - - `waterFrameTick = (tick / 32) % 3` → Water / WaterSpriteB / WaterSpriteC; - - `smokeFrameTick = (tick / 40) % 3` → SmokeSpriteA/B/C,画在民居屋顶上方 `offsetTile pos -2 -3`。 + - `waterFrameTickAt tick x y = (tick / 32 + x + 2y) % 3` → Water / WaterSpriteB / WaterSpriteC。 + 相位按**世界 tile 坐标**偏移,所以同一帧里相邻河面砖显示不同相位;`waterFrameTick` 仍保留为 + 全局相位(旧断言)。 + - `smokeFrameTick = (tick / 40) % 3` → SmokeSpriteA/B/C。炊烟在 `drawWorld` 的**末尾单独一遍** + 绘制,位置 `offsetTile (house door) 0 -3`(屋脊正上方),保证画在屋瓦、竹子等所有 prop 之上。 - 以上帧选择只用 `tick` 与「是否移动」,无墙钟/`System.Random`;同 tick 必得同帧。 +## 预乘 alpha 与夜间光晕/炊烟接线(P14) + +- **机理**:MonoGame `SpriteBatch` 默认 `BlendState.AlphaBlend` 按**预乘**语义合成 + (source blend = `One`,destination = `InverseSourceAlpha`)。因此直传未预乘的 + `Color(r,g,b,a)` 会把 rgb 按原值直接加进帧缓冲:多层暖色叠加在核心区饱和成 + **不透明纯白方块**(P13 夜晚灯笼的 75×75 白块即由此而来;`Color(255,0,0,60)` 实测渲染为 + `(255,63,68)`)。光晕、色调等任何 alpha<255 的前景绘制都必须**按自身 alpha 预乘 rgb**。 +- **正确写法**:`VillageArt.premultiply r g b a`(每通道 `round(c * a / 255)`,四舍五入; + alpha=255 为恒等)。预乘后单通道 ≤ alpha,alpha<250 时不可能出现纯白。 +- **夜间光晕**:`VillageArt.lanternGlowLayers cx cy radius rings r g b peakAlpha` 用同心圆 + pixel run 近似径向衰减,每层色值预乘、核心多层叠加≈`peakAlpha`、边缘单层最暗; + `Game.fs` 只在 `renderPlan.Props` 的 `RiverLantern` 实体处绘制,无灯笼处不产生光斑。 +- **炊烟**:见上「动画语义」——烟雾是独立的后置绘制遍,与灯笼光晕同理。 +- **角色站位**:`characterDestination` 把精灵下移 `characterFeetOffset = tilePixels/2`(16px), + 使脚底贴合地砖底线;`drawGroundShadow` 用 `ellipseRuns` 画预乘半透明椭圆接触阴影。 +- **回归**:Desktop 单测 `PremultiplyScalesEachChannelByItsOwnAlpha`、 + `LanternGlowLayersArePremultipliedAndRadial`、`WaterRipplePhaseIsDistributedPerTile`、 + `CharacterFeetSitOnTheTileGroundLine`;图像级 `scripts/check-no-white-blocks.py` + 对夜晚录帧断言不存在 ≥64×64、每通道 ≥250、alpha ≥250 的方块(P13 旧帧 42/69 命中,修复后 0 命中)。 + ## 性能基线命令 ```bash @@ -97,6 +120,11 @@ timeout 45 xvfb-run -a -s "-screen 0 1280x720x24" env \ - `LV_RECORD_DIR` 默认 `/tmp/lv-p5-prompt`,`LV_RECORD_EVERY` 默认 25(每 N 次绘制存一帧)。 跑完 `sample result=ok`;连续移动帧(如 day-run 的 0136..0146)即走路逐帧采样。 +- 夜晚白块图像级回归(0 命中 = 通过;对 P13 旧帧应报 42/69 命中): + +```bash +python3 scripts/check-no-white-blocks.py evidence/night-run +``` ## 取证快照位置(近期) @@ -107,4 +135,7 @@ timeout 45 xvfb-run -a -s "-screen 0 1280x720x24" env \ - `/tmp/opencode/lv-p13/evidence/`(P13:`walk-idle-frames.png`、`water-3phase.png`、 `smoke-3phase.png`、`water-2frame.png`、`smoke-2frame.png`、`day-panorama.png`、 `night-lantern.png`、`day-night-compare.png`、`walk-real-run.png`、`day-run/`、`night-run/`) +- `/tmp/opencode/lv-p13-evidence/`(P14 修复后重录:`day-panorama.png`、`night-lantern.png`、 + `day-night-compare.png`、`chimney-closeup.png`、`night-lantern-closeup.png`、 + `white-block-check.txt`、`day-run/`、`night-run/`;同步一份到 `evidence/`) - `artifacts/perf-independent/<TS>/`(digest 3 联测回读) |
