wisp/filter/
motion_blur.rs1use crate::filter::{Filter, FilterContext};
7use crate::texture::render_texture::RenderTexture;
8
9#[derive(Debug, Clone, Copy)]
16pub struct MotionBlurFilter {
17 pub velocity: glam::Vec2,
19 pub peak_velocity_pps: f32,
21 pub max_kernel_px: f32,
23}
24
25impl Default for MotionBlurFilter {
26 fn default() -> Self {
27 Self {
28 velocity: glam::Vec2::ZERO,
29 peak_velocity_pps: 1400.0,
30 max_kernel_px: 14.0,
31 }
32 }
33}
34
35impl MotionBlurFilter {
36 fn kernel_pixels(&self) -> f32 {
37 let speed = self.velocity.length();
38 (speed / self.peak_velocity_pps).clamp(0.0, 1.0) * self.max_kernel_px
39 }
40
41 fn unit_direction(&self) -> [f32; 2] {
42 if self.velocity.length_squared() < 1e-6 {
43 [1.0, 0.0]
44 } else {
45 let n = self.velocity.normalize();
46 [n.x, n.y]
47 }
48 }
49}
50
51impl Filter for MotionBlurFilter {
52 fn passes(&self) -> u32 {
53 1
54 }
55
56 fn render_pass(
57 &self,
58 ctx: &mut FilterContext<'_>,
59 input: &RenderTexture,
60 output: &RenderTexture,
61 _pass: u32,
62 ) {
63 let radius = self.kernel_pixels();
64 if radius < 0.05 {
65 super::blur::run_blur_pass(ctx.app, ctx.encoder, input, output, [1.0, 0.0], 0.0);
67 return;
68 }
69 super::blur::run_blur_pass(
70 ctx.app,
71 ctx.encoder,
72 input,
73 output,
74 self.unit_direction(),
75 radius,
76 );
77 }
78}