wgpu 保守光栅化实战:用 CONSERVATIVE_RASTERIZATION 特性渲染"被触碰到的每一个像素"
【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu
本文以 wgpu 官方示例conservative_raster为蓝本,完整拆解保守光栅化(conservative rasterization)的工作原理与 API 用法:如何声明CONSERVATIVE_RASTERIZATION特性、如何通过PrimitiveState::conservative开启"超集光栅",以及示例中"低分辨率渲染 + 最近邻放大 + 轮廓描边"的演示方案。读完后你可以独立在自己的 wgpu 项目中启用该特性,理解其平台支持边界(Vulkan/DirectX 12 原生特性)与管线创建时的校验规则,为体积光栅化(voxelization)等高级技术打下基础。
什么是保守光栅化
标准光栅化遵循"覆盖测试"语义:只有像素中心落在三角形内部的像素才会被着色器写入。保守光栅化则把语义扩展为超集——只要三角形与像素发生任何接触(哪怕只碰到一个角),该像素就会被光栅化、执行片元着色器。
用 PrimitiveState 的文档注释描述,即 "the primitives are rendered with conservative overestimation. I.e. any rastered pixel touched by it is filled"(原语以保守超集方式渲染,即凡是被其触碰的像素都会被填充)。
这一能力对"像素是否被某原语覆盖"敏感的技术至关重要,最典型的应用是实时体积光栅化(realtime voxelization):需要保证三角形扫过的所有体素都被检测到,绝不能漏掉边缘像素。wgpu 的 conservative_raster 示例 正是围绕这一点做的可视化演示。
运行方式与特性要求
在仓库根目录执行示例(README 中给出的命令):
cargo run --bin wgpu-examples conservative_raster从 examples/features/src/conservative_raster/mod.rs 的framework::Example实现可以看到示例对设备特性的声明:
- 必需特性:
wgpu::Features::CONSERVATIVE_RASTERIZATION(required_features()); - 可选特性:
wgpu::Features::POLYGON_MODE_LINE(optional_features()),仅用于在原始分辨率下绘制三角形白色轮廓线,不支持时优雅降级。
该特性在 wgpu-types/src/features.rs 中的定义值得注意:
/// Allows the user to set a overestimation-conservative-rasterization in [`PrimitiveState::conservative`] /// /// Processing of degenerate triangles/lines is hardware specific. /// Only triangles are supported. /// /// Supported platforms: /// - Vulkan /// /// This is a native only feature. #[name("wgpu-conservative-rasterization", "conservative-rasterization")] const CONSERVATIVE_RASTERIZATION = 1 << 21;要点有三:
- 仅原生平台可用(native only),WebGPU 后端不提供;
- 文档标注的参考平台是Vulkan(依赖
VK_EXT_conservative_rasterization扩展,见下文后端章节),Direct3D 12 后端同样接入了该特性(见 wgpu-hal/src/dx12/device.rs); - 只支持三角形;退化三角形/线的处理行为由具体硬件决定。
因此如果你的目标设备是 macOS(Metal)或 GLES 环境,从源码结构看该特性不会被报告为支持,示例会因特性不满足而无法运行——这是使用该 API 前必须确认的前提。
核心 API:PrimitiveState::conservative
在创建渲染管线时,只需在PrimitiveState中打开conservative字段即可:
primitive: wgpu::PrimitiveState { conservative: true, ..Default::default() },PrimitiveState 中与本主题相关的字段及约束:
| 字段 | 含义 | 约束 |
|---|---|---|
conservative: bool | 设为true时以保守超集方式光栅化原语 | 需要启用Features::CONSERVATIVE_RASTERIZATION;仅在PolygonMode::Fill下有效 |
polygon_mode: PolygonMode | 默认Fill,可选Line/Point | Line需POLYGON_MODE_LINE,Point需POLYGON_MODE_POINT |
这些约束在管线创建时被 wgpu-core 强制校验:
if desc.primitive.conservative { self.require_features(wgt::Features::CONSERVATIVE_RASTERIZATION)?; } if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill { return Err( pipeline::CreateRenderPipelineError::ConservativeRasterizationNonFillPolygonMode, ); }即:未声明特性却开启conservative会在创建管线时报错;把保守光栅化与Line/Point多边形模式组合同样非法。在业务代码中应先用adapter.features().contains(...)探测能力再决定是否走保守路径,这也是示例把线条轮廓处理成"可选管线"的原因。
示例实现详解:用颜色差异可视化保守像素
示例的演示思路(来自 README):把三角形先渲染到低分辨率目标上,再用最近邻过滤放大到全屏;只有开启保守光栅化才会画出的像素显示为红色,常规光栅化画出的部分为蓝色,三角形轮廓以白色线条在原始分辨率下描出。
四条渲染管线
mod.rs 在init()中构建 4 条管线,全部共用同一个着色器模块triangle_and_lines.wgsl:
| 管线 | 片元入口 | 目标 | 关键配置 |
|---|---|---|---|
pipeline_triangle_conservative | fs_main_red | 低分辨率目标 | conservative: true |
pipeline_triangle_regular | fs_main_blue | 低分辨率目标 | 默认(conservative: false) |
pipeline_upscale | fs_main(upscale.wgsl) | 全屏窗口 | 采样低分辨率纹理 |
pipeline_lines(Option) | fs_main_white | 全屏窗口 | PolygonMode::Line+LineStrip |
两个三角形管线使用相同的顶点着色器(vs_main),因此覆盖区域完全对齐,颜色差异纯粹来自光栅化语义——红色像素即"保守超集减去常规覆盖"的部分。
低分辨率目标:1/16 降采样
create_low_res_target()(mod.rs L15-L61)创建一张尺寸为窗口width/16 × height/16(最小 1×1)的Rgba8UnormSrgb纹理,用法为TEXTURE_BINDING | RENDER_ATTACHMENT,并配套一个FilterMode::Nearest的采样器,打包成两个绑定的 BindGroup(binding 0: 纹理视图,binding 1: 采样器)。
降采样到 1/16 是有意的:像素块越大,光栅化边缘处"常规 vs 保守"的差异越醒目,肉眼即可分辨红色超集像素。resize()回调中会重建该目标与 BindGroup,保证窗口尺寸变化后比例一致。
每帧渲染流程
render()(mod.rs L256-L313)在一个命令编码器里顺序执行两个渲染通道:
- 低分辨率通道:清屏为黑色后,先用保守管线
draw(0..3, 0..1)画红色三角形,再切到常规管线draw(0..3, 0..1)画蓝色三角形。由于没有深度测试,后画的蓝色会覆盖重叠的常规覆盖区域,仅保守超集部分保留红色; - 全屏分辨率通道:先清屏,用
pipeline_upscale全屏四边形(draw(0..3, 0..1)+ 绑定 upscale BindGroup)把低分辨率结果最近邻放大;若POLYGON_MODE_LINE可用,再切换线条管线draw(0..4, 0..1)描出白色三角形轮廓——注意这里画了 4 个顶点而非 3 个,因为顶点着色器对索引取vertex_index % 3,第 4 个顶点恰好回到第 1 个顶点,闭合LineStrip。
WGSL 着色器
triangle_and_lines.wgsl 用纯程序化顶点(无顶点缓冲)生成一个不对称三角形:
@vertex fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> { let i: i32 = i32(vertex_index % 3u); let x: f32 = f32(i - 1) * 0.75; let y: f32 = f32((i & 1) * 2 - 1) * 0.75 + x * 0.2 + 0.1; return vec4<f32>(x, y, 0.0, 1.0); }三个片元入口分别返回纯红、矢车菊蓝(注释标明是线性空间取值)和白色常量,逻辑极简,把演示重点完全让位给光栅化行为本身。
upscale.wgsl 则是标准的全屏放大:顶点着色器用vertex_index的位运算构造覆盖 NDC 的屏幕四边形并生成纹理坐标,片元着色器对低分辨率纹理做最近邻采样:
@fragment fn fs_main(vertex: VertexOutput) -> @location(0) vec4<f32> { return textureSample(r_color, r_sampler, vertex.tex_coords); }对应的绑定布局在 Rust 侧声明为不可过滤的浮点纹理(sample_type: Float { filterable: false })加NonFiltering采样器,与最近邻采样严格匹配。
后端实现:特性如何落到硬件
从源码结构看,该特性最终映射到各图形 API 的原生机制:
- Vulkan:wgpu-hal/src/vulkan/adapter.rs 通过查询
VK_EXT_conservative_rasterization扩展支持来填充能力位,请求该特性时(adapter.rs L1448-L1450)在设备创建时启用对应扩展;管线创建时(wgpu-hal/src/vulkan/device.rs)向VkPipelineRasterizationStateCreateInfo链入VkPipelineRasterizationConservativeStateEXT并置位rasterizerConservativeFill。这也是 features 文档将 Vulkan 列为支持平台的原因; - DirectX 12:wgpu-hal/src/dx12/device.rs 中
D3D12_RASTERIZER_DESC::ConservativeRaster直接对应desc.primitive.conservative,D3D12 硬件原生支持保守填充,无需扩展。
无头测试:截图回归
示例文件末尾还注册了一个无头测试(mod.rs L320-L331):
pub static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { name: "conservative-raster", image_path: "/examples/features/src/conservative_raster/screenshot.png", width: 1024, height: 768, ... };CI 会以 1024×768 窗口运行示例并与仓库内的 screenshot.png 做图像比对。需要留意:因为保守像素的具体位置依赖硬件光栅化器实现,该比对用于回归"渲染结果整体一致",而非逐像素精确断言——这也侧面印证了特性文档中"退化情形处理由硬件决定"的说法。
小结
- 保守光栅化通过
PrimitiveState { conservative: true, .. }开启,前提是设备支持Features::CONSERVATIVE_RASTERIZATION(原生特性,参考平台 Vulkan/D3D12,且仅限PolygonMode::Fill的三角形); - 它输出的是"触碰即覆盖"的像素超集,是体积光栅化、覆盖检测等技术的基石;
- 示例通过 1/16 降采样 + 最近邻放大 + 双管线(红/蓝)对比 + 可选白线描边,把这个抽象语义变成了肉眼可辨的可视化;
- 使用前务必先探测适配器特性,对不支持的平台(如 WebGPU、Metal 环境)预留降级路径,这正是示例将
POLYGON_MODE_LINE与线条管线处理为可选项的同款思路。
【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考