首页
/ Bevy 深度渲染管线重构:DepthAttachment 更名与 DepthStencilAttachment 迁移指南

Bevy 深度渲染管线重构:DepthAttachment 更名与 DepthStencilAttachment 迁移指南

2026-09-05 22:44:04作者:沈韬淼Beryl

本篇指南围绕 Bevy 渲染管线为支持模板(Stencil)而进行的深度附加体(Depth Attachment)类型重构展开:原 DepthAttachment 更名为 DepthStencilViewAttachment、新增 DepthStencilAttachment 包装类型、ViewDepthTexture 更名为 ViewDepthStencilTexture,以及 ViewPrepassTextures::depth 字段类型变更。读完后,你将能够理解深度/模板纹视图的多视图模型(combined / depth-only / stencil-only)、各类型的构造与调用方式,并将自定义渲染 Pass 与 Prepass 相关代码平滑迁移到新 API。

该变更集在仓库中对应迁移指南 _release-content/migration-guides/depth_attachment_changes.md(关联 PR 24725),标题为 “Changes have been made to DepthAttachment, ViewDepthTexture and ViewPrepassTextures::depth to accommodate stencil support”。下面逐条拆解这些变更,并结合当前仓库源码给出可验证的实现细节。

四项核心变更总览

变更前 变更后 变化要点
DepthAttachment DepthStencilViewAttachment 内部从单个 TextureView 改为持有 DepthStencilViews;构造时需区分 combined depth-stencil、depth-only、stencil-only 三类视图,并额外提供模板面(stencil)的清除值
(无对应高层封装) 新增 DepthStencilAttachment 持有 CachedTexture、对应的 DepthStencilViewAttachment,以及可选的上帧深度纹理与视图
ViewDepthTexture ViewDepthStencilTexture 内部从 Texture 改为持有 DepthStencilAttachment
ViewPrepassTextures::depth: Option<ColorAttachment> ViewPrepassTextures::depth: Option<DepthStencilAttachment> 深度 Prepass 产物由颜色附加体类型改为深度模板附加体类型

这一组变更的共同目标是“accommodate stencil support”(适配模板功能支持),即让 Bevy 的深度纹理体系从“只关心深度”扩展为“同时管理深度与模板两个面(aspect)”。

DepthStencilViews:深度模板纹视图的多视图模型

所有变更的核心是新增的枚举 DepthStencilViews,定义于 crates/bevy_render/src/texture/texture_attachment.rs

/// Depth and stencil views of a depth texture.
///
/// Texture views with single depth or stencil aspect can be read in shaders.
/// Texture views with all aspect is renderable.
#[derive(Clone)]
pub enum DepthStencilViews {
    /// The texture only has depth aspect.
    DepthOnly { depth_view: TextureView },
    /// The texture only has stencil aspect.
    StencilOnly { stencil_view: TextureView },
    /// The texture has combined depth and stencil.
    DepthStencil {
        /// A texture view with both depth and stencil aspects, renderable,
        /// but can't be used as a binding resource.
        combined_view: TextureView,
        /// A texture view with depth only aspect, sample type `unfilterable-float`
        /// or `depth` in shaders, not renderable.
        depth_view: TextureView,
        /// A texture view with stencil only aspect, sample type `uint` in shaders,
        /// not renderable.
        stencil_view: TextureView,
    },
}

这里体现了 WebGPU 深度格式的基本规则:同一张深度模板纹理可以派生出多种 TextureView,而不同视图的用途互斥——

  • combined_view(全 aspect 视图):可渲染(renderable),用于作为 RenderPassDepthStencilAttachment 挂载到渲染 Pass,但不能作为着色器绑定资源;
  • depth_view(单 depth aspect 视图):可在着色器中以 unfilterable-float / depth 采样类型读取,但不可用于渲染;
  • stencil_view(单 stencil aspect 视图):可在着色器中以 uint 采样类型读取,但不可用于渲染。

这正是原文档末尾给出的迁移建议的底层原因:为确保对将来自定义深度格式(如 combined depth-stencil 格式、stencil-only 格式)的兼容性,应当根据视图的实际用途,选择单 aspect 视图(用于着色器资源绑定)还是全 aspect 视图(用于渲染附加体)

视图的获取接口

crates/bevy_render/src/texture/texture_attachment.rs 中提供了三个访问器,分别对应三类用途:

impl DepthStencilViews {
    /// 返回可绑定的 depth-only 视图(StencilOnly 变体返回 None)
    pub fn depth_only_view(&self) -> Option<&TextureView> { ... }
    /// 返回可绑定的 stencil-only 视图(DepthOnly 变体返回 None)
    pub fn stencil_only_view(&self) -> Option<&TextureView> { ... }
    /// 返回可渲染的视图:DepthStencil 变体返回 combined_view,
    /// DepthOnly / StencilOnly 变体返回各自的单视图
    pub fn attachment_view(&self) -> &TextureView { ... }
}

在自定义 Pass 中的典型用法因此变得清晰:要在着色器里采样上一帧深度,取 depth_only_view();要把该纹挂载为 Pass 的附加体,取 attachment_view()

视图如何从纹自动派生

DepthStencilViews::from_texturecrates/bevy_render/src/texture/texture_attachment.rs)根据纹理格式的通道决定生成哪个变体:

  • TextureChannel::DEPTH_STENCIL:创建默认描述符的 combined_view,再分别以 wgpu::TextureAspect::DepthOnlywgpu::TextureAspect::StencilOnly 创建 depth_viewstencil_view
  • TextureChannel::DEPTH:生成 DepthOnly 变体;
  • TextureChannel::STENCIL:生成 StencilOnly 变体;
  • 其他格式:直接 panic!,信息为 “Can't create depth attachment. Texture format is not a depth-stencil format.”。

也就是说,新 API 会在构造期强制校验纹理格式必须是深度/模板格式,而非深度格式在运行到该分支时才会暴露问题。

DepthStencilViewAttachment:更名后的 DepthAttachment

原来的 DepthAttachment 现更名为 DepthStencilViewAttachmentcrates/bevy_render/src/texture/texture_attachment.rs):

/// A wrapper for a [`TextureView`] that is used as a [`RenderPassDepthStencilAttachment`].
#[derive(Clone)]
pub struct DepthStencilViewAttachment {
    pub depth_stencil_views: DepthStencilViews,
    depth_stencil_data: DepthStencilData,
}

与旧实现相比有两个实质变化:

  1. 持有 DepthStencilViews 而非单一 TextureView:需要为 combined depth-stencil、depth-only、stencil-only 三种用途分别提供对应视图;
  2. 新增模板清除值:构造函数同时接收 depth_clear_value: Option<f32>stencil_clear_value: Option<u32>
impl DepthStencilViewAttachment {
    pub fn new(
        depth_stencil_views: DepthStencilViews,
        depth_clear_value: Option<f32>,
        stencil_clear_value: Option<u32>,
    ) -> Self { ... }

内部通过私有枚举 DepthStencilDatacrates/bevy_render/src/texture/texture_attachment.rs)按视图变体分别记录 depth 与 stencil 各自的清除值及“首次调用”原子标志,实现两个面独立的首次清除语义

  • get_attachment(store: StoreOp):首次调用且提供了对应清除值时,对该面执行 LoadOp::Clear,否则 LoadOp::Load;深度面或模板面中未提供清除值的一侧不会参与清除。从源码结构看,is_first_call 标志通过 fetch_and(store != StoreOp::Store, ...) 更新,即 StoreOp::Discard 表示内容被丢弃后仍保持“首次”状态,下次使用时会再次清除;
  • prepare_for_new_frame():把本帧标记为“未使用”,从而在下一帧首次使用时触发清除(见 crates/bevy_render/src/texture/texture_attachment.rs)。

对只关心深度的旧代码,迁移方式是:构造时传 stencil_clear_value: None,行为与原先的深度清除逻辑保持一致。

新增的 DepthStencilAttachment 高层封装

DepthStencilAttachmentcrates/bevy_render/src/texture/texture_attachment.rs)是本次变更引入的新类型:

/// A wrapper for a [`CachedTexture`] that is used as a depth
/// [`RenderPassDepthStencilAttachment`].
#[derive(Clone)]
pub struct DepthStencilAttachment {
    pub texture: CachedTexture,
    pub previous_frame_texture: Option<CachedTexture>,
    depth_stencil_view_attachment: DepthStencilViewAttachment,
    pub previous_frame_depth_stencil_views: Option<DepthStencilViews>,
}

它按原文档的描述,包含“一个 CachedTexture、其对应的 DepthStencilViewAttachment,以及可选的上帧深度纹理和视图”。关键点:

  • new(texture, previous_frame_texture, depth_clear_value, stencil_clear_value):当提供 previous_frame_texture 时,会对其调用 DepthStencilViews::from_texture 生成 previous_frame_depth_stencil_views,供时序类渲染技术(如需要读取上帧深度的 TAAO、动态 Mipmap 生成等)直接绑定;
  • depth_stencil_views():暴露当前帧的 &DepthStencilViews
  • get_attachment(store):委托给内部的 DepthStencilViewAttachment,签名带 StoreOp 参数;
  • prepare_for_new_frame():同样委托,用于帧间清除状态管理。

previous_frame_texture 字段与同文件中的 ColorAttachmentcrates/bevy_render/src/texture/texture_attachment.rs)的 previous_frame_texture 设计相呼应,使深度附件也能统一支持双缓冲式“上帧纹”访问。

ViewDepthTexture 更名:ViewDepthStencilTexture

相机主 Pass 使用的深度纹组件 ViewDepthTexture 更名为 ViewDepthStencilTexture,定义于 crates/bevy_render/src/view/mod.rs

#[derive(Component)]
pub struct ViewDepthStencilTexture {
    pub attachment: DepthStencilAttachment,
}

impl ViewDepthStencilTexture {
    pub fn new(
        texture: CachedTexture,
        depth_clear_value: Option<f32>,
        stencil_clear_value: Option<u32>,
    ) -> Self {
        let attachment =
            DepthStencilAttachment::new(texture, None, depth_clear_value, stencil_clear_value);
        Self { attachment }
    }

    pub fn texture(&self) -> &Texture {
        &self.attachment.texture.texture
    }

    pub fn get_attachment(&self, store: StoreOp) -> RenderPassDepthStencilAttachment<'_> {
        self.attachment.get_attachment(store)
    }
}

迁移要点:

  • ECS 查询中所有 &ViewDepthTexture / With<ViewDepthTexture> 等用法需替换为 &ViewDepthStencilTexture
  • 需要底层 Texture 的地方可继续调用 texture()
  • 挂载到 Pass 时通过 get_attachment(store) 获取,CachedTexture 与视图细节收敛到 attachment 字段内部。

仓库内已有调用方完成了这一迁移,可作为参照:3D 主 Pass 的纹准备在 crates/bevy_core_pipeline/src/core_3d/mod.rs 中插入 ViewDepthStencilTexture::new(...),2D 主 Pass 同理见 crates/bevy_core_pipeline/src/core_2d/mod.rs;延迟渲染 Pass 则在 crates/bevy_core_pipeline/src/deferred/node.rs 中通过 &ViewDepthStencilTexture 查询并将 &ViewDepthStencilTexture 传入绑定组构建函数;主不透明/透明 Pass 的节点(如 crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rscrates/bevy_core_pipeline/src/core_2d/main_opaque_pass_2d_node.rs)的静态查询列表也已改用 &ViewDepthStencilTexture

ViewPrepassTextures::depth 类型变更

Prepass 产物组件 ViewPrepassTextures 定义于 crates/bevy_core_pipeline/src/prepass/mod.rs

/// Textures that are written to by the prepass.
///
/// This component will only be present if any of the relevant prepass
/// components are also present.
#[derive(Component)]
pub struct ViewPrepassTextures {
    /// The depth texture generated by the prepass.
    /// Exists only if [`DepthPrepass`] is added to the [`ViewTarget`]
    pub depth: Option<DepthStencilAttachment>,
    /// The normals texture generated by the prepass.
    pub normal: Option<ColorAttachment>,
    /// The motion vectors texture generated by the prepass.
    pub motion_vectors: Option<ColorAttachment>,
    /// The deferred gbuffer generated by the deferred pass.
    pub deferred: Option<ColorAttachment>,
    /// A texture that specifies the deferred lighting pass id for a material.
    pub deferred_lighting_pass_id: Option<ColorAttachment>,
    /// The size of the textures.
    pub size: Extent3d,
}

原文档指出 depth 字段从 Option<ColorAttachment> 变为 Option<DepthStencilAttachment>。这意味着此前借道颜色附加体类型持有深度 Prepass 产物的写法被取消,深度 Prepass 的纹现在具有完整的深度/模板视图语义。组件同时提供两个便捷访问器,把 DepthStencilViews 的接口“上浮”到 Prepass 层面(crates/bevy_core_pipeline/src/prepass/mod.rs):

impl ViewPrepassTextures {
    pub fn depth_only_view(&self) -> Option<&TextureView> {
        self.depth
            .as_ref()
            .and_then(|t| t.depth_stencil_views().depth_only_view())
    }

    pub fn previous_depth_only_view(&self) -> Option<&TextureView> {
        self.depth.as_ref().and_then(|t| {
            t.previous_frame_depth_stencil_views
                .as_ref()
                .and_then(|views| views.depth_only_view())
        })
    }
    ...
}

即:绑定着色器资源时用 depth_only_view() / previous_depth_only_view() 获取单 aspect 视图,而不是直接拿 default view 去绑定——这与开头“按用途选视图”的兼容性建议一脉相承。仓库内的实际使用示例见动态 Mipmap 生成的实验性深度路径 crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs,其中同时查询了当前帧与上一帧的深度视图;模板视图的消费方还包括 crates/bevy_pbr/src/render/light.rs 中对 DepthStencilViews 的引用(光影/阴影路径下按视图类型分别取用)。

迁移检查清单

对下游自定义 Pass 或扩展渲染插件,可按以下清单迁移:

  1. 类型替换DepthAttachmentDepthStencilViewAttachmentViewDepthTextureViewDepthStencilTexture(包括 With<...>Without<...> 过滤器与查询元组中的引用);
  2. 构造参数补全:涉及深度附件构造的位置,为 depth_clear_value 之外补充 stencil_clear_value 参数;纯深度场景传 None 即可;
  3. 视图选择:凡原来直接把深度 TextureView 绑进着色器的代码,改为取 depth_only_view()(单 aspect、可绑定);作为渲染附加体挂载的代码,走 get_attachment(store)attachment_view()(全 aspect、可渲染);
  4. Prepass 深度访问ViewPrepassTextures::depth 不再是 ColorAttachment,取纹请用 .depth_stencil_views(),取可绑定视图请用 depth_only_view() / previous_depth_only_view()
  5. 格式前提:传给这些类型的 CachedTexture 必须是深度或模板格式,否则 DepthStencilViews::from_texture 会 panic。

小结

本次变更把 Bevy 的深度附加体系从“单一深度视图”重构为“深度/模板双面、多视图”模型:DepthStencilViews 按纹理格式自动派生 combined / depth-only / stencil-only 三类视图并明确各自的可渲染/可绑定边界;DepthStencilViewAttachment 为两个面提供独立的首次清除语义;DepthStencilAttachment 在更高层封装 CachedTexture 与上帧视图,支撑双缓冲式时序技术。核心实现集中在 crates/bevy_render/src/texture/texture_attachment.rscrates/bevy_render/src/view/mod.rs,Prepass 侧的落地见 crates/bevy_core_pipeline/src/prepass/mod.rs,配合迁移指南 _release-content/migration-guides/depth_attachment_changes.md 即可完整完成自定义渲染代码的升级。

登录后查看全文
热门项目推荐
相关项目推荐