wgpu 多渲染目标(MRT)实战:一次 Render Pass 同时输出到多个颜色附件

发布时间:2026/9/14 4:28:37

wgpu 多渲染目标(MRT)实战:一次 Render Pass 同时输出到多个颜色附件 wgpu 多渲染目标MRT实战一次 Render Pass 同时输出到多个颜色附件【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu本指南以 wgpu 仓库中 multiple_render_targets 示例 为核心系统讲解如何在单个 Fragment Shader 中声明多个输出并让同一个 Render Pass 同时写入多个颜色附件。读完本文你将掌握 MRT 的完整实现路径从多目标渲染管线的ColorTargetState配置、WGSL 中多location输出的声明到离屏纹理的创建与分屏视口展示可直接复用到延迟着色、G-buffer 等需要一帧产出多张图的场景。示例目标与运行方式该示例的完整源码位于 mod.rs 与 shader.wgsl。它演示的核心能力是让片段着色器同时向一个 Render Pass 的两个颜色附件输出。具体流程是程序从零生成一张黑白球状径向渐变纹理数据片段着色器采样这张纹理并同时输出两个结果——第一个颜色附件收到红色版本第二个颜色附件收到绿色版本两张离屏纹理各自被渲染到屏幕左右两个视口viewport中分屏显示。运行示例只需在仓库根目录执行cargo run --bin wgpu-examples multiple_render_targets该示例在 examples/features/src/main.rs 中注册标记为webgpu: true, webgl: false——即支持原生 WebGPU 后端但 WebGL 后端不适用WebGL 2 对多渲染目标支持有限这也是 MRT 常用于 WebGPU 原生场景的原因。运行结果如下黑色背景下左半屏为红色渐变圆、右半屏为绿色渐变圆第一步从零生成黑白球状纹理示例没有加载外部图片而是用 CPU 代码逐像素生成一张 256×256 的R8Unorm灰度纹理mod.rsfn create_ball_texture_data(width: usize, height: usize) - Vecu8 { let mut img_data Vec::with_capacity(width * height); let center: glam::Vec2 glam::Vec2::new(width as f32 * 0.5, height as f32 * 0.5); let half_distance width as f32 * 0.5; for y in 0..width { for x in 0..height { let cur_pos glam::Vec2::new(x as f32, y as f32); let distance_to_center_normalized 1.0 - (cur_pos - center).length() / half_distance; let val: u8 (u8::MAX as f32 * distance_to_center_normalized) as u8; img_data.push(val) } } img_data }算法要点以图像中心为圆心像素离圆心越近1.0 - 距离/半宽越接近 1灰度值越高从而形成中心亮、边缘暗的径向渐变。生成的像素数据通过queue.write_texture上传到 GPU 纹理mod.rs。纹理描述符的关键点format: wgpu::TextureFormat::R8Unorm只需红色通道承载黑白数据usage: COPY_DST | TEXTURE_BINDING先作为拷贝目标写入再作为纹理被着色器采样。第二步用 ColorTargetState 配置多输出管线MRT 的关键一步是在创建渲染管线时通过FragmentState::targets提供一个与着色器输出一一对应的ColorTargetState数组mod.rsfragment: Some(wgpu::FragmentState { module: shader, entry_point: Some(fs_multi_main), targets: target_states, // 传入两个 ColorTargetState }),在Example::init中两个目标状态被构造为mod.rs[ Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: None, write_mask: Default::default(), }), Some(wgpu::ColorTargetState { format: config.view_formats[0], blend: None, write_mask: Default::default(), }), ]要点说明数组索引即输出索引targets[0]对应着色器中location(0)的输出targets[1]对应location(1)的输出格式必须匹配每个ColorTargetState.format必须与对应附件的纹理格式一致此处两者都使用表面配置config.view_formats[0]指定的格式blend: None与默认write_mask表示本次演示不启用混合、四通道全写。第三步WGSL 中的多输出片段着色器着色器侧shader.wgsl用结构体声明两个location输出struct FragmentOutput { location(0) red_target : vec4f32, location(1) green_target : vec4f32, } fragment fn fs_multi_main(vs: VertexOutput) - FragmentOutput { let smp textureSample(image_texture, image_sampler, vs.uv).x; var output: FragmentOutput; output.red_target vec4f32(smp, 0.0, 0.0, 1.0); output.green_target vec4f32(0.0, smp, 0.0, 1.0); return output; }逻辑非常直观textureSample取出黑白纹理的红色分量smp把它分别放入红色通道red和绿色通道green其余通道置零——于是同一个采样值被同时写进两个附件形成一红一绿两个渐变圆。顶点着色器vs_main只用builtin(vertex_index)生成一个覆盖全屏的三角形无需顶点缓冲并通过位运算技巧产出 UV 坐标vertex fn vs_main( builtin(vertex_index) vi: u32) - VertexOutput { var out: VertexOutput; out.uv vec2f32( f32((vi 1u) 2u), f32(vi 2u), ); out.clip_position vec4f32(out.uv * 2.0 - 1.0, 0.0, 1.0); out.uv.y 1.0 - out.uv.y; return out; }第四步创建带 RENDER_ATTACHMENT 用法的目标纹理要接收渲染输出离屏纹理必须同时具备TEXTURE_BINDING供后续采样显示和RENDER_ATTACHMENT作为颜色附件两种用途。示例的TextureTargets::new创建了两张完全相同的纹理mod.rslet red_texture device.create_texture(wgpu::TextureDescriptor { size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format, usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, view_formats: [format], });并分别创建对应纹理视图red_view、green_view存入TextureTargetsmod.rs。view_formats: [format]将视图格式显式声明为纹理格式本身便于后续以该格式创建视图。第五步一次 Render Pass 绑定两个颜色附件多输出的落地发生在MultiTargetRenderer::draw——向RenderPassDescriptor::color_attachments传入两个RenderPassColorAttachmentmod.rsfn draw(self, encoder: mut wgpu::CommandEncoder, targets: [Optionwgpu::RenderPassColorAttachment]) { let mut rpass encoder.begin_render_pass(wgpu::RenderPassDescriptor { color_attachments: targets, depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, multiview_mask: None, }); rpass.set_pipeline(self.pipeline); rpass.set_bind_group(0, self.bindgroup, []); rpass.draw(0..3, 0..1); }在render中两个附件分别指向红、绿纹理视图mod.rsself.multi_target_renderer.draw( mut encoder, [ Some(wgpu::RenderPassColorAttachment { view: self.texture_targets.red_view, depth_slice: None, resolve_target: None, ops: Default::default(), }), Some(wgpu::RenderPassColorAttachment { view: self.texture_targets.green_view, depth_slice: None, resolve_target: None, ops: Default::default(), }), ], );注意这里color_attachments数组的顺序必须与ColorTargetState、着色器location三者保持一致。一次draw调用即可同时写入两个附件这正是 MRT 相比“两次 Pass 两次纹理拷贝”的核心性能优势。第六步用两个视口分屏显示结果TargetRenderer负责把两张离屏纹理搬到屏幕。它创建了两个 Bind Group分别绑定red_view与green_viewmod.rs随后在同一帧内通过set_viewport切换左右半屏各自绘制一次mod.rs// draw results in two separate viewports that split the screen: rpass.set_viewport(0.0, 0.0, half_w, height, 0.0, 1.0); rpass.set_bind_group(0, self.bindgroup_left, []); rpass.draw(0..3, 0..1); rpass.set_viewport(half_w, 0.0, half_w, height, 0.0, 1.0); rpass.set_bind_group(0, self.bindgroup_right, []); rpass.draw(0..3, 0..1);其中half_w width * 0.5因此左视口覆盖[0, half_w]、右视口覆盖[half_w, width]实现左右对称分屏。展示管线的片段着色器fs_display_main直接采样纹理原样输出shader.wgslfragment fn fs_display_main(vs: VertexOutput) - location(0) vec4f32 { let smp textureSample(image_texture, image_sampler, vs.uv).xyz; return vec4f32(smp, 1.0); }窗口尺寸变化时Example::resize会按新尺寸重建TextureTargets并重建两个 Bind Groupmod.rs保证分屏始终铺满窗口。测试与验证示例自带 GPU 测试mod.rs通过wgpu_test::gpu_test!宏注册测试参数与截图基准对齐#[cfg(test)] #[wgpu_test::apply(wgpu_test::gpu_test!)] pub static TEST: crate::framework::ExampleTestParams crate::framework::ExampleTestParams { name: EXAMPLE_NAME, image_path: /examples/features/src/multiple_render_targets/screenshot.png, width: 1024, height: 768, ... comparisons: [wgpu_test::ComparisonType::Mean(0.014)], // Bounded by Apple A9 };该测试同时登记在 lib.rs 的all_tests()中会以 1024×768 渲染一帧并与截图做平均像素对比容差由软件光栅化器 lavapipe 与 Apple A9 的差异共同界定从测试侧验证了 MRT 渲染结果的可复现性。小结通过这个示例可以提炼出在 wgpu 中实现多渲染目标的三步固定套路着色器在 WGSL 片段着色器中用结构体声明多个location(n)输出管线FragmentState::targets传入与输出数量一致、格式匹配的ColorTargetState数组PassRenderPassDescriptor::color_attachments传入等量的RenderPassColorAttachment且保证索引顺序与着色器location一一对应。目标纹理需同时具备RENDER_ATTACHMENT | TEXTURE_BINDING用途才能“先被渲染、再被采样”。掌握这套流程后即可在此基础上扩展出延迟渲染 G-buffer法线/反照率/深度多张输出、多视图渲染等更复杂的应用。深入阅读源码可继续参考 mod.rs 与 shader.wgsl运行命令为cargo run --bin wgpu-examples multiple_render_targets【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/14 4:23:37

2026年人体工学椅选购黄金期:技术成熟度与国标落地交汇点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/14 5:08:39

MongoDB还是向量数据库?AI搜索选型指南与实战解析

先放结论:如果你问我现在给产品加一个AI搜索,是上向量数据库还是直接用MongoDB,我的回答是——大部分情况下,先用MongoDB的Atlas Vector Search把原型跑通,等数据量上来、查询复杂到MongoDB撑不住的时候,再…

2026/9/14 5:08:39

粒子群优化算法在电力系统最优潮流计算中的应用

1. 项目背景与核心价值电力系统最优潮流(Optimal Power Flow, OPF)是电力系统运行与控制中的经典问题。简单来说,就是在满足各种物理约束和运行限制的条件下,找到使系统运行成本最低、效率最高或者其它优化目标最优的发电调度方案…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码