这里的“少后处理、少动态光”是移动端渲染里的一个性能原则不是说完全不能用而是说移动端 GPU 带宽、算力、电量、散热都紧不能像 PC 那样堆很多屏幕级 Pass 和很多实时光源。先说“少后处理”。后处理的特点是它通常对整张屏幕做计算。比如 1080p1920 × 1080 ≈ 207 万像素一个后处理 Pass 就可能要处理 207 万个像素。如果你有很多个Bloom DOF Motion Blur SSR SSAO Color Grading TAA/TSR 描边 径向模糊 屏幕空间雾那就变成整屏处理一次 整屏处理一次 整屏处理一次 整屏处理一次 ...移动端吃不消尤其是多次读写 SceneColor 多张临时 RenderTarget 高分辨率模糊 多次采样邻近像素所以“少后处理”的意思是少 pass 少全屏采样 少大半径 blur 少高分辨率临时 RT 能合并就合并 能半分辨率就半分辨率 能不用就不用PC 高配后期可能长这样SceneColor ↓ Depth of Field ↓ Motion Blur ↓ Bloom 多级模糊 ↓ Lens Flare ↓ SSR / SSAO / SSGI ↓ Exposure ↓ Tonemap ↓ Color Grading ↓ TAA / TSR ↓ Sharpen / FXAA ↓ UI移动端/前向端一般会变成SceneColor ↓ 简单 Bloom可选 ↓ Exposure可选或简化 ↓ Tonemap Color Grading 合并 ↓ FXAA / 简化 TAA可选 ↓ UI常被砍掉或大幅简化的是这些SSR SSAO SSGI 复杂 DOF Motion Blur 高质量 Bloom Lens Flare 复杂 Volumetric Fog 复杂 Screen Space Fog 复杂 TAA/TSR 多个自定义后处理材质 高质量半透明后处理为什么这些容易被砍SSR: 要沿屏幕空间 ray marching多次采样 SceneColor/Depth很贵而且移动端效果还不稳 SSAO: 要围绕每个像素采很多深度/法线样本典型全屏多采样 SSGI: 更贵本质是屏幕空间间接光多采样降噪 DOF: 需要分层/散景/多次模糊/合成RT 很多 Motion Blur: 要读 velocity按速度方向多次采样 高质量 Bloom: 要 downsample 多级再 upsample 多级虽然可优化但还是一串 pass TSR/TAA: 要 history、velocity、邻域采样、反鬼影带宽和 ALU 都不轻所以移动端不是“没有后期”而是尽量保留性价比最高的Tonemap Color Grading 简单 Bloom 简单曝光 简单抗锯齿 少量风格化后期怎么更节约地用后期第一条合并 pass。不要这样Pass 1: 调色 Pass 2: vignette Pass 3: 饱和度 Pass 4: 角色边缘变暗 Pass 5: 色阶应该尽量变成一个 Tonemap/ColorGrading pass 里一起做因为每多一个 pass通常就多一次读 SceneColor 写一个 RT 再读这个 RT 再写下一个 RT第二条半分辨率 / 四分辨率。很多模糊类效果不需要全分辨率。比如Bloom DOF 雾 光晕 辉光 远景模糊可以1/2 分辨率做 甚至 1/4 分辨率做 最后双线性上采样合回去这样像素数直接变少全分辨率1920 × 1080 207万 半分辨率960 × 540 52万 四分之一第三条降低采样数。你的描边就是典型例子。PC 可以8方向 × 多半径移动端可以4方向 只采上下左右 OutlineWidth 限制为 1 只对角色 stencil 做从8 * Radius降到4 * 1第五条减少 RT 格式和数量。移动端 RT 格式很重要。比如能用R8 RG8 R11G11B10 RGBA8 Half res就别直接RGBA16F 全分辨率多张尤其自定义后处理别随手开高精度 HDR RT。带宽就是单位时间内数据能从一个地方搬到另一个地方的量。放到 GPU 渲染里最常说的是显存带宽 GPU 每秒能从显存读/写多少数据。比如GPU 算力 我一秒能算多少次加减乘除 GPU 带宽 我一秒能搬多少 GB 数据这俩不是一回事。举个后处理例子。一张 1920×1080 的 RGBA16F 颜色图1920 × 1080 ≈ 207 万像素 RGBA16F 8 bytes / pixel 一张图 ≈ 16.6 MB一个后处理 pass 如果做读 SceneColor 写 OutputColor那大概就是读 16.6 MB 写 16.6 MB 合计 33.2 MB如果一个效果要 5 个 pass33.2 MB × 5 ≈ 166 MB这还只是颜色没有算深度、法线、velocity、临时 RT、多次采样。所以后处理贵不只是“算得多”还因为一直在搬数据从显存读一张大图 处理 再写回显存 下一步再读 再写 再读 再写这就是带宽压力。你可以用厨房比喻算力 厨师切菜炒菜的速度 带宽 服务员/传送带搬食材和盘子的速度厨师再快如果食材搬不过来也会卡住。你可以记这个公式感受一下带宽消耗 ≈ 像素数 × 每像素字节数 × 读写次数 × 采样次数所以优化方向就是降低分辨率 降低格式精度 减少 pass 减少采样 减少 RT 数量 合并读写移动端把Lighting pass也合到basepass其实也是为了减少带宽对核心目的之一就是减少带宽而且是非常关键的原因。移动端把 Lighting 合到 BasePass可以理解成PC Deferred BasePass 先写一堆 GBuffer LightingPass 再读 GBuffer 算光 最后写 SceneColor Mobile Forward BasePass 直接算材质 光照 直接写 SceneColorPC Deferred 大概是这样BasePass 写 GBufferA 写 GBufferB 写 GBufferC 写 Depth 写 Velocity 可选 LightingPass 读 GBufferA 读 GBufferB 读 GBufferC 读 Depth 读 Shadow 算光 写 SceneColor这中间发生了大量“搬数据”写 GBuffer 再读 GBuffer 再写 SceneColor移动端 Forward 是Mobile BasePass 算材质 算主光 算简单阴影 算少量局部光 直接写 SceneColor它省掉了多张 GBuffer 的写入 LightingPass 读 GBuffer 额外的全屏 LightingPass 部分中间 RT所以确实省带宽。但不只是带宽还省这些少一次/多次 render target 读写 少一些 pass 切换 少 MRT 压力 少显存占用 更适合 tile-based GPU 功耗更低