卡通街景样板(2026-10-14)
本样板以“真实城市结构、清晰色块、柔和环境光、夸张人物轮廓”为方向,在独立开发场景中验证统一材质。它保留现有积木骑手与 low-poly 树木造型,展示的是 GZA 自身的风格化广州;原神仅作为卡通渲染方向的参考。
样板包含四间原创街边小店:云记糖水、阿婆云吞、街角士多与电驴维修。青绿、砖红、奶油色墙面搭配条纹遮阳棚、窗框、空调、排水管、凳子、菜单牌和盆栽。黄袍骑手、电驴、四棵行道树、两辆轿车与两辆微面复用游戏的程序模型;车辆按固定时间轨迹双向行驶。店名与文字贴图在运行时绘制,没有新增外部媒体文件或网络资源。
预览与交互
在游戏源码仓库执行 pnpm dev,打开开发服务器的 /cartoon.html。支持:
- 原材质/卡通材质:只切换同一场景的表面着色;相机、几何、车辆位置与光照沿用同一份状态。原材质是这个新样板的原始材质对照,不是已经发布的完整广州城市基线,也不是写实美术成品。树木在原材质档本来就使用卡通材质。
- 白天/黄昏:成组切换天空、雾、太阳与填充光。两种材质在每个时段共用相同参数。
- 暂停/继续车流、拖动环绕、缩放、键盘操作与重置视角;减少动态效果偏好默认暂停车流,页面隐藏时停止动画。
- 追加
?backend=webgl或?backend=webgpu请求对应后端。实际后端显示在读数中,性能工具拒绝把回退后端当作指定后端。
页面与控制逻辑只从开发 HTML 入口加载,不进入 Web 或桌面发行入口。基础按钮、面板与通知复用共享 UI 组件及 --ui-* token;正式游戏的存档、玩法、物理、地图与默认画面设置没有切换到该样板。
材质及成本边界
角色服装、墙面、路面与车身的哑光表面使用共享三段明暗 ramp;不透明金属、低粗糙度玻璃、车灯与印刷招牌保留原材质。切换不修改原材质对象,不拆分合批,不增加模型或全屏描边 pass。这个样板没有接入完整城市的 HDR 色块归并与颜色反差墨线。
原材质与卡通材质都在显示 ready 前预热,避免第一次点击切换时才编译。即时对照会同时保留原材质及卡通材质副本,并增加一张 3 × 1 的共享 ramp;纹理像素数不能代表完整显存成本。GPU 管线、资源占用与首次预热仍需按真实设备测量。
性能方法
复用 pnpm benchmark:camera --scenario=cartoon,冻结新样板的完整应用源码后,分别对原材质与卡通材质运行同一条连续镜头轨迹;车辆位置由相同的时间函数决定。正式 A/B 串行运行,每个后端三次原材质与三次卡通材质,顺序为原、卡通、卡通、原、原、卡通;每次独立进程、--rounds=1、30 秒,正式采样前另做 1.5 秒预热轨迹。帧时间采样期间不开启 GPU profiler,诊断数据另列。
pnpm benchmark:camera --scenario=cartoon --backend=webgl --style=original --duration=30000 --rounds=1 --output=/tmp/gza-sample-original-1
pnpm benchmark:camera --scenario=cartoon --backend=webgl --style=toon --duration=30000 --rounds=1 --output=/tmp/gza-sample-toon-1
# 改为 --backend=webgpu 对照另一后端;每次输出使用独立目录。
# --baseline=/absolute/frozen-app 使用冻结目录中的 src,样板必须也包含在快照中。固定实际缓冲 1440 × 900、DPR 1、42° FOV、抗锯齿开启、2048² 阴影、ACES 曝光 1.05、白天。没有应用限帧,浏览器显示回调仍可能限制帧率。CPU 是动画回调入口到 renderer.render 返回的墙钟时间,包含样板动画与提交;不等于进程 CPU 使用率,也不等于 GPU 时间。ready 包含两种材质预热,属于开发样板加载,不能当作生产城市首次可玩时间。
原始数据、截图、失败 trace 与冻结源码保留在 Git 外。本页仅保存可公开的汇总与方法。
本机正式对照
设备:macOS / Apple M1 Pro,Chromium 156.0.8078.4,WebGL 使用 ANGLE Metal,WebGPU 使用 Apple / metal-3。每行取三次独立样本的统计值中位数;长帧为该行累计 90 秒内超过 50 ms 的次数。共采集 21,612 个帧间隔,未发现运行时错误。
| 后端/材质 | 平均 FPS | 帧间隔 P95 / P99(ms) | 回调 CPU P50 / P95(ms) | >50 ms | 两档材质完整 ready(s) |
|---|---|---|---|---|---|
| WebGL 原材质 | 60.00 | 16.8 / 16.8 | 1.1 / 1.3 | 0 | 0.721 |
| WebGL 卡通材质 | 60.00 | 16.7 / 16.8 | 1.2 / 1.6 | 0 | 0.887 |
| WebGPU 原材质 | 60.00 | 16.7 / 16.8 | 1.9 / 2.4 | 0 | 1.036 |
| WebGPU 卡通材质 | 60.00 | 16.7 / 16.8 | 1.9 / 2.4 | 0 | 1.160 |
全部正式样本最大帧间隔约 16.8 ms,超过 22 ms 与 50 ms 的帧均为 0。两档材质的峰值几何/绘制量一致:WebGL 286 次 / 48,718 三角形,WebGPU 287 次 / 48,719 三角形;计量包含阴影及后端输出工作,后端之间不逐项等同比较。
各轮 CPU P50 / P95 为:WebGL 原材质 1.2/1.5、1.1/1.3、1.1/1.3 ms,卡通 1.2/1.7、1.2/1.6、1.1/1.3 ms;WebGPU 原材质 1.8/2.3、1.9/2.5、1.9/2.4 ms,卡通 2.0/2.5、1.9/2.4、1.8/2.3 ms。WebGL 卡通组的中位 CPU 增加约 0.1 ms,P95 增加约 0.3 ms,第三组与原材质相同;WebGPU 两组统计中位数相同且波动区间重叠。不能把回调上限附近相同的 FPS 解释为零成本或性能提升。
完整 ready 的每轮范围是 WebGL 0.552–1.001 秒、WebGPU 1.003–1.214 秒;它们都包含原材质与卡通材质的预热,不是两种独立发行方案的冷启动成本。新浏览器进程不保证操作系统、Vite 与 GPU 驱动缓存完全冷,开发样板就绪也不代表弱网或生产城市加载。
单独的 GPU 诊断
正式样本结束后,为每种后端/材质另开独立进程,固定镜头与第 4 秒的车辆姿态,采集 120 帧。四组都提供了 120 个有效 GPU 时间,GPU 验证与 shader 没有报错。
| 后端/材质 | GPU P50 / P95 / P99(ms) | 计量 |
|---|---|---|
| WebGL 原材质 | 0.97 / 6.26 / 6.79 | frame timer query |
| WebGL 卡通材质 | 1.09 / 5.52 / 5.99 | frame timer query |
| WebGPU 原材质 | 1.70 / 5.64 / 8.72 | render-pass-sum |
| WebGPU 卡通材质 | 0.72 / 2.49 / 4.72 | render-pass-sum |
这些是单轮短时 profiler 诊断,计时钩子不混入上述 30 秒正式帧样本。尾部波动较大,没有执行重复并交替顺序的 GPU 诊断矩阵,不能用表中差值宣布卡通材质的 GPU 加速。两个后端的 GPU 计量边界不同,也不能直接相减或把 GPU 与 CPU 数字相加作为帧时间。
验证与未覆盖范围
真实 WebGL/WebGPU 检查覆盖:页面标题与内容、无 Vite 错误遮罩、控制台、材质切换后的几何/实际缓冲一致、时段切换、拖动镜头、键盘重置与 WebGL 上下文丢失/恢复。390 × 844 手机视口检查了骑手可见性、44 px 控件、暂停状态与无横向溢出。
初次交互检查发现镜头重置仍继承 OrbitControls 拖动惯性,修复后复测通过。初次 WebGPU 几何对照在同一动画帧内重复手动绘制,读到了复用阴影后的较低绘制数;截帧现在等待正常渲染循环更新阴影后再读取,正式性能采样使用正常循环,不混入这一失败诊断。
本轮不包含整城、真实实体手机、Windows/Linux、多人网络、物理与战斗、长时间温度与显存验收;固定视口并不代表实体手机性能。也未将样板风格推广到整个游戏。
全仓 pnpm typecheck、pnpm build、pnpm verify:performance、pnpm verify:release、pnpm assets:git-check 与 diff 格式检查通过;三项真实 GPU 样板 E2E 通过,可用 pnpm test:e2e:cartoon 复测。555 个 Web 发布文件通过验证,样板 HTML 与开发诊断未打包;首屏 JS 321.4 KiB / 350 KiB、CSS 15.9 KiB / 16 KiB,完整资源 19.63 MiB / 20 MiB,预算未提高。未执行完整 release:check 或重新制作桌面安装包。
公开文档的 pnpm docs:check、pnpm docs:build 与资源 Git 检查也通过。