广州街区卡通材质接入(2026-10-14)
本轮把街景样板的三段明暗规则接入实际广州自由骑行。骑手服装与电驴、普通建筑及店铺的哑光表面、行道树和现有实例化车流使用同一组明暗级别;透明玻璃、金属、低粗糙度表面、带发光贴图的招牌以及自定义幕墙/地面/水面 shader 保留各自的材质与采样职责。图形风格改动不修改道路、碰撞、驾驶、物理步长、几何、实例批次、实际缓冲、阴影或水面刷新规则。
材质与资源边界
共享控制器在场景创建和换装等明确的边界注册网格,不逐帧遍历城市。原材质所有者继续驱动颜色、纹理、透明度和发光强度,转换材质读取同一份值,保留步行克隆与原骑手的外观同步。原材质发出 shader 失效后,转换材质也失效,覆盖货箱贴图从无到有等情况;按需加载的头盔和装备完成后再次注册。
行道树沿用原来的几何和顶点配色,只统一其已有卡通材质的 gradient ramp。车流中原本共享一个材质的实例批次继续共享,不为不同零件额外拆批。打印招牌和独立的玻璃/金属材质不被转换;原实例批次里没有独立材质的玻璃色块仍沿用原有批次结构。
清理时先恢复借用的原材质和树木 ramp,再让各工厂释放自己的资源。装备原材质销毁时同步释放对应转换材质,避免反复换装保留旧资源。新增贴图是程序生成的 3 × 1 ramp,没有新增媒体文件、下载或 COS 对象。
原有 HDR 色块归并与颜色反差墨线继续使用同一条呈现路径;本轮没有新增后处理 pass。以上资源与结构约束不代表新增材质零成本,成本需看正式对照和单独 GPU 诊断。
验证
四项控制器回归覆盖:制服颜色/货箱纹理/发光强度的实时同步;玻璃、金属、招牌及自定义 shader 的排除;树木 ramp 借用与恢复、按需网格注册;装备资源释放。骑行路径回归还验证“导航 sweep 返回可通行,但骑行实体持续停在原地”时使用正常倒车输入脱困,不改写姿态。
真实 GPU E2E 覆盖 WebGL/WebGPU 的骑行、上下车、手机视口、WebGL 丢失/恢复,以及水面和唯品会/TCL 玻璃幕墙。实际画面已检查两种后端的 TIT 西门与步行骑手。
最终版本的相关单测 5 文件/23 项、真实 GPU E2E 6 项、全仓类型检查、Web 生产构建、原有体积预算、发布文件校验、资源策略与 diff 检查通过。首屏 JS 为 321.4 / 350 KiB、CSS 为 15.9 / 16 KiB,街区入口为 471.5 KiB / 1 MiB,总游戏资源为 19.63 / 20 MiB;发布产物校验 556 个文件,诊断样板没有进入发布包。没有提高预算。公开文档输入检查、类型检查与构建也通过;完整 release:check、正式桌面包装和全部 E2E 未在本轮运行。
测量结束后的源码与冻结最终快照逐文件一致,锁文件/媒体清单的 SHA-256 与初始记录一致,共享包源码无改动。白天原版/卡通版使用同一站位截图,WebGPU 黄昏/夜景及手机视口分别检查,未出现 shader 错误。截图只作为本地实机效果交付,不进入 Git 或性能样本。
整城骑行对照方法
完整应用源码分别冻结为接入前和接入后快照;锁文件、资源版本与共享包在两组之间保持相同。两组使用同一版基准工具、同一份驾驶输入规划与真实碰撞查询。复用 benchmark:camera 的路线模式:从 TIT 西侧出发,依次经过广州塔、客村、丽园与腾讯广州大厦,计划道路长度约 7.04 km。实际路程、路线进度、横纵跨度、终点距离和运行状态都必须满足完整到达条件。
pnpm benchmark:camera --platform=browser --backend=webgl --scenario=district --motion=route \
--route=canton-tower,kecun,liyuan,tencent --duration=600000 --rounds=1 --frame-rate=60 \
--baseline=/absolute/frozen-app --output=/tmp/gza-city-toon-run每个后端的原版与卡通版各三次独立进程,前后、后前、前后的顺序串行运行。完成路线后提前结束,最长 600 秒。固定 1440 × 900、1080p 设置、DPR 1、60 FPS 设置、晴天正午和原第三人称驾驶;不使用自适应分辨率抵偿成本。记录实际 HDR/MSAA/阴影、缓冲与后端,拒绝回退、尺寸变化、运行时错误和未完整到达的样本。
CPU 分别列出世界渲染提交的墙钟时间,以及动画回调入口到 HDR 呈现结束的墙钟时间;后者包含路线输入规划与碰撞查询,不是进程 CPU 利用率。帧间隔报告 P95、P99、长帧发生率与最低完整一秒帧数。ready 是开发页面从导航到正常 ready 状态的耗时,新进程不保证磁盘或驱动缓存完全冷。
预跑失败与修正
最初的 360 秒预跑在约 4.04 km 路线进度、丽园附近停止移动,未到达终点。该失败保留在 Git 外,不能算作整城验收。原自动驾驶只在导航查询找不到路径时倒车;真实骑行约束与导航 sweep 的差异可以使实体停住。基准驾驶器现在在连续两秒几乎不移动、低速且未到终点时使用三秒正常倒车,清除旧绕行目标再规划,仍保留游戏的碰撞、警察与拦停。
修正后,TIT—丽园—腾讯的 3.70 km 定向路线在约 189 秒完整到达,实际骑行 3.61 km。这个不同路线的预跑只用于验证工具,不混入上述完整路线正式对照。
原始数据、截图、冻结源码与失败日志留在 Git 外;公开文档只记录汇总和方法。
正式结果
环境为本机 Apple M1 Pro、Chromium 156.0.8078.4、ANGLE Metal。每个后端独立运行三组,全部十二次完成计划路线,实际骑行 6.921–6.968 km,横向跨度约 2.535 km、纵向跨度约 1.087 km,结束仍在第三人称电驴骑行。没有运行时/shader 错误或后端回退。每轮实际缓冲始终为 1440 × 900,HDR 半浮点目标、4× MSAA 和阴影一致;WebGL 另记录到 antialias 为 true,WebGPU 的这一独立布尔读数未提供。
下表除长帧合计/发生率及峰值外,均为各轮统计值的中位数;箭头表示接入前 → 接入后。两组同一路网计划,真实驾驶的绕行与脱困有少量差异,不声称逐 tick 姿态相同。
| 指标 | WebGL | WebGPU |
|---|---|---|
| 平均实际 FPS | 59.976 → 59.923 | 59.273 → 59.300 |
| 帧间隔 P95(ms) | 19.2 → 20.6 | 20.9 → 21.8 |
| 帧间隔 P99(ms) | 20.5 → 22.4 | 24.4 → 25.0 |
| 世界提交 CPU P50(ms) | 7.2 → 7.8 | 8.1 → 9.3 |
| 整回调 CPU P50(ms) | 8.5 → 9.1 | 9.6 → 10.7 |
| 整回调 CPU P95(ms) | 9.8 → 10.9 | 11.9 → 13.2 |
| 导航到真实 ready(秒) | 8.685 → 8.601 | 10.374 → 10.135 |
| 超过 50 ms 合计 | 6 → 17 | 95 → 108 |
| 超过 50 ms 每分钟 | 0.30 → 0.86 | 4.76 → 5.50 |
| 十二轮中同版最低完整一秒帧数 | 53 → 50 | 19 → 28 |
| 绘制峰值 | 309 → 309 | 309 → 309 |
| 三角形峰值 | 118,628 → 118,626 | 119,191 → 118,353 |
| 超过 60 FPS 的 16.667 ms 预算比例中位数 | 52.0% → 51.2% | 50.5% → 50.0% |
卡通版在本组中位数上有约 0.6/1.1 ms 的回调 CPU 增量,尾帧及长帧发生率也略升;平均帧率受 60 FPS 上限约束,不能据此称整城更快或有足够余量。第三对两种后端的 CPU 均比对应基线低,说明单轮时序和环境波动仍存在,不把中位数增量解释为每一帧固定的材质开销。ready 的差值小于轮间波动,没有证明启动提速。
前后两版都没有达到全程完整一秒至少 60 帧。 本轮完成了画面接入和整条路线的前后测量,没有将其写成严格稳 60 验收通过。上述帧预算比例按原始间隔 > 1000 / 60 计算,含限帧边界附近的抖动;它不能单独表示肉眼卡顿率。绘制/三角形峰值超过旧局部场景的 <300 / <90,000 目标;该目标有指定计量场景,本轮没有放宽它,也没有宣布整个城市预算合格。
各轮数据如下。CPU 列是整回调 P50,长帧是超过 50 ms 的次数;索引按同版独立进程次数排列,实际运行顺序仍为前后、后前、前后。
| 后端/版本/轮次 | FPS | P95 / P99(ms) | CPU(ms) | 长帧 | 最低一秒 | ready(秒) | 采样(秒) | 实际骑行(m) | 脱困 |
|---|---|---|---|---|---|---|---|---|---|
| WebGL 前 1 | 59.962 | 19.2 / 20.4 | 8.4 | 3 | 55 | 8.727 | 407.209 | 6934.5 | 1 |
| WebGL 后 1 | 59.953 | 19.8 / 21.3 | 9.1 | 4 | 54 | 8.489 | 387.885 | 6921.3 | 1 |
| WebGL 前 2 | 59.979 | 19.2 / 20.5 | 8.5 | 1 | 54 | 8.515 | 412.509 | 6967.8 | 3 |
| WebGL 后 2 | 59.923 | 21.0 / 23.0 | 9.7 | 5 | 52 | 9.022 | 387.798 | 6921.5 | 1 |
| WebGL 前 3 | 59.976 | 20.5 / 22.0 | 9.2 | 2 | 53 | 8.685 | 388.391 | 6921.7 | 1 |
| WebGL 后 3 | 59.905 | 20.6 / 22.4 | 8.9 | 8 | 50 | 8.601 | 412.522 | 6967.8 | 3 |
| WebGPU 前 1 | 59.273 | 19.8 / 21.8 | 9.1 | 28 | 23 | 10.374 | 390.210 | 6921.8 | 1 |
| WebGPU 后 1 | 59.327 | 21.8 / 25.0 | 10.9 | 32 | 40 | 9.797 | 389.538 | 6921.8 | 1 |
| WebGPU 前 2 | 59.307 | 20.9 / 24.4 | 9.6 | 30 | 19 | 9.894 | 416.513 | 6966.0 | 3 |
| WebGPU 后 2 | 59.213 | 22.0 / 25.5 | 10.7 | 38 | 28 | 11.375 | 399.054 | 6931.2 | 1 |
| WebGPU 前 3 | 59.114 | 22.4 / 25.7 | 10.8 | 37 | 20 | 11.503 | 390.417 | 6921.7 | 1 |
| WebGPU 后 3 | 59.300 | 20.7 / 23.5 | 9.5 | 38 | 37 | 10.135 | 389.205 | 6921.7 | 1 |
P99 范围:WebGL 前 20.4–22.0 ms、后 21.3–23.0 ms;WebGPU 前 21.8–25.7 ms、后 23.5–25.5 ms。回调 CPU P50 范围分别为 8.4–9.2/8.9–9.7 ms 和 9.1–10.8/9.5–10.9 ms。末尾 JS 堆单点(MiB)为 WebGL 前 1943.2 / 1227.9 / 1163.2、后 1260.0 / 1387.9 / 1262.6;WebGPU 前 2104.1 / 1597.8 / 1767.0、后 1767.6 / 1288.8 / 2027.6。单点受 GC 时机影响,不代表进程 RSS、GPU 显存、长期泄漏或可靠的材质内存增量。
这组只覆盖本机浏览器、晴天正午、单人自由骑行和所列跨片区路线。实体手机、Safari/Firefox、Windows、正式安装包、公网联机、全部道路与天气、破坏状态以及长时间内存稳定性未在本轮完成性能验收。Godot 原生实验使用不同负载、画质和计量口径,不能与本表直接比较。
单独 GPU 诊断
正式矩阵完成后,在 TIT 西侧固定骑手位置与朝向,另开四个独立进程,每版/后端采 120 帧。两种后端均有实际时间戳支持,120 / 120 帧有效,缓冲为 1440 × 900。该短窗口含 GPU 计时探针,不能混入全程验收,单次局部结果也不能推广为整城 GPU 收益。
| 后端与计量范围 | GPU P50 前 → 后(ms) | GPU P95 前 → 后(ms) |
|---|---|---|
| WebGL,整帧 timer query | 6.104 → 5.839 | 6.560 → 6.220 |
| WebGPU,属于本游戏帧的 render pass 时间之和 | 11.010 → 9.961 | 17.105 → 14.942 |
两种计量范围不同,不用此表判断哪个后端更快。WebGPU 固定视角前后都是 232 次绘制、76,701 个三角形、431 个几何,纹理读数为 70 → 71。这个视角的 GPU 时间下降与全程回调 CPU 中位数增加同时存在;本轮尚未对尾帧或提交成本进一步归因,不能把简单明暗 shader 等同于整机提速。
Three.js、Godot 与同构
本轮继续使用 Three.js,Web 与现有 Electron 桌面客户端共享同一套 TypeScript 场景、规则、UI、存档和资源流程。卡通渲染本身可以在两种引擎实现;平台、内容制作流程和已完成的集成决定这次选择。
Godot 是后续原生桌面内容制作的候选,适合需要编辑器场景制作、骨骼动画、原生打包和更复杂 3D 工作流时进一步验证。当前独立 Godot 实验已有原生城市与人群压力测试,但生产任务、账号、存档、全部武器和网络权威仍未证明等价,现有数据不能直接宣布全项目迁移收益。Godot 官方当前说明 Web 导出使用 Compatibility/WebGL 2,Forward+/Mobile 不支持 Web,尚无 WebGPU:Web 导出文档。
如果未来用 Godot 原生客户端配 Three.js 网页客户端,先共享地图、资源版本、任务定义、协议和存档 schema,并使用共同的玩法 fixture 验证一致性。TypeScript 代码不会自动成为 Godot 的同一份执行逻辑,需要明确的共享核心或移植适配;这会增加两套渲染和平台实现的维护成本。当前建议保持单一 Three.js 运行时,不在本轮同时扩建第二套生产玩法。