Path: blob/main/crates/bevy_post_process/src/motion_blur/pipeline.rs
6596 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},17BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId, ColorTargetState,18ColorWrites, FragmentState, PipelineCache, RenderPipelineDescriptor, Sampler,19SamplerBindingType, SamplerDescriptor, ShaderStages, ShaderType, SpecializedRenderPipeline,20SpecializedRenderPipelines, 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: BindGroupLayout,34pub(crate) layout_msaa: BindGroupLayout,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 = render_device.create_bind_group_layout("motion_blur_layout", mb_layout);83let layout_msaa =84render_device.create_bind_group_layout("motion_blur_layout_msaa", mb_layout_msaa);8586Self {87sampler,88layout,89layout_msaa,90fullscreen_shader,91fragment_shader,92}93}94}9596pub fn init_motion_blur_pipeline(97mut commands: Commands,98render_device: Res<RenderDevice>,99fullscreen_shader: Res<FullscreenShader>,100asset_server: Res<AssetServer>,101) {102let fullscreen_shader = fullscreen_shader.clone();103let fragment_shader = load_embedded_asset!(asset_server.as_ref(), "motion_blur.wgsl");104commands.insert_resource(MotionBlurPipeline::new(105&render_device,106fullscreen_shader,107fragment_shader,108));109}110111#[derive(PartialEq, Eq, Hash, Clone, Copy)]112pub struct MotionBlurPipelineKey {113hdr: bool,114samples: u32,115}116117impl SpecializedRenderPipeline for MotionBlurPipeline {118type Key = MotionBlurPipelineKey;119120fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {121let layout = match key.samples {1221 => vec![self.layout.clone()],123_ => vec![self.layout_msaa.clone()],124};125126let mut shader_defs = vec![];127128if key.samples > 1 {129shader_defs.push(ShaderDefVal::from("MULTISAMPLED"));130}131132#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]133{134shader_defs.push("NO_DEPTH_TEXTURE_SUPPORT".into());135shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into());136}137138RenderPipelineDescriptor {139label: Some("motion_blur_pipeline".into()),140layout,141vertex: self.fullscreen_shader.to_vertex_state(),142fragment: Some(FragmentState {143shader: self.fragment_shader.clone(),144shader_defs,145targets: vec![Some(ColorTargetState {146format: if key.hdr {147ViewTarget::TEXTURE_FORMAT_HDR148} else {149TextureFormat::bevy_default()150},151blend: None,152write_mask: ColorWrites::ALL,153})],154..default()155}),156..default()157}158}159}160161#[derive(Component)]162pub struct MotionBlurPipelineId(pub CachedRenderPipelineId);163164pub(crate) fn prepare_motion_blur_pipelines(165mut commands: Commands,166pipeline_cache: Res<PipelineCache>,167mut pipelines: ResMut<SpecializedRenderPipelines<MotionBlurPipeline>>,168pipeline: Res<MotionBlurPipeline>,169views: Query<(Entity, &ExtractedView, &Msaa), With<MotionBlurUniform>>,170) {171for (entity, view, msaa) in &views {172let pipeline_id = pipelines.specialize(173&pipeline_cache,174&pipeline,175MotionBlurPipelineKey {176hdr: view.hdr,177samples: msaa.samples(),178},179);180181commands182.entity(entity)183.insert(MotionBlurPipelineId(pipeline_id));184}185}186187188