02 · 预算优先:帧时间 / 内存 / 资产 / 人天
02 · 预算优先:帧时间 / 内存 / 资产 / 人天
没有预算的美术方案等于没有方案。 独立游戏的画面崩坏,90% 不是因为技术不行,而是因为没人提前写过那张表。
1. 帧预算表(先写这张,再谈画面)
以 60fps = 16.6ms 为例(30fps = 33.3ms,120fps = 8.3ms)。 必须留出 15% 余量,所以实际可用 ≈ 14.1ms。
标准分配模板(3D 中等规模场景)
| 模块 | 预算(ms) | 占比 | 超支时的第一刀 |
|---|---|---|---|
| CPU:游戏逻辑/AI | 2.0 | 12% | 分帧、LOD 降 AI 频率 |
| CPU:物理 | 1.0 | 6% | 减少动态刚体、降迭代次数 |
| CPU:动画/蒙皮 | 1.0 | 6% | 骨骼 LOD、动画 LOD、GPU skinning |
| CPU:渲染提交(Draw Call) | 2.5 | 15% | 合批、实例化、减材质种类 |
| GPU:阴影 | 1.5 | 9% | 降级联数/降分辨率/改烘焙 |
| GPU:不透明几何 | 3.0 | 18% | 减面、LOD、剔除 |
| GPU:透明/粒子 | 2.0 | 12% | 砍 overdraw,这是第一杀手 |
| GPU:后处理 | 1.5 | 9% | 降采样、合并 pass、砍特效 |
| GPU:UI | 0.5 | 3% | 少用全屏透明 UI |
| 余量 | 1.6 | 10% | — |
| 合计 | 16.6 | 100% |
2D 项目分配(更容易被忽略)
| 模块 | 预算(ms) |
|---|---|
| CPU:逻辑/碰撞 | 2.5 |
| CPU:动画/骨骼 | 1.5 |
| CPU:渲染提交 | 2.0 |
| GPU:不透明(精灵) | 1.5 |
| GPU:2D 光照/法线 | 2.0 |
| GPU:透明/粒子 | 3.0 |
| GPU:后处理 | 2.0 |
| 余量 | 2.1 |
2D 项目最容易死在透明 + 后处理上,因为 2D 的精灵大量重叠,overdraw 天然高。
2. 平台与最低机型定义(必须先定死)
| 档 | 代表机型 | 目标帧率 | 目标分辨率 | 备注 |
|---|---|---|---|---|
| Low(最低机型) | Steam Deck / GTX 1050 / 骁龙 6 系 / iPhone 8 | 30fps 稳定 | 1280×720 | 这是"能不能卖"的底线 |
| Mid(主力机型) | GTX 1060 / 骁龙 8 Gen1 / iPhone 12 | 60fps | 1920×1080 | 这是"评测跑分"的机型 |
| High | RTX 3060+ / M1+ | 60~120fps | 2560×1440 | 截图机型 |
| Ultra | RTX 4070+ | 120fps+ | 4K | 只服务 5% 玩家,不为它做内容决策 |
铁律:按 Low 档设计,按 Mid 档验收,High 档只做加分项。 任何只有 High 档才能跑的效果,必须有 Low 档降级方案,否则不立项。
3. 内存预算表
| 类别 | Low 档(2GB 可用) | Mid 档(4GB) | High(8GB+) | 备注 |
|---|---|---|---|---|
| 纹理 | 500 MB | 1200 MB | 2500 MB | 通常占 50–60% |
| 网格 | 150 MB | 400 MB | 800 MB | |
| 动画 | 80 MB | 200 MB | 400 MB | 骨骼动画很吃内存 |
| 音频 | 100 MB | 250 MB | 500 MB | 常驻 + 流式 |
| Shader/程序 | 60 MB | 120 MB | 250 MB | 变体爆炸的重灾区 |
| 场景常驻 | 200 MB | 500 MB | 1000 MB | |
| 峰值余量 | ≥20% | ≥20% | ≥20% | |
| 合计 | ~1100 MB | ~2700 MB | ~5450 MB |
Shader 变体内存:一个变体平均 20–80KB。5000 个变体 = 100–400MB。这是独立游戏最常翻车且最难查的一项。
4. 纹理规格矩阵(最重要的一张表,写进校验器)
| 用途 | 尺寸 | 格式(PC) | 格式(移动) | sRGB | Mip | 通道打包 |
|---|---|---|---|---|---|---|
| 角色 Albedo | 1024(主角 2048) | BC7 | ASTC 6×6 | ✅ | ✅ | — |
| 角色 Normal | 1024 | BC5 | ASTC 6×6 | ❌ | ✅ | — |
| 角色 ORM | 1024 | BC7 | ASTC 6×6 | ❌ | ✅ | R=AO G=Rough B=Metal |
| 环境 Albedo(中景) | 1024 | BC7 | ASTC 6×6 | ✅ | ✅ | — |
| 环境 Albedo(远景/地表) | 512 | BC7 | ASTC 8×8 | ✅ | ✅ | 可三平面 |
| 道具/小物 | 512 | BC7 | ASTC 6×6 | ✅ | ✅ | 尽量进图集 |
| UI | 按需(≤2048) | BC7 / 未压缩 | ASTC 4×4 | ✅ | ❌ | 图集 |
| 特效 Flipbook | 512 |
BC7 | ASTC 6×6 | ✅ | ⚠️ | 单通道可 BC4 |
| 遮罩/Detail/Noise | 256~512 | BC4(R) / BC7 | ASTC 8×8 | ❌ | ✅ | 灰度存 R |
| LUT | 256×16 或 32³ | 未压缩/RGB | 未压缩 | ❌ | ❌ | — |
| 天空/HDRI | 2048 以下 | BC6H | ASTC HDR | ❌ | ❌ | HDR 才用 |
三条硬规则
- 任何纹理不允许是 2 的非幂次(NPOT)除非是 UI/图集;
- 任何超过 1024 的纹理必须有理由并写进规格表(默认 1024 封顶);
- 同一材质的 Rough/AO/Metal 必须打包成一张 ORM,分开就是浪费带宽。
5. 资产预算表(几何)
| 资产类型 | 三角面上限(Low 档) | 材质槽 | 骨骼上限 | LOD 数 |
|---|---|---|---|---|
| 主角 | 15k~30k | 2(身体+配件) | 60~80 | 2 |
| 普通敌人 | 5k~10k | 1 | 40~60 | 2 |
| 小怪/群怪 | 1k~3k | 1 | 20~30 | 1(用 impostor) |
| Boss | 30k~60k | 2~3 | 80~120 | 2 |
| 环境大件(建筑/岩体) | 3k~8k | 1~2 | — | 2~3 |
| 环境小件(石头/桶) | 300~1.5k | 1 | — | 2 |
| 植被(近) | 500~2k | 1 | — | 2 |
| 植被(远) | 100~300 | 1 | — | billboard |
| 道具/武器 | 500~3k | 1~2 | — | 2 |
单场景建议上限(3D 中等规模):
- Draw Call:< 800(Low)/ 1500(Mid)
- 三角面(可见):< 500k(Low)/ 1.5M(Mid)
- 材质种类:< 40
- 动态光源:< 4(前向渲染)/ 8(延迟)
- 阴影投射光源:≤ 1
6. Overdraw 预算(独立游戏第一杀手)
Overdraw = 同一像素被绘制的次数。透明物体、粒子、全屏后处理是主要来源。
| 层级 | 允许叠加层数(全屏等效) | 说明 |
|---|---|---|
| 不透明(有深度预pass) | 1.0~1.2 | 基本无害 |
| 透明/粒子 | ≤ 2.5(Low)/ ≤ 4(Mid) | 超过立刻掉帧 |
| 全屏后处理 pass | ≤ 5(Low)/ ≤ 8(Mid) | 每个 pass 至少读写一次全屏 |
| UI 全屏透明层 | ≤ 2 | 很多 UI 死在这里 |
预算公式
透明开销 ≈ 屏幕像素 × 平均叠加层数 × 每像素采样数 × 带宽系数
1080p × 3 层 × 4 次采样 ≈ 25M 次纹理读取/帧 → 移动端直接跪
降 Overdraw 的六板斧(按性价比排序)
- 减少粒子数量,增大单粒子尺寸(同样视觉,1/3 的填充)
- 粒子贴图中挖空透明区域(不要画满透明)
- 关掉软粒子的深度采样(或降采样深度)
- 后处理降采样:Bloom/DOF/色差在 1/2 或 1/4 分辨率做
- 合并后处理 pass:一个 Uber Post 优于 5 个独立效果
- 用不透明 + Alpha Test 替代透明(植被、链条、网格常用)
7. Shader 变体预算
| 项 | 上限 |
|---|---|
| Shader 总数 | ≤ 30(含引擎自带) |
| 母材质实例数 | 不限制(实例不算变体) |
| 单个 Shader 变体数 | ≤ 200 |
| 项目总变体数 | ≤ 5000 |
| 首屏 Shader 编译时间 | ≤ 3s(否则必须有预热场景) |
| Shader 内存 | ≤ 120MB(Low) |
变体治理三件事(必须做):
- 剥离:Player Settings 里剥离不用的光照模式/雾模式/阴影变体
- 预热:首屏加载一个隐藏相机渲染所有材质,或使用 Shader Variant Collection(Unity)/ PSO 缓存(UE)
- 审计:每月跑一次变体统计工具,超预算立刻查是哪个 shader 用了太多 keyword
8. 人天预算(独立游戏最稀缺的资源)
| 工作 | 独立游戏建议人天 | 说明 |
|---|---|---|
| 母材质体系(3–5 个) | 3–5 天 | 一次投入,永久回报 |
| 导入预设 + 校验器 | 2–3 天 | |
| 招牌技术原型 | 3–5 天(含验证) | 原型不过就砍 |
| 招牌技术落地 | 5–15 天 | 视复杂度 |
| 单个通用工具 | 0.5–3 天 | 超过 3 天的工具要重新评估 |
| 画质档位系统 | 1–2 天 | |
| 宣发素材录制方案 | 1 天 | |
| 全流程性能优化 | 5–10 天(出货前) |
反例:花 3 周写一个"通用场景生成工具",结果只用 5 次 → 净亏。见 domains/06-tool-development.md 的 ROI 公式。
9. 预算的执行:把它变成机器能检查的东西
预算写在文档里 = 没有预算。必须变成下面三样之一:
- 导入预设:纹理导入即自动套用规格(尺寸/压缩/通道)
- 校验器:资产入库前检查命名、面数、材质槽、pivot、纹理尺寸,不通过不让提交
- CI 性能回归:每周构建自动跑一段标准场景录制,输出帧时间曲线,超阈值红灯
最低配置(1 人团队也必须有的三件事):
- 一个自动导入预设脚本(省 80% 手动设置)
- 一个资产校验器(命名 + 面数 + 纹理尺寸)
- 一个性能快照脚本(一键输出当前场景 DrawCall/面数/透明层/内存)
10. 一句话总结
帧预算是合同,不是参考值。 谁超了谁负责砍自己的部分,而不是让 TA 一个人当恶人。 先写表,再开工;先量,再改;先真机,再结论。