Zoom Blur Is Updated
Zoom Blur has been one of our most popular tools. We have made changes to how it works and how you can interact with it.
What Changed
Previously, Zoom Blur was implemented as a Custom Transformer Shader. While functional, this made it cumbersome to incorporate into your own projects. Zoom Blur is now its own dedicated Composition Zoom Blur node in the graph editor, and it is also available in the Python API. The parameters remain the same: a center point and a strength value.
Using Zoom Blur from Python
You can now apply Zoom Blur directly from Python:
import brushcue
ctx = brushcue.Context()
img = brushcue.composition_image_from_path("my_image.jpg")
center = brushcue.vector2f_from_components(0.5, 0.5)
zoom_blurred_img = brushcue.composition_zoom_blur(img, center, 0.5)Check out the Python API documentation and the Zoom Blur example for more details.
Easier to Use on the BrushCue Website
We have also improved the Zoom Blur experience in the BrushCue editor. You will now see a drag handle on the canvas where you can interactively set the effect center.
How the Shader Works
In the spirit of transparency, here is the WGSL shader that powers Zoom Blur. You can use this as a starting point to create your own variation with a Custom Transformer Shader.
@group(0) @binding(0) var input_texture: texture_2d<f32>;
@group(0) @binding(1) var<uniform> center: vec2<f32>;
@group(0) @binding(2) var<uniform> strength: f32;
fn do_transformation(input: vec4<f32>, position: vec2<u32>) -> vec4<f32> {
let dims = vec2<f32>(textureDimensions(input_texture));
let uv = (vec2<f32>(position) + vec2<f32>(0.5)) / dims;
let center_uv = clamp(center, vec2<f32>(0.0), vec2<f32>(1.0));
let dir = uv - center_uv;
let dist = length(dir);
let max_dist = 0.85;
let distance_scale = smoothstep(0.0, max_dist, min(dist, max_dist));
let effective_strength = strength * distance_scale * 0.85;
let pixel_hash = fract(sin(dot(vec2<f32>(position), vec2<f32>(12.9898, 78.233))) * 43758.5453);
var result = vec4<f32>(0.0);
var total_weight = 0.0;
let samples = 32;
for (var i = 0; i < samples; i++) {
let base_t = (f32(i) + 0.5) / f32(samples);
let jitter = (pixel_hash - 0.5) / f32(samples);
let t = clamp(base_t + jitter, 0.0, 1.0);
let eased_t = t * t * (3.0 - 2.0 * t);
let weight = 1.0 - eased_t * 0.65;
let sample_uv = uv - dir * eased_t * effective_strength;
result += sample(input_texture, sample_uv) * weight;
total_weight += weight;
}
return result / total_weight;
}
fn sample(tex: texture_2d<f32>, uv: vec2<f32>) -> vec4<f32>; // function implemented for youThe effect works by sampling the image 32 times along the direction from each pixel toward the center. Each sample is jittered slightly (using a per-pixel hash) to avoid banding. Samples closer to the center are weighted more heavily, and the blur strength is scaled by distance from the center so that the effect falls off naturally near the focal point.
We hope this update makes Zoom Blur easier to use in your projects. As always, feel free to reach out to feedback@brushcue.com with any feedback or questions.