Skip to content

UI Node Gradients #18139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 152 commits into from
May 20, 2025
Merged

UI Node Gradients #18139

merged 152 commits into from
May 20, 2025

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Mar 3, 2025

Objective

Allowing drawing of UI nodes with a gradient instead of a flat color.

Solution

The are three gradient structs corresponding to the three types of gradients supported: LinearGradient, ConicGradient and RadialGradient. These are then wrapped in a Gradient enum discriminator which has Linear, Conic and Radial variants.

Each gradient type consists of the geometric properties for that gradient and a list of color stops.
Color stops consist of a color, a position or angle and an optional hint. If no position is specified for a stop, it's evenly spaced between the previous and following stops. Color stop positions are absolute, if you specify a list of stops:
vec![vec![ColorStop::new(RED, Val::Percent(90.), ColorStop::new(Color::GREEN, Val::Percent(10.))
the colors will be reordered and the gradient will transition from green at 10% to red at 90%.

Colors are interpolated between the stops in SRGB space. The hint is a normalized value that can be used to shift the mid-point where the colors are mixed 50-50. between the stop with the hint and the following stop.

For sharp stops with no interpolated transition, place two stops at the same position.

ConicGradients and RadialGradients have a center which is set using the new Positiontype.Positionconsists of a normalized (relative to the UI node)Vec2` anchor point and a responsive x, y offset.

To draw a UI node with a gradient you insert the components BackgroundGradient and BorderGradient, which both newtype a vector of Gradients. If you set a background color, the background color is drawn first and the gradient(s) are drawn on top.

The implementation is deliberately simple and self contained. The shader draws the gradient in multiple passes which is quite inefficient for gradients with a very large number of color stops. It's simple though and there won't be any compatibility issues. We could make gradients a specialization for UiPipeline but I used a separate pipeline plugin for now to ensure that these changes don't break anything.

Not supported in this PR

  • Interpolation in other color spaces besides SRGB.
  • Images and text: This would need some breaking changes like a UiColor enum type with Color and Gradient variants, to enable BorderColor, TextColor, BackgroundColor and ImageNode::color to take either a Color or a gradient.
  • Repeating gradients

Testing

Includes three examples that can be used for testing:

cargo run --example linear_gradients
cargo run --example stacked_gradients
cargo run --example radial_gradients

Most of the code except the components API is contained within the bevy_ui/src/render/linear_gradients module.
There are no changes to any existing systems or plugins except for the addition of the gradients rendering systems to the render world schedule and the Val changes from #18164 .

Showcase

gradients
stacked
rad

Conic gradients can be used to draw simple pie charts like in CSS:
PIE

@ickshonpe ickshonpe changed the title UI Linear Gradients UI Node Gradients Mar 3, 2025
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen A-UI Graphical user interfaces, styles, layouts, and widgets labels Mar 3, 2025
Copy link
Contributor

@NthTensor NthTensor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was created before we implemented the new release notes process, and so hasn't gotten the right pings by the bot. I'm re-adding the tags so that you'll get the new instructions.

@NthTensor NthTensor added M-Needs-Release-Note Work that should be called out in the blog due to impact and removed M-Needs-Release-Note Work that should be called out in the blog due to impact labels Apr 25, 2025
Copy link
Contributor

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

@NthTensor NthTensor added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it labels Apr 27, 2025
@ickshonpe ickshonpe added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels May 12, 2025
Copy link
Contributor

@NthTensor NthTensor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Release content looks good.

Minor nit that I was not aware of before reading the new content:

Colors are interpolated between the stops in SRGB space.

Srgb is almost certainly the wrong space to do any kind of color gradient or interpolation in, except in the case where you are trying to match another program (which also does it wrong). This should ideally be (a) configurable and (b) default to OkLab.

I consider this feedback non-blocking, but I did want it to be registered.

@ickshonpe
Copy link
Contributor Author

Release content looks good.

Minor nit that I was not aware of before reading the new content:

Colors are interpolated between the stops in SRGB space.

Srgb is almost certainly the wrong space to do any kind of color gradient or interpolation in, except in the case where you are trying to match another program (which also does it wrong). This should ideally be (a) configurable and (b) default to OkLab.

I consider this feedback non-blocking, but I did want it to be registered.

I went with SRGB, despite the transitions looking so dull and muddy, as it's the default for CSS which the api here is roughly based on. I'd definitely be on board with making Bevy default to OkLab though. I'm kind of fighting myself not to make more changes here and add multiple color space support etc but I've got so many PRs in review atm need to get some of them merged hehe.

@NthTensor
Copy link
Contributor

Yeah, totally fair let's look into this as follow up.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 20, 2025
Merged via the queue into bevyengine:main with commit bf20c63 May 20, 2025
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen A-UI Graphical user interfaces, styles, layouts, and widgets C-Feature A new feature, making something new possible D-Shaders This code uses GPU shader languages M-Needs-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

8 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy