# 地图光影优化验收 2026-11-12,香港时间。工作区 `D:/vibeCoding/unityRouge/workTree/tree3`,分支 `codex/map-improvement`,Unity `6000.6.8f1`。实施依据为 [地图光影优化计划](../../Production/LightingOptimizationPlan.md)。 当前状态:实现、独立动态阴影验证、功能回归及三个候选画质的无限帧性能采样通过。60 FPS 限帧实测平均 60.01 FPS,P95 帧间隔 17.23–17.28 ms,未通过严格的 16.7 ms 判据;原始失败标记保留。最终结论只采用本页指定的完整数据集。 ## 实现与运行产物 Windows x64 完整目录为 `Builds/Windows/x64/Lighting/`,入口 `Ironspore.exe`。通过 Unity MCP 构建,Mono、Development、DX12,最终构建报告为 **0 错误、0 警告**,见 [WindowsBuild.json](Logs/WindowsBuild.json)。运行时保留完整目录及 `Ironspore_Data`、`UnityPlayer.dll` 等依赖。 - Built-in 渲染管线采用 Linear 色彩空间与线性灯光强度;Standard 材质按涂装、混凝土和裸金属分别校准。 - 太阳光、导航工作灯、撤离坪工作灯及机库工作灯采用实际 Light 和几何遮挡;中等档启用太阳软阴影和最多一个局部投影 Spot Light。 - 第一人称保留机体对象,通过 Renderer 的 `ShadowsOnly` 隐藏表面并持续投影;驾驶舱、文字、弹道和细小标记分别配置投影职责。非发光地面接缝继续接收真实阴影。 - 实景反射探针在运行时环境生成完成后捕获,排除机甲、敌人、移动道具及标记;灯光选择变化时限频更新,最短更新间隔 8 秒,并分帧处理。 - 游戏相机明确标记为 MainCamera;DynamicProps 渲染分层同时保留原有射线阻挡语义,物理查询验证见下表。 - 正常启动默认中等画质、1920×1080 和 60 FPS 上限。QA 模式由显式命令行参数启用,不出现在游戏界面。 主要入口为 `WorldLightingProfile`、`WorldLighting`、`WorldFactory`、`WarzoneDirector` 和 `MechPilot`。场景共享 `Assets/Game/Data/Lighting/Daylight.asset`;资产及原有 GUID 保留。原型场景生成命令未执行。 ## 本机与测试隔离 | 项目 | 实际配置 | | --- | --- | | CPU | AMD Ryzen 9 5900HX,8 核 16 线程 | | GPU | NVIDIA GeForce RTX 3070 Laptop GPU,物理显存 8192 MiB;实际 Player 回读该 GPU | | 系统内存 | Windows 识别约 31.42 GiB | | 驱动 / API | NVIDIA 581.80 / Direct3D12 | | 供电与电源模式 | 接电、100% 电量,Windows 平衡模式;未改动系统电源配置 | | 游戏渲染 | 1920×1080,宽高渲染比例均为 1,动态分辨率关闭 | | 中等档 | 太阳 2048 级阴影图、60 米距离、2 级联、软阴影,局部 Spot 阴影图 1024,2× MSAA | | 测试数据 | ProductName 为 `IRONSPORE Lighting tree3`,使用独立 persistentDataPath 与 PlayerPrefs 命名空间 | | 其他实例 | [采样前快照](TestResults/EditorsBeforePerformance.json)确认两个编辑器均不在 Play;启动器每 2 秒检查其他 Ironspore 程序,发现竞争程序则停止本次验证 | 采样启动时硬件、电源配置、Runtime DLL 与光照配置 SHA-256 记录在 [environment.json](TestResults/PerformanceFinal/environment.json)。测试存档沿用原有版本 1 和结算编号;主工程、其他分支的存档及偏好未迁移。 ## 真实动态阴影证据 最终独立程序的 [report.json](TestResults/PerformanceFinal/report.json)记录: | 检查 | 实际结果 | | --- | --- | | 第一人称仍持续投影 | 26 个激活机体 Renderer 使用 ShadowsOnly | | 固定观察相机下移动机甲 2 米 | 95,868 个像素出现显著变化;观察相机排除文字与弹道,只比较场景几何 | | 太阳阴影关闭 / 开启 | 63,956 个像素出现显著变化 | | 导航灯关闭 / 开启 | 86,347 个像素识别到实际照明增量 | | 在灯前加入遮挡体 | 83,231 个原受照像素的灯光增量降至原来的 45% 以下,灯本身开启真实阴影 | 比较使用 RGB 通道差值和固定相机;局部灯检查采用“开灯减关灯”的两组差分,分离遮挡体自身及太阳光的影响。临时观察相机和遮挡体只属于显式 QA 模式,测试结束即释放。 原始画面:[移动前](TestResults/PerformanceFinal/Screenshots/shadow-before-move.png)、[移动后](TestResults/PerformanceFinal/Screenshots/shadow-after-move.png)、[太阳阴影关闭](TestResults/PerformanceFinal/Screenshots/sun-shadows-disabled.png)、[太阳阴影开启](TestResults/PerformanceFinal/Screenshots/sun-shadows-enabled.png)、[局部灯开启](TestResults/PerformanceFinal/Screenshots/local-on.png)、[局部灯被遮挡](TestResults/PerformanceFinal/Screenshots/local-blocked-on.png)。另有真实 Player 的 [越肩](TestResults/PerformanceFinal/Screenshots/shoulder.png)、[第一人称](TestResults/PerformanceFinal/Screenshots/cockpit.png)和[机库](TestResults/PerformanceFinal/Screenshots/hangar.png)画面。 ## 性能方法与结果 采样以原生 1080p、中等画质、VSync 关闭、帧率上限关闭,验证超过 60 FPS 的持续渲染能力。正常游戏的默认上限仍为 60 FPS。先预热 60 秒,再分别以越肩和第一人称各采样 120 秒、重复 3 次。每个样本单独检查 P95 ≤ 16.7 ms,保留 P50/P99、平均 FPS、CPU/GPU 时间及内存。 使用实际首领战区、固定种子 1739、8 个真实运行 AI 的敌人,包含移动、跳跃、开火、弹道、运输机到达和灯光/反射更新。控制路线经过地图外围与中央通道,每个样本要求到达至少 4 个路点。为保持整个采样期间相同的战斗负载,QA 模式提高玩家和敌人的耐久;这不改变正常启动的玩法。完整通关节奏和平衡仍按制作计划另行验收。 帧耗时来自 Player 真实帧间隔;CPU/GPU 时间来自 FrameTimingManager。另以主相机 onPostRender 独立计数,要求实际渲染帧数至少达到采样帧数的 98%,并核对实际相机尺寸和渲染比例。相机截图及临时对照渲染发生在性能预热之前,保存 CSV 和截图的时间排除在采样区间之外。 **中等画质本机验收通过。** 6 组样本全部达到 P95 ≤ 16.7 ms;平均 299.41–329.08 FPS,P95 为 5.67–6.31 ms,P99 为 6.78–7.39 ms。每组 8 个敌人持续运行,实际主相机渲染计数均与采样帧数一致;每组移动约 420 米、到达 10–11 个路点。最终报告 completed、visualPassed 及各组 passed 均为 true,未检测到竞争测试程序。 | 样本(各 120 秒) | 平均 FPS | P50 ms | P95 ms | P99 ms | CPU P95 ms | GPU P95 ms | 实际渲染帧 / 采样帧 | | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 越肩 1 | 329.08 | 2.64 | 5.67 | 6.78 | 5.35 | 0.54 | 39,489 / 39,489 | | 第一人称 1 | 322.44 | 2.72 | 5.77 | 6.90 | 5.45 | 0.49 | 38,692 / 38,692 | | 越肩 2 | 299.41 | 2.91 | 6.31 | 7.39 | 5.97 | 0.54 | 35,928 / 35,928 | | 第一人称 2 | 313.97 | 2.73 | 5.97 | 7.09 | 5.65 | 0.50 | 37,676 / 37,676 | | 越肩 3 | 300.94 | 2.91 | 6.21 | 7.33 | 5.87 | 0.53 | 36,112 / 36,112 | | 第一人称 3 | 313.34 | 2.73 | 5.98 | 7.18 | 5.66 | 0.50 | 37,600 / 37,600 | Player 已分配内存为 156.79–157.28 MiB。CPU/GPU 时间分别按可用 FrameTimingManager 样本统计;GPU 每组有 30,444–35,044 条有效记录,未用缺失记录填充百分位。原始 CSV 同时保留主线程、渲染线程和 Present 等待时间,平均 FPS 按整段真实帧间隔计算。 原始数据、每组截图与运行日志均保存在 `TestResults/PerformanceFinal/`。基线可见程序记录在 [BaselineVisible](TestResults/BaselineVisible/report.json),其旧控制路线与最终路线不同,仅作历史参照,不用于声称精确 GPU 增量。`Baseline/` 是隐藏窗口的无效尝试,`Performance/` 是兼容修正前中断的采样;两者均标记排除,未参与最终结论。 ### 候选画质补测 三个候选档均在相同构建、原生 1080p、100% 渲染比例下独立运行。基础档与增强档各预热 60 秒、双视角各采样 60 秒一次;中等档采用上方完整 6×120 秒协议。增强档同时覆盖护送阶段,7 个敌人及护送对象持续运行,护送最终到达终点。三档全部完成动态阴影对照及真实相机渲染检查。 | 档位与代表场景 | 主光阴影配置 / 局部投影灯预算 | 越肩 P95 ms | 第一人称 P95 ms | GPU P95 ms(越肩 / 第一人称) | 结果 | | --- | --- | ---: | ---: | ---: | --- | | 基础 Low,首领战区 | 35 米、2 级联、1024、硬阴影 / 0 | 5.95 | 5.84 | 0.33 / 0.31 | 通过 | | 中等 Medium,首领战区 | 60 米、2 级联、2048、软阴影 / 1 | 5.67–6.31 | 5.77–5.98 | 0.53–0.54 / 0.49–0.50 | 通过 | | 增强 Very High,护送战区 | 100 米、4 级联、4096、软阴影 / 2 | 6.59 | 6.62 | 0.67 / 0.67 | 通过 | 补测数据:[Low](TestResults/QualityLow/report.json)、[Very High / 护送](TestResults/QualityHighEscort/report.json)。Low 的常规运行关闭额外局部灯,保留太阳及机甲真实投影;其局部灯对照仅在 QA 的临时固定镜头阶段强制启用,未带入性能采样。不同路线和采样长度不用于推算档位间的精确增量。 ### 默认 60 FPS 上限与诊断边界 以同一中等档构建另外执行 60 秒预热、两视角各 60 秒,开启 `Application.targetFrameRate = 60`、VSync 关闭。实际主相机各渲染 3,600 帧,两个样本平均均为 60.01 FPS。 | 限帧样本 | 平均 FPS | P50 ms | P95 ms | P99 ms | GPU P95 ms | Present 等待 P95 ms | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | 越肩 | 60.01 | 16.67 | 17.28 | 17.53 | 3.69 | 15.46 | | 第一人称 | 60.01 | 16.67 | 17.23 | 17.52 | 3.54 | 15.55 | [原始报告](TestResults/Capped60/report.json)的两段 `passed` 均为 false,启动脚本因 P95 超过 16.7 ms 返回失败;报告已完整完成、原生尺寸和动态阴影检查通过。这个结果不计入上方已通过的无限帧性能样本,也不修改阈值后重写为通过。Present 等待明显增加,与限帧后的等待相符;当前只能确认渲染性能有充足余量且限帧平均达到 60 FPS,不能宣称限帧后的 95% 帧均不超过 16.7 ms。 对全部 12 个采样 CSV 另行复算行数、实际时长、P95 和相机渲染帧数,均与报告一致;见 [数据核查](TestResults/FinalDataAudit.json)。中等档无限帧的主线程 P95 为 2.02–2.09 ms、渲染线程 P95 为 0.66–0.73 ms、Present 等待 P95 为 4.10–4.69 ms,各指标独立统计,不能把百分位直接相加。 另在性能采样结束后,通过 Unity MCP 对中等档首领战区抓取一个**编辑器诊断帧**:[计数](TestResults/EditorRenderCounters.json)为 471 Draw Calls、134 SetPass、94,992 三角形和 378 Shadow Casters 计数;[帧调试器](TestResults/EditorFrameDebugger.json)共 477 个事件,其中有 118 个方向光 RenderJobDir 和 2 个 RenderJobSpot 事件。这些包含编辑器渲染上下文,不等同于 Player 的单相机成本或唯一投影物体数量。当前 MCP 未回读到各事件的可靠 GPU 耗时,不将事件数替代阴影 Pass 时间。 ## 功能与生命周期回归 | 检查 | 实际结果与证据 | | --- | --- | | EditMode | 最终 19/19 通过,覆盖字形、双语参数、偏好和存档/回收去重、损坏恢复、写入失败。[结果](TestResults/EditMode.json) | | 键鼠驾驶 | Input System 回放验证移动约 19.56 米、推进耗能、射击及双视角;机体高度约 3.205 米。[结果](EditorPlayback/TestResults/KeyboardPlayback.json) | | 回收与撤离 | 搜索、受击中断、货舱入库、跨战区、机毁保留已寄收益、到达未自动入库、主动登机均通过。[结果](EditorPlayback/TestResults/RecoveryPlayback.json) | | 双语 UI | 44 步集成回归通过;覆盖 1080p、720p、1440p、2560×1080,语言菜单键鼠操作、已有通知/结算和世界标记刷新。[结果](Localization/TestResults/Integration.json) | | 三种底盘与循环 | 轻/中/重各执行战区、第一人称、回机库检查;每次均为一个 World、一个太阳、一个探针、一个相机,第一人称各有 26 个投影 Renderer。[结果](TestResults/WorldCycles.json) | | 内存观察 | 编辑器三轮循环的已分配内存约 607.66–608.45 MiB,未见本轮逐次增长;该短检查不作为长期泄漏分析。 | | 物理分层兼容 | 实际物理查询确认 0、10 层阻挡世界射线,8、9 层保持排除。[结果](TestResults/PhysicsLayers.json) | | 最终 Console / 场景保存 | 通过准确的 tree3 MCP 实例回读 0 错误、0 警告;Bootstrap 未修改、已保存,帧调试器关闭并退出 Play。[结果](Logs/FinalConsole.json) | 最后通过桌面工具普通启动完整产物,实际观察机库、试驾入口、阴影和鼠标视角响应。桌面工具注入的 V/Esc 没有触发 Unity 原生动作,因此这部分原生键盘检查未判通过;双视角切换及驾驶操作的结论采用上表 Input System 回放、生命周期检查及独立 QA 渲染。普通试驾程序已通过窗口关闭,未关闭其他分支程序。 五次最终 Player 日志未发现托管 Exception 或断言;均保留同一条 DX12 启动诊断 `failed to query info queue interface (0x80004002)`,图形设备、真实渲染及 FrameTimingManager 样本有效,详见数据核查中的日志匹配行。原始 `Player.log` 按仓库忽略规则仅在本地保留。 构建前发现旧字体资产会在构建时清空图集,已保留动态字形数据并预热 412 个所需字符;字形检查与实际中英画面均通过。各阶段结果放入光影 QA 目录,原有 Prototype/Localization 验收归档未被覆盖。 ## 范围与后续 本轮交付实时直接光、真实动态阴影、PBR 校准、实景环境反射及画质/生命周期控制。当前地图仍在运行时生成,S4 的静态烘焙前置条件尚未具备;间接光使用 Trilight 环境近似,固定环境落地后再安排 lightmaps 和 Light Probes。环境反射按事件更新,其内容不承担动态镜面反射验收。 本轮记录整帧 CPU/GPU 时间;独立程序 ShadowCaster Pass 的单独 GPU 时间、环境初次加载及探针首捕获峰值尚未形成独立记录,未由平均帧率反推,也未把历史不同路线的差值当作 3 ms 增量预算的独立验收。 复现入口为 `Tools/Unity/RunLightingValidation.ps1`;默认执行中等档、60 秒预热、两视角各 3×120 秒。可通过 Quality、RouteBranch、SampleSeconds、Repetitions 和 VisualOnly 参数选择检查;输出目录已有报告时拒绝覆盖。运行前通过 Unity MCP 核对目标工程、保存和构建,再关闭其他测试游戏。 从分支复现这组数据时,在专用测试工作区将 Player Settings 的 Product Name 设为 `IRONSPORE Lighting tree3`,再构建光影测试程序。该名称供 QA 入口检查,同时隔离存档和 PlayerPrefs。云端仓库保留游戏原有的产品名。