Bevy Rendering
Bevy 渲染系统的核心概念、管线结构与近期关键修复汇总。
渲染管线概览
Bevy 使用基于 wgpu 的模块化渲染管线,主要阶段包括:
- Extract:将 ECS 世界中的数据提取到渲染世界
- Prepare:准备渲染资源(如
PrepareAssets阶段) - Queue:排序并生成渲染指令
- Render:执行 GPU 绘制调用
近期关键修复
Mesh 重分配 GPU 内存泄漏修复(2026-08-04,critical)
PR #25259(0.19.1,+735/-13)修复了 mesh handle 从 Assets 移除后同帧重新插入相同 handle 时发生的 GPU 内存泄漏(#18808)。
根因: MeshAllocator::free_meshes 原逻辑假设 extracted_meshes.added 只包含新增 mesh,但实际上它持有本帧提取的全部 mesh。当 mesh 被移除后重新插入时,旧 slab 分配未被释放,导致 GPU 内存随帧累积。
修复: free_meshes 现在释放本帧所有计划重分配的 mesh,避免旧 slab 残留。slab_allocator 新增 empty_slabs 追踪,在无 pending submit 时尝试 reallocation 会 panic/error。
测试基建副产物: 新增 test_utils.rs 使用 wgpu noop backend,让渲染单测可在无 GPU 环境创建 dummy RenderDevice/RenderQueue——为后续渲染模块单测铺设了路径。
WESL 迁移(2026-08-05,M-Release-Note,378 files)
PR #25088(+4527/-5381, 378 files, 无 milestone)将 Bevy 全部内部 shader 迁移到 WESL(webgpu-tools 的 WGSL 超集扩展),经 wesl-rs 实现。这是 0.20 前渲染侧最大的基础变更:自定义 shader / material 作者需关注 0.20 的 shader 资产格式与导入语法变化。
0.19.1 渲染 bugfix 批次(2026-08-05,同一 merge-queue 批次)
- #25261 — 修复
binding_arrays_are_usable检查(+8/-1)。旧检查误用max_storage_textures_per_shader_stage(#10268 时代 wgpu 无对应 limit),现改查max_binding_array_elements_per_shader_stage/max_binding_array_sampler_elements_per_shader_stage。 - #25256 — clearcoat 下 emission 正确分层(+2/-1)。修复 #25083,按 glTF
KHR_materials_clearcoat规范实现 emission 分层。 - #25252 — 修复 shader 越界访问(+8/-3, 2 files)。修复 #25251 及作者另发现的越界 bug。
三者均绑定 0.19.1,指向补丁发布临近。
UI 渲染提取 removed-component 路径修复(2026-08-07,两个 P-Regression,0.20)
PR #25188 + #25184(2026-08-07 批量合并,均为 milestone=0.20 的 P-Regression 修复)补齐了 UI 渲染提取管线在组件被移除时的两条漏洞,两个 PR 都绑定 0.20——UI 渲染提取逻辑在 0.19 开发中累积的回归正在 0.20 集中清理:
- #25188 —
CalculatedClip移除后 gradient 未被重新提取:UI 渐变依赖CalculatedClip,组件被移除时渐变本应重新提取,但旧逻辑直接 despawn 对应 render entity。修复将 removedCalculatedClip实体链入 UI nodes changed query,并从 cleanup iterator 移除removed_calculated_clip_query。 - #25184 —
MaterialNode变更检测遗漏:(1) 材质异步加载完成不触发组件Changed,导致加入nodes_to_reextract_next_frame的节点不保证下帧重提取;(2)CalculatedClip从MaterialNode实体移除时,ExtractedUiMaterialNode不更新而是连同 render entity 被删除。
影响场景:UI 中使用自定义 Material(MaterialNode)或 gradient 背景且动态变更 clip 的项目。
08-11 渲染修复/性能批次(2026-08-11,合并暂停恢复后)
08-11 单日 18 PR 中 7 个渲染相关(2 个 0.20 正确性 + 2 个性能 + 3 个 0.19.1 bugfix),显示 0.20 渲染侧在正确性与性能两个方向同时收口:
- #24971 — 间接参数构建 shader 越界写修复(0.20, P-Regression, +521/-73, 5 files)。修复 #23662 引入的阴影偶发闪烁:indirect params 构建 shader 每次调用只写自己负责的 batch range。触发条件:多视图(如点光源提取 6 个 shadow view)+ 物体 OBB 变化导致跨视图移动时;
3d_shapes示例可复现。 - #24148 — UI CPU clipping 支持旋转/缩放(0.20, M-Deliberate-Rendering-Change, +758/-645, 18 files)。
Overflowclipping 现支持变换节点。CalculatedClip由结构体变为 enum(Rects:本地坐标 Rect 列表 + world-to-localAffine2;FullyClipped),bevy_ui_render新增clipping模块 +clip_polygon。修复 17630/21775/25126。0.20 破坏性变更(自定义 UI 渲染/提取/picking 代码需适配 enum)。 - #25058 — material bind group 复用(pcwalton, +579/-147, 7 files)。仅 POD 变化(如 color)时不释放重建 bind group,只有 GPU 资源(buffer/texture/sampler)变化才重建——避免 slab 无谓溢出与重建开销。
- #24928 — 2D mesh 保留式提取(+235/-46, 7 files)。
RenderMesh2dInstances从逐帧全量重提取改为保留式 + 细粒度 change detection(对齐 3D mesh 已有逻辑),未变化 mesh 不再重复提取。 - #25253 — 2D flicker:retained phase items 清理(0.19.1, +8/-4)。
queue_material2d_meshes在render_material_instances为空时提前 return,最后一个使用该 material 类型的实体 despawn 帧的 retained phase items 永久滞留 → 修复 #25163。 - #25338/#25334 — SSAO 双修复(均 0.19.1)。#25338:
texture_depth_2d的textureGather首参数非整数导致 ChromecreateShaderModule报错(+1/-1);#25334:processSample()将归一化法线 [0..1] 与fast_acos()弧度值混用,front_back_horizon需先除以 PI 归一化(+5/-6, 4 files)。 - #25325 — 2D material 同帧 swap 渲染失败(+16/-4)。同帧添加
MeshMaterial2d<M2>+ 移除MeshMaterial2d<M1>时,实例被错误从RenderMaterial2dInstances删除(类型不匹配时不该删)。
模式信号:SSAO 在 08-10/11 连续收到 3 个修复(含 open 的 #25319 viewport depth sampling、#25358 depth-writes),0.19.1/0.20 对 SSAO 正确性集中收口。
GPU sorted phase batching bugfix(2026-05-22)
PR #24365 修复了 GPU 预处理路径忽略 AUTOMATIC_BATCHING = false 标志的 bug。当 GPU 预处理启用时,本应按有序 chunk 渲染的 sorted phase 项被错误地合并批处理。
- 影响场景:
Transmissive3d等需要按ScreenSpaceTransmission.steps控制渲染顺序的 pass - 修复: GPU 预处理路径现在检查
PhaseItem::AUTOMATIC_BATCHING再决定是否批处理 - 0.19 milestone bugfix,RenderDoc 已验证修复
Solari light leak 改进(2026-05-21)
PR #24332(JMS55)两项改进降低 Solari GI 的光照泄漏:
- Jitter 仅在 specular GI 时开启(减少非必要噪声)
- 选择大于
ray_t的最大 cell size,而非立即 snap 到 base cell
标签 C-Refinement,改善输出质量。详见 bevy-solari-pathtracer。
SpotLight + Camera 同实体 Frustum 覆盖(2026-05-21)
PR #24324(纯文档):当 SpotLight 和 Camera 在同一实体时,聚光灯 frustum 计算会覆盖相机的 Frustum,导致错误的 frustum culling。文档添加了粗体警告。
PR #24216 修复了 Windows 11 Vulkan 下窗口最小化/恢复后的阴影闪烁问题。相关逻辑原在 PrepareAssets 阶段中运行;PR 将其移动到 Specialize 并在 specialize_shadows 前执行,规避了该阶段变化带来的不一致性。仅影响 Windows 11 + Vulkan 且触发最小化/恢复路径的用户。
GPU 可见性裁剪回退(待决定)
PR #24252 提议回退 #23115(GPU 可见性范围裁剪),以避免 0.19 发布时的阴影回归。JMS55 和 Zeophlite 已批准该务实选择。若合并,0.19 可能在 24-48 小时内发布。
体素渲染(Voxel Rendering)
体素场景在 Bevy 中通过表面网格化实现,主要流程为:体素数据 → Greedy Meshing → Bevy Mesh → GPU 光栅化。关键工具链:
- block-mesh — Rust 底层 greedy meshing 库,支持可见面提取和贪心合并两种算法
- bevy_voxel_world — 全功能体素地形插件,内置多线程 chunk meshing、LOD、纹理数组
- voxel-rendering — 体素渲染概念与技术谱系总览
- voxel-rendering-pipelines — 体素渲染双路线对比
与 Virtual Geometry(Meshlet)的结合:体素经 greedy meshing 生成的 mesh 可转换为 MeshletMesh,获得自动连续 LOD 和 GPU-driven 剔除。
物体高亮与选择(Hover Highlighting)
游戏中鼠标悬停或选中物体的高亮效果在 Bevy 中有多种实现路线:
- hover-highlighting-techniques — 游戏高亮技术的深度解析(后处理、模板缓冲、JFA、自发光、贴花)
- hover-highlighting-comparison — 五种技术的完整对比与决策矩阵
- bevy_mod_outline — Bevy 最成熟的描边插件,支持顶点挤出与跳跃洪水距离场
Bevy 0.15+ 原生能力:自定义渲染阶段可在主 Pass 之后执行后处理,Prepass 提供深度/法线纹理供 Sobel 边缘检测使用。
Skybox 渲染世界清理(0.19 bugfix)
PR #24389(2026-05-22 合并)修复了一个影响所有 Skybox 用户的渲染世界残留 bug:skybox 组件从主世界移除后,渲染世界中的提取副本不会同步清除。
根因: Skybox 在 PR #22682 中从 bevy_pbr 迁移至 bevy_light 时,因 orphan rule 限制改为手动采掘逻辑,但遗漏了 SyncComponentPlugin<Skybox> 的手动注册(该 plugin 在 ExtractComponentPlugin 路径下会自动注册,手动路径则需显式声明)。详见 sync-component-plugin。
修复: 一行 app.add_plugins(SyncComponentPlugin::<Skybox>::default())。
复现: anisotropy 示例中按 Space 从环境贴图模式切回方向光模式时,天空盒应消失但之前一直残留。
相关页面
- skybox — Skybox 组件实体页面(本 bug 的实际用例)
- sync-component-plugin — SyncComponentPlugin 同步机制概念
- bevy-shadow-maps — 阴影映射系统与 ShadowLodOrigin 修复
- bevy — Bevy 引擎总览
- bevy-game-dev-2026-05 — 2026 年 5 月引擎变更追踪
- bevy-game-dev-2026-08 — 2026 年 8 月引擎变更追踪
- bevy-migration-2026-05 — 迁移敏感变更