mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Interpolating hues should use rem_euclid. (#12641)
Also, added additional tests for the hue interpolation. Fixes #12632 Fixes #12631
This commit is contained in:
parent
6910ca3e8a
commit
7133d51331
4 changed files with 31 additions and 28 deletions
|
@ -97,10 +97,18 @@ pub trait ClampColor: Sized {
|
||||||
fn is_within_bounds(&self) -> bool;
|
fn is_within_bounds(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Utility function for interpolating hue values. This ensures that the interpolation
|
||||||
|
/// takes the shortest path around the color wheel, and that the result is always between
|
||||||
|
/// 0 and 360.
|
||||||
|
pub(crate) fn lerp_hue(a: f32, b: f32, t: f32) -> f32 {
|
||||||
|
let diff = (b - a + 180.0).rem_euclid(360.) - 180.;
|
||||||
|
(a + diff * t).rem_euclid(360.0)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::Hsla;
|
use crate::{testing::assert_approx_eq, Hsla};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rotate_hue() {
|
fn test_rotate_hue() {
|
||||||
|
@ -113,4 +121,23 @@ mod tests {
|
||||||
assert_eq!(hsla.rotate_hue(360.0), hsla);
|
assert_eq!(hsla.rotate_hue(360.0), hsla);
|
||||||
assert_eq!(hsla.rotate_hue(-360.0), hsla);
|
assert_eq!(hsla.rotate_hue(-360.0), hsla);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hue_wrap() {
|
||||||
|
assert_approx_eq!(lerp_hue(10., 20., 0.25), 12.5, 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(10., 20., 0.5), 15., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(10., 20., 0.75), 17.5, 0.001);
|
||||||
|
|
||||||
|
assert_approx_eq!(lerp_hue(20., 10., 0.25), 17.5, 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(20., 10., 0.5), 15., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(20., 10., 0.75), 12.5, 0.001);
|
||||||
|
|
||||||
|
assert_approx_eq!(lerp_hue(10., 350., 0.25), 5., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(10., 350., 0.5), 0., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(10., 350., 0.75), 355., 0.001);
|
||||||
|
|
||||||
|
assert_approx_eq!(lerp_hue(350., 10., 0.25), 355., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(350., 10., 0.5), 0., 0.001);
|
||||||
|
assert_approx_eq!(lerp_hue(350., 10., 0.75), 5., 0.001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,16 +105,8 @@ impl Mix for Hsla {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mix(&self, other: &Self, factor: f32) -> Self {
|
fn mix(&self, other: &Self, factor: f32) -> Self {
|
||||||
let n_factor = 1.0 - factor;
|
let n_factor = 1.0 - factor;
|
||||||
// TODO: Refactor this into EuclideanModulo::lerp_modulo
|
|
||||||
let shortest_angle = ((((other.hue - self.hue) % 360.) + 540.) % 360.) - 180.;
|
|
||||||
let mut hue = self.hue + shortest_angle * factor;
|
|
||||||
if hue < 0. {
|
|
||||||
hue += 360.;
|
|
||||||
} else if hue >= 360. {
|
|
||||||
hue -= 360.;
|
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
hue,
|
hue: crate::color_ops::lerp_hue(self.hue, other.hue, factor),
|
||||||
saturation: self.saturation * n_factor + other.saturation * factor,
|
saturation: self.saturation * n_factor + other.saturation * factor,
|
||||||
lightness: self.lightness * n_factor + other.lightness * factor,
|
lightness: self.lightness * n_factor + other.lightness * factor,
|
||||||
alpha: self.alpha * n_factor + other.alpha * factor,
|
alpha: self.alpha * n_factor + other.alpha * factor,
|
||||||
|
|
|
@ -73,16 +73,8 @@ impl Mix for Hsva {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mix(&self, other: &Self, factor: f32) -> Self {
|
fn mix(&self, other: &Self, factor: f32) -> Self {
|
||||||
let n_factor = 1.0 - factor;
|
let n_factor = 1.0 - factor;
|
||||||
// TODO: Refactor this into EuclideanModulo::lerp_modulo
|
|
||||||
let shortest_angle = ((((other.hue - self.hue) % 360.) + 540.) % 360.) - 180.;
|
|
||||||
let mut hue = self.hue + shortest_angle * factor;
|
|
||||||
if hue < 0. {
|
|
||||||
hue += 360.;
|
|
||||||
} else if hue >= 360. {
|
|
||||||
hue -= 360.;
|
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
hue,
|
hue: crate::color_ops::lerp_hue(self.hue, other.hue, factor),
|
||||||
saturation: self.saturation * n_factor + other.saturation * factor,
|
saturation: self.saturation * n_factor + other.saturation * factor,
|
||||||
value: self.value * n_factor + other.value * factor,
|
value: self.value * n_factor + other.value * factor,
|
||||||
alpha: self.alpha * n_factor + other.alpha * factor,
|
alpha: self.alpha * n_factor + other.alpha * factor,
|
||||||
|
|
|
@ -77,16 +77,8 @@ impl Mix for Hwba {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mix(&self, other: &Self, factor: f32) -> Self {
|
fn mix(&self, other: &Self, factor: f32) -> Self {
|
||||||
let n_factor = 1.0 - factor;
|
let n_factor = 1.0 - factor;
|
||||||
// TODO: Refactor this into EuclideanModulo::lerp_modulo
|
|
||||||
let shortest_angle = ((((other.hue - self.hue) % 360.) + 540.) % 360.) - 180.;
|
|
||||||
let mut hue = self.hue + shortest_angle * factor;
|
|
||||||
if hue < 0. {
|
|
||||||
hue += 360.;
|
|
||||||
} else if hue >= 360. {
|
|
||||||
hue -= 360.;
|
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
hue,
|
hue: crate::color_ops::lerp_hue(self.hue, other.hue, factor),
|
||||||
whiteness: self.whiteness * n_factor + other.whiteness * factor,
|
whiteness: self.whiteness * n_factor + other.whiteness * factor,
|
||||||
blackness: self.blackness * n_factor + other.blackness * factor,
|
blackness: self.blackness * n_factor + other.blackness * factor,
|
||||||
alpha: self.alpha * n_factor + other.alpha * factor,
|
alpha: self.alpha * n_factor + other.alpha * factor,
|
||||||
|
|
Loading…
Reference in a new issue