Writing Brief: Bevy 里「overlay」到底怎么实现的

版本锚点:正文以 v0.19.0git show v0.19.0:crates/bevy_dev_tools/...)为准;maindiagnostics_overlay.rs 行数与 0.19.0 一致,后续小修见 #24433、#24611。
不是 Bevy 统一 API:文中用「四类叠层」避免读者以为有一个 Overlay trait。

目标

建议
公众号标题≤12 字,例:「Bevy 调试叠层」 / 「四层叠层怎么叠」
副标题(frontmatter title)Bevy 调试叠层:Diagnostic、FPS、渲染与 UI 线框
受众已写过 Bevy App/Plugin,想少造轮子、搞清 dev_tools 边界的中文开发者
风格杂志技术稿:先地图后细节;代码块短、可 cargo run --example fps_overlay 验证
长度2800–3500 字(单篇专题,不塞进 0.19 总览)
正文落点Vault My Blog/share: false 起草)

一句话论点

Bevy 的 overlay 是 四条并行管线(UI 诊断窗、UI FPS HUD、3D 缓冲区全屏 shader、UI 布局线框),共同点是「叠在画面上」,实现上 只有前两类在 bevy_dev_tools,后两类分别在 render_debugbevy_ui_render extract 阶段

建议结构(按节写)

1. 开场:为什么 0.19 值得单独讲 overlay(~300 字)

  • 以前:FrameTimeDiagnosticsPlugin + 自己 spawn Text + GlobalZIndex
  • 0.19:#22486 DiagnosticsOverlayPlugin — spawn 带 DiagnosticsOverlay Component 即得可拖、可折叠窗口。
  • 澄清:RenderDebugOverlay 很多 3D 项目 已在 DefaultPluginsbevy_dev_tools + bevy_pbr),和 Diagnostic 窗 不是同一套

2. 总览图(必配 ASCII 或 Mermaid)

flowchart LR
  subgraph ui_dev["bevy_ui 叠层"]
    D[DiagnosticsOverlayPlugin]
    F[FpsOverlayPlugin]
  end
  subgraph diag["bevy_diagnostic"]
    S[DiagnosticsStore]
  end
  subgraph render["RenderApp"]
    R[RenderDebugOverlayPlugin]
  end
  subgraph ui_dbg["bevy_ui_render extract"]
    U[extract_debug_overlay]
  end
  S --> D
  S --> F
  R --> ViewTarget
  U --> ExtractedUiNodes

3. DiagnosticsOverlay — 数据到窗口(~900 字)★核心

源码crates/bevy_dev_tools/src/diagnostics_overlay.rs

概念作用
DiagnosticsOverlayComponent:title + items: Vec<DiagnosticsOverlayItem>
DiagnosticsOverlayItempath + statistic(Value/Average/Smoothed)+ precision
DiagnosticsOverlayPlanePreStartup 全屏根,GlobalZIndex(1_000_000)
DiagnosticsOverlayPluginObservers + 每秒 rebuild_diagnostics_list

生命周期(写作时按顺序讲)

  1. PreStartup::build_plane — 一个 Plane,子 overlay 都挂下面。
  2. commands.spawn(DiagnosticsOverlay::fps())On<Add, DiagnosticsOverlay>build_overlay 建标题栏 + Grid 内容区。
  3. 每秒从 DiagnosticsStore 读数;未注册路径显示 Missing(教读者补对应 diagnostic plugin)。
  4. 交互:拖标题Node top/left点标题折叠 Grid;点窗口 ChildOf 重挂 Plane 置顶
  5. Pickable::should_block_lower: false — 不抢游戏点击。

可贴代码(0.19 合法)

use bevy::prelude::*;
use bevy::dev_tools::diagnostics_overlay::{
    DiagnosticsOverlay, DiagnosticsOverlayItem, DiagnosticsOverlayPlugin,
    DiagnosticsOverlayStatistic,
};
use bevy::diagnostic::FrameTimeDiagnosticsPlugin;
 
fn main() {
    App::new()
        .add_plugins((DefaultPlugins, FrameTimeDiagnosticsPlugin::default()))
        .add_plugins(DiagnosticsOverlayPlugin)
        .add_systems(Startup, |mut c: Commands| {
            c.spawn(DiagnosticsOverlay::fps());
            c.spawn(DiagnosticsOverlay::mesh_and_standard_material());
        })
        .run();
}

注意:mesh_and_standard_material() 方法名(单数 material);release note 里偶写 mesh_and_standard_materials() 以源码为准。

预设与依赖

  • fps() → 需 FrameTimeDiagnosticsPlugin(FPS overlay 插件会自动加,Diagnostic 窗 不会 自动加 frame plugin,文中写清读者要自己 add_plugins)。
  • mesh_and_standard_material() → 需 MeshAllocatorDiagnosticPluginMaterialAllocatorDiagnosticPlugin<StandardMaterial> 等已注册路径。

4. FpsOverlay — 何时不用 Diagnostic 窗(~500 字)

源码fps_overlay.rs + frame_time_graph/

  • 一个 FpsOverlayConfig Resource,Startup 建固定 UI 树。
  • GlobalZIndex(i32::MAX - 32)update_texton_timer(refresh_interval) 默认 100ms。
  • 可选 帧时间柱状图UiMaterialPlugin<FrametimeGraphMaterial> + ShaderBuffer;WebGL 无 webgpu 时 warn 并跳过。
  • 文内引用官方态度:优先平台原生 HUD(Metal MTL_HUD_ENABLED=1),应用内 overlay 有刷新开销。

示例命令cargo run --example fps_overlay --features bevy_dev_tools(按项目 feature 表写一句怎么开 dev_tools)。

5. RenderDebugOverlay — 叠在 3D 画面上(~500 字)

源码render_debug.rs,shader debug_overlay.wgsl

  • 插入点Core3dPostProcess 之后、ui_pass 之前(文章画一条简化渲染顺序条)。
  • F1 循环 RenderDebugMode(depth / normal / motion / deferred…),按相机 prepass 能力跳过。
  • 与 Diagnostic 正交:读 GPU buffer,不读 DiagnosticsStore
  • 默认插件组:default_plugins.rsbevy_dev_tools + bevy_pbr 时自动加入。

6. UI Debug — 不是窗口,是假节点(~400 字)

源码bevy_ui_render/src/debug_overlay.rs,feature bevy_ui_debugbevy_ui_render default 常开)

  • GlobalUiDebugOptions / 每节点 UiDebugOptions
  • extract_debug_overlayExtractedUiNodes 追加 border 类型节点,颜色 Hsla::sequential_dispersed(entity)
  • 0.19 迁移:与 GlobalUiDebugOverlay / component 拆分(可一句带过 migration guide,不深挖 Resources-as-Components)。

7. 选型表(收尾实用)

我要…
多指标、可拖、可关内容区DiagnosticsOverlayPlugin
角落 FPS + 柱状图FpsOverlayPlugin
看 depth/normal/deferredRenderDebugOverlay(F1/F2)
调 padding/content 盒GlobalUiDebugOptions

8. 常见坑(Pitfalls 小节)

  1. 显示 Missing → diagnostic plugin / path 未注册。
  2. Diagnostic 窗 1s 刷新 vs FPS HUD 100ms — 别用来盯单帧尖峰。
  3. 不要把四类叠层混成「开一个 Plugin 全搞定」。
  4. 写教程时 Diagnostics 与 FpsOverlay 都要显式 add_plugins;RenderDebug 可能已在 Default 里。
  5. 自定义 diagnostic:先 register 路径,再 DiagnosticsOverlay::new("标题", vec![path.into()])

素材与验证命令

cd ~/workspace/bevy
git show v0.19.0:crates/bevy_dev_tools/src/diagnostics_overlay.rs | head -80
cargo run --release --example fps_overlay   # 确认本地 features
rg 'DiagnosticsOverlayPlugin' crates/bevy_internal examples/

配图建议

  1. DiagnosticsOverlay 双窗口(fps + mesh/material)截图 — 自写最小 demo 或等 scene_viewer 合入后截官方 example。
  2. fps_overlay example 绿字 + 柱状图。
  3. RenderDebug F1 切 depth 一帧(注明需 prepass)。
  4. UI debug 多色线框(full_ui + feature)。

与现有 wiki / 博客关系

  • 不重复 bevy-0-19-release-brief.md 全文;可在 0.19 总览文末链到本篇「调试叠层专题」。
  • 可链 bevy、concepts 里 diagnostic 相关页(若有)。
  • PR 时间线:aeb9e0e16 #22486;21e8ab211 PreStartup;73d4aa3c7 fixes。

Writer 完成定义

  • 四类叠层各有一句「数据从哪来、画在哪」
  • 至少一个可运行 minimal DiagnosticsOverlay 示例
  • 标明 v0.19.0,不混 main 未发布 API
  • 无「单一 Overlay 系统」表述
  • 代码在 cargo check 或 example 级别可验证(writer/coder profile 可代跑)