bevy_core_pipeline/motion_blur/
node.rs1use bevy_ecs::{query::QueryItem, world::World};
2use bevy_render::{
3 extract_component::ComponentUniforms,
4 globals::GlobalsBuffer,
5 render_graph::{NodeRunError, RenderGraphContext, ViewNode},
6 render_resource::{
7 BindGroupEntries, Operations, PipelineCache, RenderPassColorAttachment,
8 RenderPassDescriptor,
9 },
10 renderer::RenderContext,
11 view::{Msaa, ViewTarget},
12};
13
14use crate::prepass::ViewPrepassTextures;
15
16use super::{
17 pipeline::{MotionBlurPipeline, MotionBlurPipelineId},
18 MotionBlur,
19};
20
21#[derive(Default)]
22pub struct MotionBlurNode;
23
24impl ViewNode for MotionBlurNode {
25 type ViewQuery = (
26 &'static ViewTarget,
27 &'static MotionBlurPipelineId,
28 &'static ViewPrepassTextures,
29 &'static MotionBlur,
30 &'static Msaa,
31 );
32 fn run(
33 &self,
34 _graph: &mut RenderGraphContext,
35 render_context: &mut RenderContext,
36 (view_target, pipeline_id, prepass_textures, motion_blur, msaa): QueryItem<Self::ViewQuery>,
37 world: &World,
38 ) -> Result<(), NodeRunError> {
39 if motion_blur.samples == 0 || motion_blur.shutter_angle <= 0.0 {
40 return Ok(()); }
42
43 let motion_blur_pipeline = world.resource::<MotionBlurPipeline>();
44 let pipeline_cache = world.resource::<PipelineCache>();
45 let settings_uniforms = world.resource::<ComponentUniforms<MotionBlur>>();
46 let Some(pipeline) = pipeline_cache.get_render_pipeline(pipeline_id.0) else {
47 return Ok(());
48 };
49
50 let Some(settings_binding) = settings_uniforms.uniforms().binding() else {
51 return Ok(());
52 };
53 let (Some(prepass_motion_vectors_texture), Some(prepass_depth_texture)) =
54 (&prepass_textures.motion_vectors, &prepass_textures.depth)
55 else {
56 return Ok(());
57 };
58 let Some(globals_uniforms) = world.resource::<GlobalsBuffer>().buffer.binding() else {
59 return Ok(());
60 };
61
62 let post_process = view_target.post_process_write();
63
64 let layout = if msaa.samples() == 1 {
65 &motion_blur_pipeline.layout
66 } else {
67 &motion_blur_pipeline.layout_msaa
68 };
69
70 let bind_group = render_context.render_device().create_bind_group(
71 Some("motion_blur_bind_group"),
72 layout,
73 &BindGroupEntries::sequential((
74 post_process.source,
75 &prepass_motion_vectors_texture.texture.default_view,
76 &prepass_depth_texture.texture.default_view,
77 &motion_blur_pipeline.sampler,
78 settings_binding.clone(),
79 globals_uniforms.clone(),
80 )),
81 );
82
83 let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
84 label: Some("motion_blur_pass"),
85 color_attachments: &[Some(RenderPassColorAttachment {
86 view: post_process.destination,
87 resolve_target: None,
88 ops: Operations::default(),
89 })],
90 depth_stencil_attachment: None,
91 timestamp_writes: None,
92 occlusion_query_set: None,
93 });
94
95 render_pass.set_render_pipeline(pipeline);
96 render_pass.set_bind_group(0, &bind_group, &[]);
97 render_pass.draw(0..3, 0..1);
98
99 Ok(())
100 }
101}