Appearance
水面关掉后不恢复
状态: 🟢 已修复
日期: 2026-07-12 严重程度: 🔴 P1(功能破坏,用户无法恢复水面反射) 影响范围: frontend/src/scene/env/env-water.ts + env-impl.ts(水面反射 + 地面反射) 发现方式: 代码审核 修复方案: disableGroundReflection 加 _restoreWaterReflection()(ADR-092 统一反射机制)
问题描述
打开地面反射时,buildGroundReflection 调用了 disableWaterReflection()——销毁水面的 RenderTargetTexture,把水面反射混合系数设为 0。
但关闭地面反射时,disableGroundReflection 没有任何恢复逻辑。
水面永久死了。重启也不恢复——因为 RenderTargetTexture 已经被销毁了,没有被重建。
根因分析
这是一个单向门。disableWaterReflection() 是消费型操作——调用一次,水面反射就没了。但没有人调用对应的"恢复"操作。
两套反射机制互斥的设计意图是:同时开启地面反射和水面反射会消耗过多 GPU 资源。但"关闭地面反射时不恢复水面"是 bug——互斥应该是"切换",不是"永久关闭"。
为什么没有暴露
groundType: 'flat' 是默认值。大多数用户从开始就没开过地面反射。所以这个 bug 只在"先开地面反射,再关地面反射"的路径上触发——这条路径被很多人走,但水面反射是否恢复,需要用户主动去看。
很多人看不到水面反射恢复了没有——因为水面反射关了,地面反射关了,两个都关了,看起来跟"没动过"一样。
修复方案
disableGroundReflection 加一句 _restoreWaterReflection()。单向门变成了双向门。
ADR-092 进一步统一了两套反射机制:水面和地面共用 PlanarReflectionEngine,RenderTargetTexture 加镜像相机。互斥逻辑删了——水面和地面可以同时有反射。
教训
- "开关"操作必须有对应的"恢复"操作 — 消费型操作(销毁、覆盖)如果不可逆,就是破坏性操作
- 两个都关看起来跟没动过一样 — 用户的"没注意"是最容易隐藏的 bug