ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

wgpu 保守光栅化实战:用 CONSERVATIVE_RASTERIZATION 特性渲染“被触碰到的每一个像素“

wgpu 保守光栅化实战:用 CONSERVATIVE_RASTERIZATION 特性渲染“被触碰到的每一个像素“ 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_RASTERIZATIONrequired_features()可选特性wgpu::Features::POLYGON_MODE_LINEoptional_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 onlyWebGPU 后端不提供文档标注的参考平台是Vulkan依赖VK_EXT_conservative_rasterization扩展见下文后端章节Direct3D 12 后端同样接入了该特性见 wgpu-hal/src/dx12/device.rs只支持三角形退化三角形/线的处理行为由具体硬件决定。因此如果你的目标设备是 macOSMetal或 GLES 环境从源码结构看该特性不会被报告为支持示例会因特性不满足而无法运行——这是使用该 API 前必须确认的前提。核心 APIPrimitiveState::conservative在创建渲染管线时只需在PrimitiveState中打开conservative字段即可primitive: wgpu::PrimitiveState { conservative: true, ..Default::default() },PrimitiveState 中与本主题相关的字段及约束字段含义约束conservative: bool设为true时以保守超集方式光栅化原语需要启用Features::CONSERVATIVE_RASTERIZATION仅在PolygonMode::Fill下有效polygon_mode: PolygonMode默认Fill可选Line/PointLine需POLYGON_MODE_LINEPoint需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_conservativefs_main_red低分辨率目标conservative: truepipeline_triangle_regularfs_main_blue低分辨率目标默认conservative: falsepipeline_upscalefs_mainupscale.wgsl全屏窗口采样低分辨率纹理pipeline_linesOptionfs_main_white全屏窗口PolygonMode::LineLineStrip两个三角形管线使用相同的顶点着色器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的采样器打包成两个绑定的 BindGroupbinding 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) vec4f32 { 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 vec4f32(x, y, 0.0, 1.0); }三个片元入口分别返回纯红、矢车菊蓝注释标明是线性空间取值和白色常量逻辑极简把演示重点完全让位给光栅化行为本身。upscale.wgsl 则是标准的全屏放大顶点着色器用vertex_index的位运算构造覆盖 NDC 的屏幕四边形并生成纹理坐标片元着色器对低分辨率纹理做最近邻采样fragment fn fs_main(vertex: VertexOutput) - location(0) vec4f32 { return textureSample(r_color, r_sampler, vertex.tex_coords); }对应的绑定布局在 Rust 侧声明为不可过滤的浮点纹理sample_type: Float { filterable: false }加NonFiltering采样器与最近邻采样严格匹配。后端实现特性如何落到硬件从源码结构看该特性最终映射到各图形 API 的原生机制Vulkanwgpu-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 12wgpu-hal/src/dx12/device.rs 中D3D12_RASTERIZER_DESC::ConservativeRaster直接对应desc.primitive.conservativeD3D12 硬件原生支持保守填充无需扩展。无头测试截图回归示例文件末尾还注册了一个无头测试mod.rs L320-L331pub 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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进