Skip to content

[sparse strips] Support elliptical corner radii in blurred rounded rectangles - #2

Closed
nicoburns wants to merge 2 commits into
non-uniform-blurred-rect-radiifrom
elliptical-blurred-rect-radii
Closed

nicoburns wants to merge 2 commits into
non-uniform-blurred-rect-radiifrom
elliptical-blurred-rect-radii

Conversation

@nicoburns

Copy link
Copy Markdown
Member

Summary

Stacked on #1. Extends the analytic blurred rounded rect paint from scalar per-corner radii to per-corner elliptical radii (CSS border-radius with / syntax), across vello_common, vello_cpu, and vello_hybrid.

New public type in vello_common::blurred_rounded_rect (kurbo's RoundedRectRadii can't express elliptical corners):

pub struct CornerRadii {
    pub top_left: Vec2,     // x radius, y radius
    pub top_right: Vec2,
    pub bottom_left: Vec2,
    pub bottom_right: Vec2,
}
// From<f64> and From<RoundedRectRadii> preserve the old call sites via `.into()`

fill_blurred_rounded_rect on vello_cpu::RenderContext and vello_hybrid::Scene now takes CornerRadii (breaking, follows on from #1's change).

Field math

The isotropic superellipse corner term is replaced by an anisotropic one. Per corner we encode blur-adjusted axis radii r1_x = hypot(rx, 2σ), r1_y = hypot(ry, 2σ), an exponent derived from the corner's geometric mean radius (which reduces to #1's exponent for circular corners), plus precomputed weights w_x = r1_x^-p, w_y = r1_y^-p. In the fine shader (same code in vello_cpu SIMD and render.wesl):

a = x1^p; b = y1^p
d_pos = (a + b)^(1/p)                                  // unchanged shape of the field
r_eff = ((a + b + ε) / (a·w_x + b·w_y + ε·mean_w))^(1/p) // direction-dependent effective radius
d     = d_pos + d_neg - r_eff

r_eff is the radius of the anisotropic superellipse in the direction of the sample point — it interpolates between r1_x (on the horizontal midline) and r1_y (vertical), so the Gaussian falloff tracks the local corner curvature instead of assuming a circle. When r1_x == r1_y the shader selects r1_x directly, so circular corners take exactly the same value path as before — all existing uniform and non-uniform snapshots pass byte-identical, on both CPU and hybrid.

GpuBlurredRoundedRect grows from 6 to 9 texels (r1_x, r1_y, exponent, w_x, w_y corner vectors).

Caveats

This remains an approximation: the anisotropic field's iso-contours are not uniformly spaced Euclidean offsets, so blur falloff around highly eccentric corners is heuristic rather than exact. It is well-behaved for moderate eccentricity and improves as σ grows; the fully-elliptical pill snapshot (40×25 radii) renders correctly.

Testing

New snapshot tests (CPU + hybrid/wgpu): blurred_rounded_rect_elliptical_radii, ..._elliptical_radii_std_dev, ..._elliptical_pill, inverse_blurred_rounded_rect_elliptical_radii. An elliptical example was added to the blurred_rounded_rect example scene. cargo fmt / clippy --workspace --all-targets clean; full blurred_rounded_rect filter: 192 passed, 0 failed.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/f0e29f278fc544ebb7a91bfeed0bcc85
Requested by: @nicoburns

@nicoburns nicoburns self-assigned this Aug 4, 2026
@staging-devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nicoburns nicoburns closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant