You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从OpenGL迁移至WGPU:如何在清除前设置Scissor Rectangle?

WGPU中实现局部清除(模拟OpenGL的Scissor清除效果)

WGPU的LoadOp::Clear操作是针对整个纹理视图生效的,后续设置的Scissor不会影响这个清除动作,所以你当前的代码会把整个帧缓冲区都清掉。要实现只清除指定区域的需求,有两种可行方案:

方案一:加载原有内容后,用Scissor裁剪绘制清除颜色

这种方式是先保留帧缓冲区的全部内容,再通过Scissor限制绘制范围,用清除颜色填充目标区域:

  1. 将颜色附件的load操作改为LoadOp::Load,保留原帧内容
  2. 设置Scissor到需要清除的区域
  3. 绘制一个覆盖Scissor区域的四边形(用全屏四边形即可,Scissor会自动裁剪掉超出范围的部分)

修改后的代码示例:

let mut render_pass = encoder.begin_render_pass(
    &wgpu::RenderPassDescriptor {
        label: Some("Render Pass"),
        color_attachments: &[Some(
            wgpu::RenderPassColorAttachment {
                view: &view,
                resolve_target: None,
                ops: wgpu::Operations {
                    load: wgpu::LoadOp::Load, // 保留原有帧内容
                    store: true,
                },
            }
        )],
        depth_stencil_attachment: None,
    }
);

// 设置Scissor到目标区域
render_pass.set_scissor_rect(
    render_area.x,
    render_area.y,
    render_area.width(), 
    render_area.height()
);

// 设置清除颜色的管线(提前创建好的纯色填充管线)
render_pass.set_pipeline(&clear_pipeline);
// 绘制全屏四边形(可通过无索引绘制实现)
render_pass.draw(0..6, 0..1);

// 后续执行你的正常渲染操作
// ...

render_pass.end();

这里的clear_pipeline需要提前创建:顶点着色器输出全屏顶点,片段着色器输出你需要的清除颜色(r:0.04, g:0.08, b:0.08, a:1.0)。

方案二:创建子纹理视图,针对子视图执行清除

如果不想额外绘制四边形,可以创建原纹理的子视图,只包含需要清除的区域,然后针对这个子视图执行LoadOp::Clear:

  1. 根据需要清除的区域,创建原纹理的子视图
  2. 先执行一个针对子视图的RenderPass,完成局部清除
  3. 再执行正常的渲染Pass,使用完整的纹理视图

代码示例:

// 创建子纹理视图,对应需要清除的区域
let clear_view = view.texture.create_view(&wgpu::TextureViewDescriptor {
    label: Some("Clear Subview"),
    format: None,
    dimension: None,
    aspect: wgpu::TextureAspect::All,
    base_mip_level: 0,
    mip_level_count: None,
    base_array_layer: 0,
    array_layer_count: None,
    view_dimension: wgpu::TextureViewDimension::D2,
    bounds: wgpu::ImageSubresourceRange {
        aspect: wgpu::TextureAspect::All,
        base_mip_level: 0,
        mip_level_count: 1,
        base_array_layer: 0,
        array_layer_count: 1,
    },
    offset: wgpu::Origin3d {
        x: render_area.x,
        y: render_area.y,
        z: 0,
    },
    size: wgpu::Extent3d {
        width: render_area.width(),
        height: render_area.height(),
        depth_or_array_layers: 1,
    },
});

// 第一个Pass:清除子视图区域
let mut clear_pass = encoder.begin_render_pass(
    &wgpu::RenderPassDescriptor {
        label: Some("Clear Pass"),
        color_attachments: &[Some(
            wgpu::RenderPassColorAttachment {
                view: &clear_view,
                resolve_target: None,
                ops: wgpu::Operations {
                    load: wgpu::LoadOp::Clear(
                        wgpu::Color {
                            r: 0.04,
                            g: 0.08,
                            b: 0.08,
                            a: 1.0,
                        }
                    ),
                    store: true,
                },
            }
        )],
        depth_stencil_attachment: None,
    }
);
clear_pass.end();

// 第二个Pass:执行正常渲染操作
let mut render_pass = encoder.begin_render_pass(
    &wgpu::RenderPassDescriptor {
        label: Some("Render Pass"),
        color_attachments: &[Some(
            wgpu::RenderPassColorAttachment {
                view: &view,
                resolve_target: None,
                ops: wgpu::Operations {
                    load: wgpu::LoadOp::Load, // 加载已完成局部清除的帧内容
                    store: true,
                },
            }
        )],
        depth_stencil_attachment: None,
    }
);

// 设置Scissor并执行你的渲染逻辑
render_pass.set_scissor_rect(
    render_area.x,
    render_area.y,
    render_area.width(), 
    render_area.height()
);
// ... 你的渲染代码

render_pass.end();

方案对比

  • 方案一更适合需要频繁变更清除区域的场景,不需要额外创建纹理视图,只需要维护一个简单的清除管线
  • 方案二更适合固定清除区域的场景,利用硬件的清除操作,性能略优,但需要额外管理子视图

内容的提问来源于stack exchange,提问作者Gustav Nilsson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:20:43