use bevy_app::{App, Plugin};
use bevy_asset::embedded_asset;
use bevy_camera::Camera;
use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d},
prepass::{DepthPrepass, MotionVectorPrepass},
};
use bevy_ecs::{
component::Component,
query::{QueryItem, With},
reflect::ReflectComponent,
schedule::IntoScheduleConfigs,
};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin},
render_graph::{RenderGraphExt, ViewNodeRunner},
render_resource::{ShaderType, SpecializedRenderPipelines},
Render, RenderApp, RenderStartup, RenderSystems,
};
pub mod node;
pub mod pipeline;
#[derive(Reflect, Component, Clone)]
#[reflect(Component, Default, Clone)]
#[require(DepthPrepass, MotionVectorPrepass)]
pub struct MotionBlur {
pub shutter_angle: f32,
pub samples: u32,
}
impl Default for MotionBlur {
fn default() -> Self {
Self {
shutter_angle: 0.5,
samples: 1,
}
}
}
impl ExtractComponent for MotionBlur {
type QueryData = &'static Self;
type QueryFilter = With<Camera>;
type Out = MotionBlurUniform;
fn extract_component(item: QueryItem<Self::QueryData>) -> Option<Self::Out> {
Some(MotionBlurUniform {
shutter_angle: item.shutter_angle,
samples: item.samples,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_webgl2_padding: Default::default(),
})
}
}
#[doc(hidden)]
#[derive(Component, ShaderType, Clone)]
pub struct MotionBlurUniform {
shutter_angle: f32,
samples: u32,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_webgl2_padding: bevy_math::Vec2,
}
#[derive(Default)]
pub struct MotionBlurPlugin;
impl Plugin for MotionBlurPlugin {
fn build(&self, app: &mut App) {
embedded_asset!(app, "motion_blur.wgsl");
app.add_plugins((
ExtractComponentPlugin::<MotionBlur>::default(),
UniformComponentPlugin::<MotionBlurUniform>::default(),
));
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app
.init_resource::<SpecializedRenderPipelines<pipeline::MotionBlurPipeline>>()
.add_systems(RenderStartup, pipeline::init_motion_blur_pipeline)
.add_systems(
Render,
pipeline::prepare_motion_blur_pipelines.in_set(RenderSystems::Prepare),
);
render_app
.add_render_graph_node::<ViewNodeRunner<node::MotionBlurNode>>(
Core3d,
Node3d::MotionBlur,
)
.add_render_graph_edges(
Core3d,
(
Node3d::StartMainPassPostProcessing,
Node3d::MotionBlur,
Node3d::Bloom, ),
);
}
}