From 925ade1ef789fd4dc804507c462fa8e42c509119 Mon Sep 17 00:00:00 2001 From: James Gayfer <10660608+jgayfer@users.noreply.github.com> Date: Mon, 27 May 2024 12:54:59 -0700 Subject: [PATCH] Use dynamic uniform buffer for post process settings While learning about shaders and pipelines, I found this example to be misleading; it wasn't clear to me how the node knew what the correct "instance" of `PostProcessSettings` we should send to the GPU (as the combination of `ExtractComponentPlugin` and `UniformComponentPlugin` extracts + sends _all_ of our `PostProcessSetting` components). While the example in its current state is _correct_, I believe that fact that it's intended to showcase a per camera post processing effect warrants a dynamic uniform buffer (even though in the context of this example we have only one camera, and therefore no adverse behaviour). --- examples/shader/post_processing.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/shader/post_processing.rs b/examples/shader/post_processing.rs index b3b7330bca8fe..f42e8075ce7e4 100644 --- a/examples/shader/post_processing.rs +++ b/examples/shader/post_processing.rs @@ -15,7 +15,8 @@ use bevy::{ prelude::*, render::{ extract_component::{ - ComponentUniforms, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin, + ComponentUniforms, DynamicUniformIndex, ExtractComponent, ExtractComponentPlugin, + UniformComponentPlugin, }, render_graph::{ NodeRunError, RenderGraphApp, RenderGraphContext, RenderLabel, ViewNode, ViewNodeRunner, @@ -124,6 +125,9 @@ impl ViewNode for PostProcessNode { &'static ViewTarget, // This makes sure the node only runs on cameras with the PostProcessSettings component &'static PostProcessSettings, + // As there could be multiple post processing components sent to the GPU (one per camera), + // we need to get the index of the one that is associated with the current view. + &'static DynamicUniformIndex, ); // Runs the node logic @@ -137,7 +141,7 @@ impl ViewNode for PostProcessNode { &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (view_target, _post_process_settings): QueryItem, + (view_target, _post_process_settings, settings_index): QueryItem, world: &World, ) -> Result<(), NodeRunError> { // Get the pipeline resource that contains the global data we need @@ -209,7 +213,10 @@ impl ViewNode for PostProcessNode { // This is mostly just wgpu boilerplate for drawing a fullscreen triangle, // using the pipeline/bind_group created above render_pass.set_render_pipeline(pipeline); - render_pass.set_bind_group(0, &bind_group, &[]); + // By passing in the index of the post process settings on this view, we ensure + // that in the event that multiple settings were sent to the GPU (as would be the + // case with multiple cameras), we use the correct one. + render_pass.set_bind_group(0, &bind_group, &[settings_index.index()]); render_pass.draw(0..3, 0..1); Ok(()) @@ -240,7 +247,7 @@ impl FromWorld for PostProcessPipeline { // The sampler that will be used to sample the screen texture sampler(SamplerBindingType::Filtering), // The settings uniform that will control the effect - uniform_buffer::(false), + uniform_buffer::(true), ), ), );