Constant MOTION_BLUR

Source
const MOTION_BLUR: &str = r#"
uniform sampler2D u_prev;
uniform sampler2D u_next;
uniform float u_frames;
uniform vec2 u_motion;
void main() {
    vec2 uv = gl_FragCoord.xy / u_res;
    vec4 src = texture(tex, uv);
    float sh = clamp(p0, 0.0, 360.0) / 360.0;
    int n = int(clamp(p1, 2.0, 32.0));
    vec4 acc = vec4(0.0);
    vec4 prev = src;
    vec4 next = src;
    if (u_frames > 0.5) {
        prev = texture(u_prev, uv);
        next = u_frames > 1.5 ? texture(u_next, uv) : prev;
        for (int i = 0; i < 32; i++) {
            if (i >= n) break;
            float o = ((float(i) + 0.5) / float(n) - 0.5) * sh;
            acc += o < 0.0 ? mix(src, prev, clamp(-o, 0.0, 1.0)) : mix(src, next, clamp(o, 0.0, 1.0));
        }
    } else {
        vec2 d = u_motion / u_res * sh;
        for (int i = 0; i < 32; i++) {
            if (i >= n) break;
            acc += texture(tex, uv + d * ((float(i) + 0.5) / float(n) - 0.5));
        }
    }
    vec4 res = acc / float(n);
    if (p2 >= 0.5 && u_frames > 0.5) {
        float mv = length(prev.rgb - src.rgb) + length(next.rgb - src.rgb);
        res = mix(src, res, clamp(mv * 4.0, 0.0, 1.0));
    }
    float m = u_has_mask > 0.5 ? texture(u_mask, uv).r : 1.0;
    out_color = mix(src, res, m);
}
"#;
Expand description

Shutter-window average of the frames gpu.rs supplies.

Extra uniforms gpu.rs must bind (this kind reports EffectKind::needs_motion()): sampler2D u_prev / u_next the layer one frame before / after (bind tex when missing) float u_frames how many of those are real: 0, 1 (prev only) or 2 vec2 u_motion the layer’s motion in layer pixels per frame, for the 0-frame fallback