Path: blob/main/crates/bevy_post_process/src/motion_blur/pipeline.rs
9414 views
use bevy_asset::{load_embedded_asset, AssetServer, Handle};1use bevy_core_pipeline::FullscreenShader;2use bevy_ecs::{3component::Component,4entity::Entity,5query::With,6resource::Resource,7system::{Commands, Query, Res, ResMut},8};9use bevy_image::BevyDefault as _;10use bevy_render::{11globals::GlobalsUniform,12render_resource::{13binding_types::{14sampler, texture_2d, texture_2d_multisampled, texture_depth_2d,15texture_depth_2d_multisampled, uniform_buffer_sized,16},17BindGroupLayoutDescriptor, BindGroupLayoutEntries, CachedRenderPipelineId,18ColorTargetState, ColorWrites, FragmentState, PipelineCache, RenderPipelineDescriptor,19Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, ShaderType,20SpecializedRenderPipeline, SpecializedRenderPipelines, TextureFormat, TextureSampleType,21},22renderer::RenderDevice,23view::{ExtractedView, Msaa, ViewTarget},24};25use bevy_shader::{Shader, ShaderDefVal};26use bevy_utils::default;2728use super::MotionBlurUniform;2930#[derive(Resource)]31pub struct MotionBlurPipeline {32pub(crate) sampler: Sampler,33pub(crate) layout: BindGroupLayoutDescriptor,34pub(crate) layout_msaa: BindGroupLayoutDescriptor,35pub(crate) fullscreen_shader: FullscreenShader,36pub(crate) fragment_shader: Handle<Shader>,37}3839impl MotionBlurPipeline {40pub(crate) fn new(41render_device: &RenderDevice,42fullscreen_shader: FullscreenShader,43fragment_shader: Handle<Shader>,44) -> Self {45let mb_layout = &BindGroupLayoutEntries::sequential(46ShaderStages::FRAGMENT,47(48// View target (read)49texture_2d(TextureSampleType::Float { filterable: true }),50// Motion Vectors51texture_2d(TextureSampleType::Float { filterable: true }),52// Depth53texture_depth_2d(),54// Linear Sampler55sampler(SamplerBindingType::Filtering),56// Motion blur settings uniform input57uniform_buffer_sized(false, Some(MotionBlurUniform::min_size())),58// Globals uniform input59uniform_buffer_sized(false, Some(GlobalsUniform::min_size())),60),61);6263let mb_layout_msaa = &BindGroupLayoutEntries::sequential(64ShaderStages::FRAGMENT,65(66// View target (read)67texture_2d(TextureSampleType::Float { filterable: true }),68// Motion Vectors69texture_2d_multisampled(TextureSampleType::Float { filterable: false }),70// Depth71texture_depth_2d_multisampled(),72// Linear Sampler73sampler(SamplerBindingType::Filtering),74// Motion blur settings uniform input75uniform_buffer_sized(false, Some(MotionBlurUniform::min_size())),76// Globals uniform input77uniform_buffer_sized(false, Some(GlobalsUniform::min_size())),78),79);8081let sampler = render_device.create_sampler(&SamplerDescriptor::default());82let layout = BindGroupLayoutDescriptor::new("motion_blur_layout", mb_layout);83let layout_msaa = BindGroupLayoutDescriptor::new("motion_blur_layout_msaa", mb_layout_msaa);8485Self {86sampler,87layout,88layout_msaa,89fullscreen_shader,90fragment_shader,91}92}93}9495pub fn init_motion_blur_pipeline(96mut commands: Commands,97render_device: Res<RenderDevice>,98fullscreen_shader: Res<FullscreenShader>,99asset_server: Res<AssetServer>,100) {101let fullscreen_shader = fullscreen_shader.clone();102let fragment_shader = load_embedded_asset!(asset_server.as_ref(), "motion_blur.wgsl");103commands.insert_resource(MotionBlurPipeline::new(104&render_device,105fullscreen_shader,106fragment_shader,107));108}109110#[derive(PartialEq, Eq, Hash, Clone, Copy)]111pub struct MotionBlurPipelineKey {112hdr: bool,113samples: u32,114}115116impl SpecializedRenderPipeline for MotionBlurPipeline {117type Key = MotionBlurPipelineKey;118119fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {120let layout = match key.samples {1211 => vec![self.layout.clone()],122_ => vec![self.layout_msaa.clone()],123};124125let mut shader_defs = vec![];126127if key.samples > 1 {128shader_defs.push(ShaderDefVal::from("MULTISAMPLED"));129}130131#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]132{133shader_defs.push("NO_DEPTH_TEXTURE_SUPPORT".into());134shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into());135}136137RenderPipelineDescriptor {138label: Some("motion_blur_pipeline".into()),139layout,140vertex: self.fullscreen_shader.to_vertex_state(),141fragment: Some(FragmentState {142shader: self.fragment_shader.clone(),143shader_defs,144targets: vec![Some(ColorTargetState {145format: if key.hdr {146ViewTarget::TEXTURE_FORMAT_HDR147} else {148TextureFormat::bevy_default()149},150blend: None,151write_mask: ColorWrites::ALL,152})],153..default()154}),155..default()156}157}158}159160#[derive(Component)]161pub struct MotionBlurPipelineId(pub CachedRenderPipelineId);162163pub(crate) fn prepare_motion_blur_pipelines(164mut commands: Commands,165pipeline_cache: Res<PipelineCache>,166mut pipelines: ResMut<SpecializedRenderPipelines<MotionBlurPipeline>>,167pipeline: Res<MotionBlurPipeline>,168views: Query<(Entity, &ExtractedView, &Msaa), With<MotionBlurUniform>>,169) {170for (entity, view, msaa) in &views {171let pipeline_id = pipelines.specialize(172&pipeline_cache,173&pipeline,174MotionBlurPipelineKey {175hdr: view.hdr,176samples: msaa.samples(),177},178);179180commands181.entity(entity)182.insert(MotionBlurPipelineId(pipeline_id));183}184}185186187