ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Frame Debugger:看清一帧是怎么画出来的

Frame Debugger:看清一帧是怎么画出来的 它是什么Unity 内置的渲染调试器。它把一帧的渲染过程暂停并拆成一步一步,你可以逐个 Draw Call 往下点,看每一步往屏幕上画了什么。Window → Analysis → Frame Debugger → 点 Enable点下去之后游戏暂停,Game 视图变成画到第 N 步为止的状态。左边是这一帧所有渲染事件的列表,点哪一步,Game 视图就显示到那一步。它最大的价值不是看好看,而是回答这三个问题:① 这一帧到底画了多少东西?顺序是什么? ② 这两个物体为什么没合批? ③ 这个东西为什么没显示 / 显示错了?一、界面怎么读┌─ 左侧:渲染事件树 ──────────┬─ 右侧:选中事件的详情 ─────────┐ │ │ │ │ ▼ UniversalRenderPipeline │ Shader: Universal Forward │ │ ▼ MainLightShadow │ Pass: ShadowCaster │ │ Draw Mesh (x18) │ │ │ ▼ RenderLoop.Draw │ ┌──────────────────┐ │ │ ▼ RenderOpaques │ │ 这一步的输出预览 │ │ │ Draw Mesh Ground │ └──────────────────┘ │ │ Draw Mesh (x24) Box │ │ │ Draw Dynamic │ Keywords / 纹理 / 属性值 │ │ ▼ RenderTransparents │ │ │ Draw Mesh Glass │ ⚠️ Why cant batch with │ │ ▼ PostProcess │ previous: ... │ │ Draw Procedural │ │ │ ▼ RenderUI │ │ │ Draw Mesh Canvas │ │ │ │ │ │ [◄][ 滑块 ] 42 / 180 │ │ └─────────────────────────────┴────────────────────────────────┘要关注的几处位置看什么底部计数42 / 180这一帧总共 180 个渲染事件。数字大得异常就要查事件名后的(x24)这一步合批了 24 个物体。数字越大越好事件树的分组阴影 Pass / 不透明 / 半透明 / 后处理 / UI 各占多少右侧的 batch 原因为什么没能和上一个合批,最常用的信息RenderTarget 下拉切换查看 Color / Depth / 各个 RT通道按钮 RGBA单独看某个通道,查法线、深度、Mask 很有用二、最主要的用途:查合批失败点中一个 Draw Call,右侧底部会直接写明原因:Why this draw call cant be batched with the previous one: Objects have different materials.这是整个工具最省时间的功能——不用猜。常见原因与对应处理提示实际原因怎么改Objects have different materials材质不同(非 SRP Batcher)合并材质 / 用图集 / 确认 SRP Batcher 开启Objects are affected by different lights受不同光源影响减少实时点光,改用烘焙或 Light ProbeObjects have different lightmapsLightmap 不同张调整 Lightmap 分辨率让它们落到同一张Objects have different reflection probes反射探针不同合并探针范围Shadow casting mode is different阴影投射设置不一致统一 Renderer 的 Cast ShadowsShader has instancing disabledShader 没开 InstancingShader 里加#pragma multi_compile_instancingObjects have different shader keywordsShader 变体不同统一材质上的 keyword 开关Non-instanced properties set for instanced shader用了 SetColor 等直接改材质改用 Instanced 属性或顶点色Instancing is disabled on the material材质没勾 Enable Instancing勾上The node has different RenderTarget中间切了 RT检查是否有多余的后处理/RT 切换SRP Batcher 的情况不一样用 URP/HDRP 时,SRP Batcher 的合批显示方式是:Draw Mesh (SRP Batch) ← 看到这个说明进 SRP Batcher 了SRP Batcher 不要求材质相同,只要求 Shader 变体相同。所以看到 “different materials” 的提示但你用的是 URP,先确认:Project Settings → Graphics → 当前 URP Asset → Advanced → ☑ SRP Batcher打断 SRP Batcher 的几个典型写法:// ❌ 运行时直接改 material,会创建材质实例renderer.material.colorColor.red;// ❌ MaterialPropertyBlock 和 SRP Batcher 冲突renderer.SetPropertyBlock(block);// ✅ 改 sharedMaterial 的属性(但会影响所有用这个材质的物体)// ✅ 更好:把变化数据放顶点色 / UV2 / Instance 属性三、用来查为什么没显示物体在 Scene 视图有,Game 视图没有——这是 Frame Debugger 第二大用途。排查路径① 在事件列表里搜这个物体的名字 找不到 → 根本没提交 Draw Call → 剔除问题(视锥 / 距离 / Layer / Occlusion) → 或者 Renderer.enabled false ② 找到了,但点上去 Game 视图没看到变化 → 画了,但被挡住 / 在屏幕外 / Alpha 为 0 / 尺寸为 0 ③ 找到了,画出来是黑的/紫的 → 紫色 Shader 编译失败或丢失 → 黑色 贴图没赋值,或光照为零 ④ 画出来了,但下一步被覆盖 → 顺序问题,检查 RenderQueue顺序问题怎么看这是 Frame Debugger 独有的能力:逐步播放。拖动底部滑块,一步步往后走: 第 30 步:角色画出来了 ✅ 第 31 步:角色不见了 ← 问题就在第 31 步 点开第 31 步 → 发现是一个全屏的半透明 Quad → RenderQueue 设错了,盖住了角色RenderQueue 参考值: 1000 Background 天空盒之前的背景 2000 Geometry 不透明物体(默认) 2450 AlphaTest Alpha 裁剪(植被) 3000 Transparent 半透明 4000 Overlay 最后画的(镜头光晕、全屏效果)四、查 Overdraw 和多余的 Pass看阴影 Pass 的开销展开MainLightShadow分支:▼ MainLightShadow Draw Mesh (x120) ← 120 个物体在投阴影 Draw Mesh (x80)阴影 Pass 等于把场景又画了一遍(只写深度,但顶点处理照跑)。如果这里的物体数接近主 Pass,说明阴影是实打实的双倍成本。优化方向: · 小物件关掉 Cast Shadows · 缩短 Shadow Distance · 减少 Cascade 数量(每个 Cascade 都是一遍) · 远处物体用烘焙阴影 / 假阴影贴片展开后能看到级联数量:▼ MainLightShadow ▼ Cascade 0 ← 4 级联 场景被画 4 遍 ▼ Cascade 1 ▼ Cascade 2 ▼ Cascade 3中低端机建议 1~2 级联。看后处理和 RT 切换▼ PostProcessPass Blit ← 每个 Blit 都是一次全屏读写 Draw Procedural Bloom Blit Draw Procedural Bloom Blit Draw Procedural UberPost Blit移动端每一次全屏 Blit 都要把整帧从主内存读出写回,带宽开销很大。看到一长串 Blit 就要考虑:· 能不能合并到一个 Pass(Bloom Tonemap Vignette 合在 UberPost) · 低端机档位直接关后处理 · Bloom 的 downsample 层数能不能减五、查贴图和参数是否对选中一个 Draw Call,右侧会列出这次绘制实际用到的所有资源:Textures _BaseMap character_albedo (1024x1024 ASTC_6x6) _BumpMap character_normal (1024x1024 ASTC_5x5) _MainLightShadowmapTexture (2048x2048) Floats _Smoothness 0.5 _Cutoff 0.5 Vectors _BaseColor (1.0, 1.0, 1.0, 1.0) Keywords _NORMALMAP _MAIN_LIGHT_SHADOWS_CASCADE _ADDITIONAL_LIGHTS能查出来的问题:· 贴图尺寸比预期大(美术给了 4K,以为是 1K) · 格式不是压缩格式(显示 RGBA32) · 用错了贴图(名字不对) · Keyword 比预期多(说明变体更复杂,影响合批) · 参数值不对(_Cutoff 被改成了 0,导致全透明)Keywords 这一栏对排查变体问题特别有用。两个看起来一样的物体不合批,经常就是 keyword 差一个。六、连真机调试编辑器里的数据参考价值有限,真机才是真相。① Build Settings 里勾上: ☑ Development Build ☑ Autoconnect Profiler ② 打包装到手机,保持同一局域网(或 USB 连接) ③ Frame Debugger 窗口顶部的下拉框 从 Editor 切到你的设备 例:AndroidPlayer(SM-G998B192.168.1.23) ④ 点 Enable⚠️ 注意事项 · Development Build 本身有额外开销,耗时数据偏高 → 用它看「画了什么、合批情况」,不要用它下性能结论 · 真机上 Frame Debugger 可能不稳定,断连重连是常事 · Android 建议用 USB adb forward 更稳: adb forward tcp:34999 localabstract:Unity-包名真机和编辑器会不一样的地方编辑器 真机 ───────────────────────────────────────────── Shader 变体全量编译 只有打包进去的变体 → 真机可能丢变体变紫 Scene 视图的额外绘制 没有 Editor Only 的 Gizmo 没有 质量档位可能不同 按实际档位走 纹理用的是 Editor 平台设置 用目标平台的压缩格式所以编辑器正常、真机显示不对的问题,必须连真机的 Frame Debugger 查。最常见的是 Shader 变体被剥离导致材质异常。七、常见排查场景现象Frame Debugger 怎么查Draw Call 远超预期看哪个分组事件最多,是阴影、UI 还是半透明两个相同物体不合批点第二个,读 “Why can’t batch”物体不显示搜名字,看有没有 Draw Call物体显示紫色看 Shader 栏,大概率变体丢失物体被莫名覆盖逐步播放,定位到哪一步盖住的半透明排序错乱看 RenderTransparents 里的绘制顺序UI 比预期慢展开 RenderUI,看 Canvas 被拆成几个批次不知道后处理花了多少数 PostProcess 分支下的 Blit 数量阴影很贵看 MainLightShadow 下的物体数和 Cascade 数怀疑贴图太大点任意 Draw Call,看 Textures 栏的实际尺寸八、UI 相关的特殊看法UGUI 的批次在 Frame Debugger 里很直观:▼ RenderUI Draw Mesh (x12) Canvas ← 12 个 UI 元素合成一批,好 Draw Mesh (x1) Canvas ← 单独一批,被打断了 Draw Mesh (x8) Canvas Draw Mesh (x1) Canvas出现大量(x1)说明批次被反复打断。常见原因:· 图片来自不同图集 → 整理图集 · 中间夹了一个 Text(字体是另一张贴图)→ 调整层级顺序 · Mask / RectMask2D → Mask 会强制打断批次 · 元素的 Z 轴不为 0 → 全部归零 · Canvas 里混了不同材质的元素 → 按材质分组排层级优化思路:让同图集的元素在层级上连续 把 Text 集中放在一起 少用 Mask,改用图片本身做形状九、局限与替代工具Frame Debugger 能看画了什么,但看不到每一步花了多少时间。Frame Debugger 能做 不能做 ────────────────────────────────────────────────────── 看渲染事件顺序和数量 ✅ 看每个 Draw Call 的耗时 ❌ 看合批失败原因 ✅ 看 GPU 各阶段占比 ❌ 看每步的贴图和参数 ✅ 看带宽消耗 ❌ 逐步回放定位覆盖问题 ✅ 看 Shader 指令数 ❌需要耗时数据就换工具:需求工具GPU 各阶段耗时、带宽、tile 统计Android GPU Inspector / Snapdragon ProfileriOS 的 GPU 帧分析、Shader 耗时Xcode GPU Frame Capture帧率/温度/功耗长期曲线PerfdogCPU 侧耗时分布Unity ProfilerShader 编译后的指令数Shader Inspector 的 Compile and show code实践顺序通常是:Unity Profiler 定性(CPU bound 还是 GPU bound) ↓ Frame Debugger 看结构(画了什么、合批如何、有无多余 Pass) ↓ AGI / Xcode 看耗时(到底哪一步贵)要点1. Frame Debugger 回答「画了什么」,不回答「花了多久」 2. 最高频用途是读 Why cant batch with previous —— 不用猜原因 3. 底部计数和事件名后的 (xN) 是两个最快的健康指标 4. 逐步拖滑块能定位「被什么盖住了」,这是它独有的能力 5. 展开阴影 Pass 看物体数和 Cascade 数,阴影经常是双倍成本 6. 数 PostProcess 下的 Blit 次数,移动端每次都是全屏带宽 7. 真机行为和编辑器不同,显示异常必须连真机查(尤其变体丢失) 8. 耗时数据要靠 AGI / Xcode / Perfdog,别指望 Frame Debugger
返回列表