bevy_color: Add sequence_dispersed to Hsla, Lcha, Oklcha (#12173)
# Objective - Fixes #12170 ## Solution - Moved the existing `color_from_entity` internals into `Hsla::sequence_dispersed` which generates a randomly distributed but deterministic color sequence based. - Replicated the method for `Lcha` and `Oklcha` as well. ## Examples ### Getting a few colours for a quick palette ```rust let palette = Hsla::sequence_dispersed().take(5).collect::<Vec<_>>(); /*[ Hsla::hsl(0.0, 1., 0.5), Hsla::hsl(222.49225, 1., 0.5), Hsla::hsl(84.984474, 1., 0.5), Hsla::hsl(307.4767, 1., 0.5), Hsla::hsl(169.96895, 1., 0.5), ]*/ ``` ### Getting a colour from an `Entity` ```rust let color = Oklcha::sequence_dispersed().nth(entity.index() as u32).unwrap(); ``` ## Notes This was previously a private function exclusively for `Entity` types. I've decided it should instead be public and operate on a `u32` directly, since this function may have broader uses for debugging purposes. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
7826313405
commit
043041f3aa
@ -66,6 +66,35 @@ impl Hsla {
|
||||
pub const fn with_lightness(self, lightness: f32) -> Self {
|
||||
Self { lightness, ..self }
|
||||
}
|
||||
|
||||
/// Generate a deterministic but [quasi-randomly distributed](https://en.wikipedia.org/wiki/Low-discrepancy_sequence)
|
||||
/// color from a provided `index`.
|
||||
///
|
||||
/// This can be helpful for generating debug colors.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use bevy_color::Hsla;
|
||||
/// // Unique color for an entity
|
||||
/// # let entity_index = 123;
|
||||
/// // let entity_index = entity.index();
|
||||
/// let color = Hsla::sequential_dispersed(entity_index);
|
||||
///
|
||||
/// // Palette with 5 distinct hues
|
||||
/// let palette = (0..5).map(Hsla::sequential_dispersed).collect::<Vec<_>>();
|
||||
/// ```
|
||||
pub fn sequential_dispersed(index: u32) -> Self {
|
||||
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
|
||||
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
|
||||
|
||||
// from https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/
|
||||
//
|
||||
// Map a sequence of integers (eg: 154, 155, 156, 157, 158) into the [0.0..1.0] range,
|
||||
// so that the closer the numbers are, the larger the difference of their image.
|
||||
let hue = index.wrapping_mul(FRAC_U32MAX_GOLDEN_RATIO) as f32 * RATIO_360;
|
||||
Self::hsl(hue, 1., 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Hsla {
|
||||
@ -306,4 +335,21 @@ mod tests {
|
||||
assert_approx_eq!(hsla2.mix(&hsla0, 0.5).hue, 0., 0.001);
|
||||
assert_approx_eq!(hsla2.mix(&hsla0, 0.75).hue, 5., 0.001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_index() {
|
||||
let references = [
|
||||
Hsla::hsl(0.0, 1., 0.5),
|
||||
Hsla::hsl(222.49225, 1., 0.5),
|
||||
Hsla::hsl(84.984474, 1., 0.5),
|
||||
Hsla::hsl(307.4767, 1., 0.5),
|
||||
Hsla::hsl(169.96895, 1., 0.5),
|
||||
];
|
||||
|
||||
for (index, reference) in references.into_iter().enumerate() {
|
||||
let color = Hsla::sequential_dispersed(index as u32);
|
||||
|
||||
assert_approx_eq!(color.hue, reference.hue, 0.001);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +70,35 @@ impl Lcha {
|
||||
pub const fn with_lightness(self, lightness: f32) -> Self {
|
||||
Self { lightness, ..self }
|
||||
}
|
||||
|
||||
/// Generate a deterministic but [quasi-randomly distributed](https://en.wikipedia.org/wiki/Low-discrepancy_sequence)
|
||||
/// color from a provided `index`.
|
||||
///
|
||||
/// This can be helpful for generating debug colors.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use bevy_color::Lcha;
|
||||
/// // Unique color for an entity
|
||||
/// # let entity_index = 123;
|
||||
/// // let entity_index = entity.index();
|
||||
/// let color = Lcha::sequential_dispersed(entity_index);
|
||||
///
|
||||
/// // Palette with 5 distinct hues
|
||||
/// let palette = (0..5).map(Lcha::sequential_dispersed).collect::<Vec<_>>();
|
||||
/// ```
|
||||
pub fn sequential_dispersed(index: u32) -> Self {
|
||||
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
|
||||
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
|
||||
|
||||
// from https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/
|
||||
//
|
||||
// Map a sequence of integers (eg: 154, 155, 156, 157, 158) into the [0.0..1.0] range,
|
||||
// so that the closer the numbers are, the larger the difference of their image.
|
||||
let hue = index.wrapping_mul(FRAC_U32MAX_GOLDEN_RATIO) as f32 * RATIO_360;
|
||||
Self::lch(0.75, 0.35, hue)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Lcha {
|
||||
|
||||
@ -69,6 +69,35 @@ impl Oklcha {
|
||||
pub const fn with_h(self, hue: f32) -> Self {
|
||||
Self { hue, ..self }
|
||||
}
|
||||
|
||||
/// Generate a deterministic but [quasi-randomly distributed](https://en.wikipedia.org/wiki/Low-discrepancy_sequence)
|
||||
/// color from a provided `index`.
|
||||
///
|
||||
/// This can be helpful for generating debug colors.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use bevy_color::Oklcha;
|
||||
/// // Unique color for an entity
|
||||
/// # let entity_index = 123;
|
||||
/// // let entity_index = entity.index();
|
||||
/// let color = Oklcha::sequential_dispersed(entity_index);
|
||||
///
|
||||
/// // Palette with 5 distinct hues
|
||||
/// let palette = (0..5).map(Oklcha::sequential_dispersed).collect::<Vec<_>>();
|
||||
/// ```
|
||||
pub fn sequential_dispersed(index: u32) -> Self {
|
||||
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
|
||||
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
|
||||
|
||||
// from https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/
|
||||
//
|
||||
// Map a sequence of integers (eg: 154, 155, 156, 157, 158) into the [0.0..1.0] range,
|
||||
// so that the closer the numbers are, the larger the difference of their image.
|
||||
let hue = index.wrapping_mul(FRAC_U32MAX_GOLDEN_RATIO) as f32 * RATIO_360;
|
||||
Self::lch(0.75, 0.1, hue)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Oklcha {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
use crate as bevy_gizmos;
|
||||
|
||||
use bevy_app::{Plugin, PostUpdate};
|
||||
use bevy_color::Oklcha;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
@ -97,18 +98,7 @@ fn draw_all_aabbs(
|
||||
}
|
||||
|
||||
fn color_from_entity(entity: Entity) -> LegacyColor {
|
||||
let index = entity.index();
|
||||
|
||||
// from https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/Low-discrepancy_sequence
|
||||
// Map a sequence of integers (eg: 154, 155, 156, 157, 158) into the [0.0..1.0] range,
|
||||
// so that the closer the numbers are, the larger the difference of their image.
|
||||
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
|
||||
const RATIO_360: f32 = 360.0 / u32::MAX as f32;
|
||||
let hue = index.wrapping_mul(FRAC_U32MAX_GOLDEN_RATIO) as f32 * RATIO_360;
|
||||
|
||||
LegacyColor::hsl(hue, 1., 0.5)
|
||||
Oklcha::sequential_dispersed(entity.index()).into()
|
||||
}
|
||||
|
||||
fn aabb_transform(aabb: Aabb, transform: GlobalTransform) -> GlobalTransform {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user