Use RenderStartup in custom_post_processing example (#19886)
# Objective - This example uses a FromWorld impl to initialize a resource on startup - #19887 ## Solution - Use RenderStartup instead ## Testing - The example still works as expected
This commit is contained in:
parent
83cd46a4dd
commit
735eb88db9
@ -27,7 +27,7 @@ use bevy::{
|
|||||||
},
|
},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
view::ViewTarget,
|
view::ViewTarget,
|
||||||
RenderApp,
|
RenderApp, RenderStartup,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,6 +66,10 @@ impl Plugin for PostProcessPlugin {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RenderStartup runs once on startup after all plugins are built
|
||||||
|
// It is useful to initialize data that will only live in the RenderApp
|
||||||
|
render_app.add_systems(RenderStartup, setup_pipeline);
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
// Bevy's renderer uses a render graph which is a collection of nodes in a directed acyclic graph.
|
// Bevy's renderer uses a render graph which is a collection of nodes in a directed acyclic graph.
|
||||||
// It currently runs on each view/camera and executes each node in the specified order.
|
// It currently runs on each view/camera and executes each node in the specified order.
|
||||||
@ -97,17 +101,6 @@ impl Plugin for PostProcessPlugin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self, app: &mut App) {
|
|
||||||
// We need to get the render app from the main app
|
|
||||||
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
render_app
|
|
||||||
// Initialize the pipeline
|
|
||||||
.init_resource::<PostProcessPipeline>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
|
||||||
@ -233,69 +226,67 @@ struct PostProcessPipeline {
|
|||||||
pipeline_id: CachedRenderPipelineId,
|
pipeline_id: CachedRenderPipelineId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWorld for PostProcessPipeline {
|
fn setup_pipeline(
|
||||||
fn from_world(world: &mut World) -> Self {
|
mut commands: Commands,
|
||||||
let render_device = world.resource::<RenderDevice>();
|
render_device: Res<RenderDevice>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
// We need to define the bind group layout used for our pipeline
|
fullscreen_shader: Res<FullscreenShader>,
|
||||||
let layout = render_device.create_bind_group_layout(
|
pipeline_cache: Res<PipelineCache>,
|
||||||
"post_process_bind_group_layout",
|
) {
|
||||||
&BindGroupLayoutEntries::sequential(
|
// We need to define the bind group layout used for our pipeline
|
||||||
// The layout entries will only be visible in the fragment stage
|
let layout = render_device.create_bind_group_layout(
|
||||||
ShaderStages::FRAGMENT,
|
"post_process_bind_group_layout",
|
||||||
(
|
&BindGroupLayoutEntries::sequential(
|
||||||
// The screen texture
|
// The layout entries will only be visible in the fragment stage
|
||||||
texture_2d(TextureSampleType::Float { filterable: true }),
|
ShaderStages::FRAGMENT,
|
||||||
// The sampler that will be used to sample the screen texture
|
(
|
||||||
sampler(SamplerBindingType::Filtering),
|
// The screen texture
|
||||||
// The settings uniform that will control the effect
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
uniform_buffer::<PostProcessSettings>(true),
|
// The sampler that will be used to sample the screen texture
|
||||||
),
|
sampler(SamplerBindingType::Filtering),
|
||||||
|
// The settings uniform that will control the effect
|
||||||
|
uniform_buffer::<PostProcessSettings>(true),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
// We can create the sampler here since it won't change at runtime and doesn't depend on the view
|
||||||
|
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
||||||
|
|
||||||
// We can create the sampler here since it won't change at runtime and doesn't depend on the view
|
// Get the shader handle
|
||||||
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
let shader = asset_server.load(SHADER_ASSET_PATH);
|
||||||
|
// This will setup a fullscreen triangle for the vertex state.
|
||||||
// Get the shader handle
|
let vertex_state = fullscreen_shader.to_vertex_state();
|
||||||
let shader = world.load_asset(SHADER_ASSET_PATH);
|
let pipeline_id = pipeline_cache
|
||||||
// This will setup a fullscreen triangle for the vertex state.
|
// This will add the pipeline to the cache and queue its creation
|
||||||
let vertex_state = world.resource::<FullscreenShader>().to_vertex_state();
|
.queue_render_pipeline(RenderPipelineDescriptor {
|
||||||
|
label: Some("post_process_pipeline".into()),
|
||||||
let pipeline_id = world
|
layout: vec![layout.clone()],
|
||||||
.resource_mut::<PipelineCache>()
|
vertex: vertex_state,
|
||||||
// This will add the pipeline to the cache and queue its creation
|
fragment: Some(FragmentState {
|
||||||
.queue_render_pipeline(RenderPipelineDescriptor {
|
shader,
|
||||||
label: Some("post_process_pipeline".into()),
|
shader_defs: vec![],
|
||||||
layout: vec![layout.clone()],
|
// Make sure this matches the entry point of your shader.
|
||||||
vertex: vertex_state,
|
// It can be anything as long as it matches here and in the shader.
|
||||||
fragment: Some(FragmentState {
|
entry_point: "fragment".into(),
|
||||||
shader,
|
targets: vec![Some(ColorTargetState {
|
||||||
shader_defs: vec![],
|
format: TextureFormat::bevy_default(),
|
||||||
// Make sure this matches the entry point of your shader.
|
blend: None,
|
||||||
// It can be anything as long as it matches here and in the shader.
|
write_mask: ColorWrites::ALL,
|
||||||
entry_point: "fragment".into(),
|
})],
|
||||||
targets: vec![Some(ColorTargetState {
|
}),
|
||||||
format: TextureFormat::bevy_default(),
|
// All of the following properties are not important for this effect so just use the default values.
|
||||||
blend: None,
|
// This struct doesn't have the Default trait implemented because not all fields can have a default value.
|
||||||
write_mask: ColorWrites::ALL,
|
primitive: PrimitiveState::default(),
|
||||||
})],
|
depth_stencil: None,
|
||||||
}),
|
multisample: MultisampleState::default(),
|
||||||
// All of the following properties are not important for this effect so just use the default values.
|
push_constant_ranges: vec![],
|
||||||
// This struct doesn't have the Default trait implemented because not all fields can have a default value.
|
zero_initialize_workgroup_memory: false,
|
||||||
primitive: PrimitiveState::default(),
|
});
|
||||||
depth_stencil: None,
|
commands.insert_resource(PostProcessPipeline {
|
||||||
multisample: MultisampleState::default(),
|
layout,
|
||||||
push_constant_ranges: vec![],
|
sampler,
|
||||||
zero_initialize_workgroup_memory: false,
|
pipeline_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
|
||||||
layout,
|
|
||||||
sampler,
|
|
||||||
pipeline_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the component that will get passed to the shader
|
// This is the component that will get passed to the shader
|
||||||
|
Loading…
Reference in New Issue
Block a user