From 727b0f6e2747192f42a42d90e679b96c439baeb9 Mon Sep 17 00:00:00 2001 From: James Gayfer <10660608+jgayfer@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:04:13 -0700 Subject: [PATCH] Use dynamic uniform buffer in post processing example (#13540) # Objective 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 shader (as the combination of `ExtractComponentPlugin` and `UniformComponentPlugin` extracts + sends _all_ of our `PostProcessSetting` components to the GPU). The goal of this PR is to clarify how to target the view specific `PostProcessSettings` in the shader when there are multiple cameras. ## Solution To accomplish this, we can use a dynamic uniform buffer for `PostProcessSettings`, querying for the relevant `DynamicUniformIndex` in the `PostProcessNode` to get the relevant index to use with the bind group. 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). ## Testing - Run the `post_processing` example before and after this change, verifying they behave the same. ## Reviewer notes This is my first PR to Bevy, and I'm by no means an expert in the world of rendering (though I'm trying to learn all I can). If there's a better way to do this / a reason not to take this route, I'd love to hear it! Thanks in advance. --- 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 b3b7330bca..f42e8075ce 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), ), ), );