UI Node with border radius causes background pixels to come through on the inside of rounded corners
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version
from 0.14 (where rounded corners were introduced) until the current main branch
## Relevant system information
```
SystemInfo { os: "macOS 15.2 Sequoia", kernel: "24.2.0", cpu: "Apple M2", core_count: "8", memory: "16.0 GiB" }
```
Although I believe this bug exists on every device.
## What you did
Spawn a Node with a border radius that is bigger than the border size, so that the inside of the border become rounded.
Example `main.rs` to reproduce (tested on main branch but should also work with bevy 15.x):
```
use bevy::{
color::palettes::css::{BLUE, GREEN, WHITE},
prelude::*,
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
Node {
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
BackgroundColor(WHITE.into()),
))
.with_children(|parent| {
parent.spawn((
Node {
width: Val::Percent(80.0),
height: Val::Percent(80.0),
border: UiRect::all(Val::Px(20.)),
..default()
},
BackgroundColor(BLUE.into()),
BorderColor(GREEN.into()),
BorderRadius::all(Val::Px(30.0)),
));
});
}
```
## What went wrong
If we zoom in to the edges, you can see that the background comes through
While i'd expect it to look like this
The issue becomes more apparent with more contrasting colors, and especially once you start zooming in.
## Cause of the issue
As a bit of background info, a Node with a border gets rendered by having 2 rectangles: 1 for the border (green part of my example images) and 1 for the background (blue part of my example images).
The problem is that the rectangle for the background is not quite big enough to fully reach the anti-aliased pixels of the inside of the border corners.
## What I tried to do to solve this issue
1) **Remove anti-aliasing of the background rectangle**
I did this by using a `t` value of 1.0 instead of any pixel that has a higher `t` value of 0 in the current code. Here `t` refers to `let t` in the relevant fragment shader: `crates/bevy_ui/src/render/ui.wgsl`. Even with this, there was still some bleed-through.
2) **Make the background rectangle bigger**
I increased the size of the background rectangle by halve of the border size. This fixes the issue if the border has no transparency (which is how I got the images of what I expect a fixed version to look like), but it creates another issue for borders with transparency: the overlapping part of the border and the background make another border (so now there's unintentionally two borders!).
## Proposed solution
Unify the two separate rectangles of border and background in to 1 rectangle. This way we have fine grained control over the pixel values and we can properly calculate the color without the background coming through.
I don't think there is any real impact or migration guide necessary for this approach.
Once I get some eyes on this to confirm that this is the right approach, I'd love to implement this myself.
## Related issues
- probably related to #14456
Contributor guide
Research direction
Start with the supplied main.rs reproduction and inspect the fragment shader in crates/bevy_ui/src/render/ui.wgsl, especially the background and border rectangles. Compare the rendered rounded corners with opaque and transparent borders, and check related issue #14456. Done means the inside corners no longer show background pixels while border transparency remains correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 42/100