bevy/examples/ui/stacked_gradients.rs
ickshonpe 45a3f3d138
Color interpolation in OKLab, OKLCH spaces for UI gradients (#19330)
# Objective

Add support for interpolation in OKLab and OKLCH color spaces for UI
gradients.

## Solution
* New `InterpolationColorSpace` enum with `OkLab`, `OkLch`, `OkLchLong`,
`Srgb` and `LinearRgb` variants.
  * Added a color space specialization to the gradients pipeline.
* Added support for interpolation in OkLCH and OkLAB color spaces to the
gradients shader. OKLCH interpolation supports both short and long hue
paths. This is mostly based on the conversion functions from
`bevy_color` except that interpolation in polar space uses radians.
  * Added `color_space` fields to each gradient type.

## Testing

The `gradients` example has been updated to demonstrate the different
color interpolation methods.
Press space to cycle through the different options.

---

## Showcase


![color_spaces](https://github.com/user-attachments/assets/e10f8342-c3c8-487e-b386-7acdf38d638f)
2025-06-21 15:06:35 +00:00

92 lines
3.3 KiB
Rust

//! An example demonstrating overlaid gradients
use bevy::color::palettes::css::BLUE;
use bevy::color::palettes::css::RED;
use bevy::color::palettes::css::YELLOW;
use bevy::prelude::*;
use core::f32::consts::TAU;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn(Node {
display: Display::Grid,
width: Val::Percent(100.),
height: Val::Percent(100.),
..Default::default()
})
.with_children(|commands| {
commands.spawn((
Node {
width: Val::Percent(100.),
height: Val::Percent(100.),
..Default::default()
},
BackgroundColor(Color::BLACK),
BackgroundGradient(vec![
LinearGradient::to_top_right(vec![
ColorStop::auto(RED),
ColorStop::auto(RED.with_alpha(0.)),
])
.into(),
LinearGradient::to_top_left(vec![
ColorStop::auto(BLUE),
ColorStop::auto(BLUE.with_alpha(0.)),
])
.into(),
ConicGradient {
start: 0.,
position: UiPosition::CENTER,
stops: vec![
AngularColorStop::auto(YELLOW.with_alpha(0.)),
AngularColorStop::auto(YELLOW.with_alpha(0.)),
AngularColorStop::auto(YELLOW),
AngularColorStop::auto(YELLOW.with_alpha(0.)),
AngularColorStop::auto(YELLOW.with_alpha(0.)),
],
..Default::default()
}
.into(),
RadialGradient {
position: UiPosition::TOP.at_x(Val::Percent(5.)),
shape: RadialGradientShape::Circle(Val::Vh(30.)),
stops: vec![
ColorStop::auto(Color::WHITE),
ColorStop::auto(YELLOW),
ColorStop::auto(YELLOW.with_alpha(0.1)),
ColorStop::auto(YELLOW.with_alpha(0.)),
],
..Default::default()
}
.into(),
LinearGradient {
angle: TAU / 16.,
stops: vec![
ColorStop::auto(Color::BLACK),
ColorStop::auto(Color::BLACK.with_alpha(0.)),
],
..Default::default()
}
.into(),
LinearGradient {
angle: 15. * TAU / 16.,
stops: vec![
ColorStop::auto(Color::BLACK),
ColorStop::auto(Color::BLACK.with_alpha(0.)),
],
..Default::default()
}
.into(),
]),
));
});
}