移动端渲染
自动关联目录:移动端渲染
覆盖说明:官方 Mobile Development 大类的子条目无法静态抓取;本篇按引擎实际模块组织,涉及版本差异处标注"以目标版本为准"。移动端工具链部分见
Profile(UE性能优化工具.md中 GPU/内存/功耗各节)。
1. 定位
移动端的渲染瓶颈和桌面完全不一样:桌面通常卡在 GPU 算力或 draw call,移动端几乎总是卡在带宽与发热。
一句话定位:**移动端优化的第一原则是"少读、少写、少全屏",而不是"少算"。**在 tile-based GPU 上,一次全屏 pass 的代价远高于一次复杂的片元着色。
2. 结构:三层选择
1. 平台与图形 API Android / iOS → Vulkan / OpenGL ES / Metal
2. 渲染器路径 移动前向渲染(默认)
3. 特性开关 Mobile HDR、MSAA、后处理、阴影、反射方案特性可用性的硬边界(这是和桌面最大的差异):
| 特性 | 移动端 |
|---|---|
| Nanite | 不支持(需 DX12 + SM6;官方列的平台是主机与桌面) |
| Lumen | 面向次世代主机与高端桌面,移动端需替代方案 |
| 虚拟阴影贴图 | 平台列表不含移动端 |
| 替代方案 | 烘焙 GI + Reflection Capture + 传统阴影 |
3. 带宽为什么是第一瓶颈
移动 GPU 多为 Tile-Based 架构:渲染时先把 tile 加载进片上高速内存,算完再写回主存。任何需要"读回整张 RT"的操作都会打破这个优化:
| 高代价操作 | 为什么 |
|---|---|
| 全屏后处理 pass | 每个 pass 都是一次完整的读 + 写 |
| MSAA | 需要保留多样本,解析时额外带宽 |
读 SceneDepth / SceneColor | 强制 resolve |
| 大 RT 与高精度格式 | 直接乘进带宽 |
| 频繁切换 RT | tile 反复回写 |
因此移动端的优化顺序:
1. 砍全屏 pass 的数量(合并后处理)
2. 降渲染分辨率(r.MobileContentScaleFactor)
3. 用低精度格式(Mobile HDR 关掉 → LDR)
4. 最后才是简化材质指令4. 纹理与压缩
| 格式 | 平台 | 说明 |
|---|---|---|
| ASTC | Android(新)+ iOS | 质量与压缩率平衡最好,首选 |
| ETC2 | Android 兜底 | 兼容老设备 |
| PVRTC | 老 iOS | 需要 2 的幂尺寸 |
| BC / DXTC | 桌面 | 移动端不用 |
| 要点 | 说明 |
|---|---|
| 按平台分别设置压缩 | 纹理编辑器的平台覆盖 |
| 关闭不必要的 mip | 但必须保留 mip,否则远处采样抖动且带宽更高 |
| 纹理尺寸 | 移动端贴图尺寸应显著低于桌面 |
| 纹理采样器数量 | 移动端 sampler 上限更低 |
5. 参数与设置
| 设置 / CVar | 作用 | 代价 |
|---|---|---|
r.MobileContentScaleFactor | 渲染分辨率缩放 | 直接决定带宽,收益最大 |
| Mobile HDR | 是否用 HDR 渲染管线 | 开启成本高(高精度 RT + 带宽);关闭则 LDR,某些效果不支持 |
| Mobile MSAA | 抗锯齿 | 带宽代价大,通常改用 TSR/后处理方案 |
r.Mobile.AllowGPUScene | GPU Scene | — |
| Max Movable Point/Spot Lights | 动态光数量 | 前向渲染下每多一个光源就多一次光照计算 |
| Vertex Fogging for Opaque Only | 顶点雾 | 便宜,但精度低 |
| Use Full Precision in Pixel Shader | 片元精度 | 关掉用半精度更快,可能有精度问题 |
r.Mobile.EnableStaticAndCSMShadowReceivers | 阴影接收 | — |
| 反射方案 | Reflection Capture 为主 | SSR/Lumen 代价高 |
| Shader Permutation | 材质开关数量 | 移动端编译时间与包体更敏感(见 材质与着色器编译) |
具体开关名随版本变化,以目标版本的 Project Settings(Rendering / Mobile 分组)实际条目为准。
6. 代价与权衡
| 选择 | 收益 | 代价 | 什么时候不该用 |
|---|---|---|---|
| 降分辨率 | 收益最直接 | 糊 | 已降到可接受下限就只能砍 pass |
| 关 Mobile HDR | 明显省带宽与内存 | 失去 HDR 相关效果 | 需要强 HDR 表现时不能关 |
| 开 MSAA | 抗锯齿质量 | 带宽代价大 | 移动端一般不该开 |
| 烘焙 GI | 运行时几乎免费 | 不能动态变化、包体增大、要烘焙时间 | 需要昼夜循环时不行 |
| 全屏后处理 | 画面风格 | 每个 pass 一次全屏读写 | 移动端应当合并与精简 |
| 高精度 PS | 精度 | 慢 | 移动端默认可用半精度 |
7. 踩坑与排查
| 坑 | 现象 | 怎么验证 |
|---|---|---|
| 帧率低但 GPU 算力不满 | 带宽瓶颈 | 用移动端 GPU 剖析工具看带宽/片元吞吐 |
| 发热降频 | 跑一会儿变卡 | 功耗与发热是移动端特有的时间维度问题,见 Profile 功耗节 |
| 包体过大 | 商店限制 | 纹理压缩与 shader permutation |
| 某些效果在移动端消失 | 分平台分支(ES3.1 等) | 检查材质的 feature level 分支 |
| 精度问题(z-fighting、条纹) | 半精度导致 | 开 Use Full Precision in Pixel Shader 对比 |
| 阴影不对 | 移动端阴影路径不同 | 检查 r.Mobile.* 阴影开关 |
| 编译慢、包体大 | permutation 膨胀 | 减少 Static Switch(见 材质与着色器编译) |
| 桌面跑得好移动端崩 | 超出 sampler / RT 上限 | 查 RHI 校验日志 |
| MSAA 开启后骤降 | 解析带宽 | 移动端改用 TSR 类方案 |
8. 排查顺序
1. 先确认瓶颈类型:带宽 / 片元 / 顶点 / CPU
└─ 移动端大概率是带宽
2. 砍全屏 pass 数量
3. 调 r.MobileContentScaleFactor
4. 检查 Mobile HDR 是否必要
5. 看纹理格式是不是 ASTC
6. 发热降频?→ 看功耗曲线(时间维度,别只看瞬时帧率)
7. 用平台工具:Android GPU Inspector / Xcode / Adreno / Mali(见 Profile)参考
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/7b116293.html
更新于:2026年10月10日