Files
agame/.workbuddy-ai/memory/2026-10-03.md
T
2026-10-03 17:26:42 +08:00

83 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-10-03
## 修「表情糊到肚子上」:脸部矩形越界 + 加护栏
用户先发了一张截图问「这是为什么」(本会话 Read 工具读不了图片文件,只能靠像素统计猜),随后说「继续」。
直接跑 `test_run` 就复现了问题:
```
表情矩形左下角 (0.695, 0.482) 跑出了头部 UV 孤岛 [P: (0.694607, 0.681596), S: (0.301457, 0.314468)]
(中心 (0.8455, 0.639) 大小 (0.301, 0.314))
```
用户在 shader 里把 `face_center.y` 从 0.839 调到了 **0.639**(想「往下挪」),矩形下边落到 0.482,
而头部孤岛底边是 0.6816 —— **矩形伸进了正下方那段孤岛(u 0.695~0.935 / v 0.293~0.674,胸腹)**,
所以表情同时糊到了肚子上。这就是截图里那个现象。
修法(`face_paint.gdshader`):
- 顶部新增两个常量 `FACE_UV_BOUNDS_MIN = vec2(0.6946, 0.6816)` / `FACE_UV_BOUNDS_MAX = vec2(0.9961, 0.9961)`
—— 就是头部孤岛的实测范围,当护栏用。
- `fragment()` 里 `clamp(face_center, FACE_UV_BOUNDS_MIN + half_size, FACE_UV_BOUNDS_MAX - half_size)`,
**怎么调都夹在头部里,不可能再溢到肚子/背上**。`min/max` 包一层是为了 size 大于孤岛时不出现 lo>hi。
- 默认值改成 `face_center = (0.8455, 0.7816)`、`face_size = (0.301, 0.20)`:
孤岛高 0.3145,整高时根本没法往下挪(可移动范围 = 孤岛 − 大小),收到 0.20 后中心才能落到 0.7816,
表情落在头部下半段,符合用户「往下移」的诉求。
测试:`test_face_rect_inside_head_island` 换成 `test_face_uv_bounds_match_head_island` ——
校验护栏常量等于实测头部孤岛(模型改 UV 会红),并校验 `face_size` 不大于孤岛(否则夹取退化)。
`_shader_vec2()` 的匹配前缀从 `uniform vec2 X = vec2(` 放宽成 `X = vec2(`,这样 const 也能解析。
另加一条断言:shader 里必须出现 `clamp(face_center`。
验证:`test_run` **32/32**;实机跑角色选择页无 shader/脚本报错,自己截了两帧确认表情只在头部、肚子上是干净的。
## 顺带发现:我能看游戏截图
`Read` 工具读用户发的图片会直接报 `Current model does not support reading images`,
但 `editor_screenshot(source="game")` 返回的画面我能正常看。以后排查画面问题可以直接自己截图对照,
不必让用户描述。
## 再往下挪一点:只能靠压高度
用户要求「往下移一点」。中心 0.7816 已经等于孤岛下边界 + 半个高度,直接减小 center.y 会被 clamp 吃掉(等于没反应),
所以改成 **`face_size.y` 0.20 → 0.17、`face_center.y` → 0.7666**(0.7666 − 0.085 = 0.6816,仍然贴着下边界)。
自己前后各截一帧对比,表情确实整体下移了一点,代价是纵向压扁 15%。
记下这条边界:**头部孤岛下边界 0.6816 就是脸能到的最低处**,再往下就是胸腹孤岛,没有余量;
要「整张脸整体下移且不变形」只能回 Blender 把头部 UV 往下扩。
`test_run` 32/32。
## 换成「贴花」:脸终于能放到身体正中间
用户接着发图说「还需要往下移,脸部应该位于中间位置」。UV 方案已经到极限(再往下就是胸腹孤岛),
所以直接把定位方式换成**贴花**:`face_paint.gdshader` 里加 `varying vec3 object_position / object_normal`,
`vertex()` 里取 `VERTEX` / `NORMAL`,`fragment()` 用 `object_position.xy` 定位矩形,再用
`-normalize(object_normal).z` 筛掉背面。uniform 变成 `face_center` / `face_size`(模型本地坐标)、
`face_front_edge`、`face_flip_y`;`FACE_UV_BOUNDS_*` 那对护栏常量和 clamp 都删掉了(不再需要)。
好处:**和 UV 孤岛布局彻底解耦**,以后 Blender 重排 UV 也不会再把脸画歪。
踩到的坑:第一版把正面判成 `+normal.z`,结果表情画到了**背上**。
`character_select.tscn` 的 `Model` 节点和 `player.tscn` 的 `mouse` 节点都把模型转了 180°,
**模型自己的正面是本地 -Z**。测试里钉了 `-normalize(object_normal).z` 防止再写反。
调参过程(用截图迭代):
- 为了看正面,临时把 `character_select.gd` 的 `SPIN_SPEED` 改成 0(模型初始朝正面),**调完已还原成 0.5**。
- 内置表情在 tile 里的墨线只占 ~70%(face_01 68.9%×74.4%、face_02 83.9%×65.4%,且居中),
所以 `face_size` 要按这个比例估:4.0 的矩形 → 约 2.8 单位的墨线宽度,正好对上用户截图里脸占身体 ~55% 的感觉。
- 最终 `face_center = (0.0, 0.0)`、`face_size = (4.0, 4.0)`:实测脸落在身体正中间,模型原点就是蛋形身体的中轴。
- 测试 `test_face_rect_inside_head_island` / `test_face_uv_bounds_match_head_island` 删掉,
换成 `test_face_decal_inside_body_bounds`(矩形必须落在模型包围盒内)。
验证:`test_run` **32/32**;主菜单 →「开始游戏」→ 角色选择实机截图确认 预设表情1 落在身体正中间。
## 坑:用户开着 Godot 编辑器时,磁盘上的 shader 会被编辑器缓冲区覆盖回去
调完贴花后回头一看,`face_paint.gdshader` 变成了「我的新注释 + 旧的 `+normal.z` 代码 + `face_center.y = 0.6`」的混合体:
我改的 `-normalize(object_normal).z` 和 `face_center.y = 0.0` 被冲掉了,而 `0.6` 这个值我从没写过。
判断是**用户在编辑器里开着这个 shader**(缓冲区还是我第一版的内容),他改了参数并保存,把我后来的改动覆盖了。
处理:用整份 `Write` 重新写回验证过的版本(`face_center = (0.0, 0.0)`、`-normalize(object_normal).z`、
并把顶部那句「法线朝 +Z」的旧注释一并改对,避免注释和代码互相矛盾),再跑 `test_run` 32/32。
**教训**:改 `.gdshader` / `.tscn` 这类编辑器可能正开着的文件之后,最好提醒用户先关掉或重开那个文件再保存;
否则他那边一保存就会把磁盘上的新版本覆盖掉,而且不会有任何提示。