diff --git a/crates/store/re_types/definitions/rerun/components/colormap.fbs b/crates/store/re_types/definitions/rerun/components/colormap.fbs index 8cd8af167b09..79976effb36b 100644 --- a/crates/store/re_types/definitions/rerun/components/colormap.fbs +++ b/crates/store/re_types/definitions/rerun/components/colormap.fbs @@ -42,4 +42,11 @@ enum Colormap: byte { /// This is a perceptually uniform colormap which is robust to color blindness. /// It interpolates from dark purple to green to yellow. Viridis, + + /// Rasmusgo's Cyan to Yellow colormap + /// + /// This is a perceptually uniform colormap which is robust to color blindness. + /// It is especially suited for visualizing signed values. + /// It interpolates from cyan to blue to dark gray to brass to yellow. + CyanToYellow, } diff --git a/crates/store/re_types/src/components/colormap.rs b/crates/store/re_types/src/components/colormap.rs index b4e251b65762..ccd393065d3a 100644 --- a/crates/store/re_types/src/components/colormap.rs +++ b/crates/store/re_types/src/components/colormap.rs @@ -62,6 +62,13 @@ pub enum Colormap { /// This is a perceptually uniform colormap which is robust to color blindness. /// It interpolates from dark purple to green to yellow. Viridis = 6, + + /// Rasmusgo's Cyan to Yellow colormap + /// + /// This is a perceptually uniform colormap which is robust to color blindness. + /// It is especially suited for visualizing signed values. + /// It interpolates from cyan to blue to dark gray to brass to yellow. + CyanToYellow = 7, } impl ::re_types_core::reflection::Enum for Colormap { @@ -74,6 +81,7 @@ impl ::re_types_core::reflection::Enum for Colormap { Self::Plasma, Self::Turbo, Self::Viridis, + Self::CyanToYellow, ] } @@ -98,6 +106,9 @@ impl ::re_types_core::reflection::Enum for Colormap { Self::Viridis => { "The Viridis colormap from Matplotlib\n\nThis is a perceptually uniform colormap which is robust to color blindness.\nIt interpolates from dark purple to green to yellow." } + Self::CyanToYellow => { + "Rasmusgo's Cyan to Yellow colormap\n\nThis is a perceptually uniform colormap which is robust to color blindness.\nIt is especially suited for visualizing signed values.\nIt interpolates from cyan to blue to dark gray to brass to yellow." + } } } } @@ -123,6 +134,7 @@ impl std::fmt::Display for Colormap { Self::Plasma => write!(f, "Plasma"), Self::Turbo => write!(f, "Turbo"), Self::Viridis => write!(f, "Viridis"), + Self::CyanToYellow => write!(f, "CyanToYellow"), } } } @@ -150,9 +162,10 @@ impl ::re_types_core::Loggable for Colormap { Field::new("Plasma", DataType::Null, true), Field::new("Turbo", DataType::Null, true), Field::new("Viridis", DataType::Null, true), + Field::new("CyanToYellow", DataType::Null, true), ]), Some(std::sync::Arc::new(vec![ - 0i32, 1i32, 2i32, 3i32, 4i32, 5i32, 6i32, + 0i32, 1i32, 2i32, 3i32, 4i32, 5i32, 6i32, 7i32, ])), UnionMode::Sparse, ) @@ -176,7 +189,7 @@ impl ::re_types_core::Loggable for Colormap { datum }) .collect(); - let num_variants = 6usize; + let num_variants = 7usize; let types = data .iter() .map(|a| match a.as_deref() { @@ -222,6 +235,7 @@ impl ::re_types_core::Loggable for Colormap { 4 => Ok(Some(Self::Plasma)), 5 => Ok(Some(Self::Turbo)), 6 => Ok(Some(Self::Viridis)), + 7 => Ok(Some(Self::CyanToYellow)), _ => Err(DeserializationError::missing_union_arm( Self::arrow_datatype(), "", diff --git a/crates/viewer/re_renderer/shader/colormap.wgsl b/crates/viewer/re_renderer/shader/colormap.wgsl index 003076893d70..e072358f716b 100644 --- a/crates/viewer/re_renderer/shader/colormap.wgsl +++ b/crates/viewer/re_renderer/shader/colormap.wgsl @@ -2,12 +2,13 @@ #import <./utils/srgb.wgsl> // NOTE: Keep in sync with `colormap.rs`! -const COLORMAP_GRAYSCALE: u32 = 1u; // sRGB gradient = perceptually even -const COLORMAP_INFERNO: u32 = 2u; -const COLORMAP_MAGMA: u32 = 3u; -const COLORMAP_PLASMA: u32 = 4u; -const COLORMAP_TURBO: u32 = 5u; -const COLORMAP_VIRIDIS: u32 = 6u; +const COLORMAP_GRAYSCALE: u32 = 1u; // sRGB gradient = perceptually even +const COLORMAP_INFERNO: u32 = 2u; +const COLORMAP_MAGMA: u32 = 3u; +const COLORMAP_PLASMA: u32 = 4u; +const COLORMAP_TURBO: u32 = 5u; +const COLORMAP_VIRIDIS: u32 = 6u; +const COLORMAP_CYAN_TO_YELLOW: u32 = 7u; /// Returns a gamma-space sRGB in 0-1 range. /// @@ -28,6 +29,8 @@ fn colormap_srgb(which: u32, t_unsaturated: f32) -> vec3f { return colormap_turbo_srgb(t); } else if which == COLORMAP_VIRIDIS { return colormap_viridis_srgb(t); + } else if which == COLORMAP_CYAN_TO_YELLOW { + return colormap_cyan_to_yellow_srgb(t); } else { return ERROR_RGBA.rgb; } @@ -143,3 +146,19 @@ fn colormap_inferno_srgb(t: f32) -> vec3f { let c6 = vec3f(25.13112622477341, -12.24266895238567, -23.07032500287172); return c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * c6))))); } + +// --- rasmusgo's color maps --- + +// Designed by Rasmus Brönnegård (rasmusgo) adapted from https://www.shadertoy.com/view/lfByRh. +// +// License CC0 (public domain) +// https://creativecommons.org/share-your-work/public-domain/cc0/ + +/// Returns a gamma-space sRGB in 0-1 range. +/// This is a perceptually uniform colormap which is robust to color blindness. +/// It is especially suited for visualizing signed values. +/// It interpolates from cyan to blue to dark gray to brass to yellow. +fn colormap_cyan_to_yellow_srgb(t: f32) -> vec3f { + let u = t * 2. - 1.; + return saturate(vec3f(1. + 3. * u, (1. + 3. * u * u) , 1. - 3. * u) / 4.); +} diff --git a/crates/viewer/re_renderer/src/colormap.rs b/crates/viewer/re_renderer/src/colormap.rs index cd8cc94e2479..2ae14b586dcb 100644 --- a/crates/viewer/re_renderer/src/colormap.rs +++ b/crates/viewer/re_renderer/src/colormap.rs @@ -18,16 +18,18 @@ pub enum Colormap { Plasma = 4, Turbo = 5, Viridis = 6, + CyanToYellow = 7, } impl Colormap { - pub const ALL: [Self; 6] = [ + pub const ALL: [Self; 7] = [ Self::Grayscale, Self::Inferno, Self::Magma, Self::Plasma, Self::Turbo, Self::Viridis, + Self::CyanToYellow, ]; } @@ -40,6 +42,7 @@ impl std::fmt::Display for Colormap { Self::Plasma => write!(f, "Plasma"), Self::Turbo => write!(f, "Turbo"), Self::Viridis => write!(f, "Viridis"), + Self::CyanToYellow => write!(f, "CyanToYellow"), } } } @@ -52,6 +55,7 @@ pub fn colormap_srgb(which: Colormap, t: f32) -> [u8; 4] { Colormap::Plasma => colormap_plasma_srgb(t), Colormap::Magma => colormap_magma_srgb(t), Colormap::Inferno => colormap_inferno_srgb(t), + Colormap::CyanToYellow => colormap_cyan_to_yellow_srgb(t), } } @@ -185,3 +189,24 @@ pub fn colormap_inferno_srgb(t: f32) -> [u8; 4] { let c = c * 255.0; [c.x as u8, c.y as u8, c.z as u8, 255] } + +// --- rasmusgo's color maps --- + +// Designed by Rasmus Brönnegård (rasmusgo) adapted from https://www.shadertoy.com/view/lfByRh. +// +// License CC0 (public domain) +// https://creativecommons.org/share-your-work/public-domain/cc0/ + +/// Returns a gamma-space sRGB in 0-255 range. +/// This is a perceptually uniform colormap which is robust to color blindness. +/// It is especially suited for visualizing signed values. +/// It interpolates from cyan to blue to dark gray to brass to yellow. +pub fn colormap_cyan_to_yellow_srgb(t: f32) -> [u8; 4] { + let t = t * 2. - 1.; + [ + ((1. + 3. * t) * (255. / 4.)).max(0.) as u8, + ((1. + 3. * t * t) * (255. / 4.)) as u8, + ((1. - 3. * t) * (255. / 4.)).max(0.) as u8, + 255, + ] +} diff --git a/crates/viewer/re_renderer/src/lib.rs b/crates/viewer/re_renderer/src/lib.rs index fa12451d951f..e3ec5fc7eae0 100644 --- a/crates/viewer/re_renderer/src/lib.rs +++ b/crates/viewer/re_renderer/src/lib.rs @@ -51,8 +51,8 @@ use allocator::GpuReadbackBuffer; pub use allocator::{CpuWriteGpuReadError, GpuReadbackIdentifier}; pub use color::Rgba32Unmul; pub use colormap::{ - colormap_inferno_srgb, colormap_magma_srgb, colormap_plasma_srgb, colormap_srgb, - colormap_turbo_srgb, colormap_viridis_srgb, grayscale_srgb, Colormap, + colormap_cyan_to_yellow_srgb, colormap_inferno_srgb, colormap_magma_srgb, colormap_plasma_srgb, + colormap_srgb, colormap_turbo_srgb, colormap_viridis_srgb, grayscale_srgb, Colormap, }; pub use context::{adapter_info_summary, RenderContext, RenderContextError}; pub use debug_label::DebugLabel; diff --git a/crates/viewer/re_viewer_context/src/gpu_bridge/colormap.rs b/crates/viewer/re_viewer_context/src/gpu_bridge/colormap.rs index 700e2feda27f..5660a0b24938 100644 --- a/crates/viewer/re_viewer_context/src/gpu_bridge/colormap.rs +++ b/crates/viewer/re_viewer_context/src/gpu_bridge/colormap.rs @@ -160,5 +160,6 @@ pub fn colormap_to_re_renderer(colormap: re_types::components::Colormap) -> re_r re_types::components::Colormap::Plasma => re_renderer::Colormap::Plasma, re_types::components::Colormap::Turbo => re_renderer::Colormap::Turbo, re_types::components::Colormap::Viridis => re_renderer::Colormap::Viridis, + re_types::components::Colormap::CyanToYellow => re_renderer::Colormap::CyanToYellow, } } diff --git a/docs/content/reference/types/components/colormap.md b/docs/content/reference/types/components/colormap.md index be50fd6208eb..6f91463556d9 100644 --- a/docs/content/reference/types/components/colormap.md +++ b/docs/content/reference/types/components/colormap.md @@ -17,6 +17,7 @@ but currently the Viewer is limited to the types defined here. * Plasma * Turbo * Viridis +* CyanToYellow ## API reference links * 🌊 [C++ API docs for `Colormap`](https://ref.rerun.io/docs/cpp/stable/namespacererun_1_1components.html) diff --git a/rerun_cpp/src/rerun/components/colormap.cpp b/rerun_cpp/src/rerun/components/colormap.cpp index 91a3372b6b41..7ae283e3110e 100644 --- a/rerun_cpp/src/rerun/components/colormap.cpp +++ b/rerun_cpp/src/rerun/components/colormap.cpp @@ -16,6 +16,7 @@ namespace rerun { arrow::field("Plasma", arrow::null(), true), arrow::field("Turbo", arrow::null(), true), arrow::field("Viridis", arrow::null(), true), + arrow::field("CyanToYellow", arrow::null(), true), }); return datatype; } diff --git a/rerun_cpp/src/rerun/components/colormap.hpp b/rerun_cpp/src/rerun/components/colormap.hpp index 064d4ba44099..45ecce0b16d9 100644 --- a/rerun_cpp/src/rerun/components/colormap.hpp +++ b/rerun_cpp/src/rerun/components/colormap.hpp @@ -58,6 +58,13 @@ namespace rerun::components { /// This is a perceptually uniform colormap which is robust to color blindness. /// It interpolates from dark purple to green to yellow. Viridis = 6, + + /// Rasmusgo's Cyan to Yellow colormap + /// + /// This is a perceptually uniform colormap which is robust to color blindness. + /// It is especially suited for visualizing signed values. + /// It interpolates from cyan to blue to dark gray to brass to yellow. + CyanToYellow = 7, }; } // namespace rerun::components diff --git a/rerun_py/rerun_sdk/rerun/components/colormap.py b/rerun_py/rerun_sdk/rerun/components/colormap.py index 0e8c78b4a8fa..77449d594acf 100644 --- a/rerun_py/rerun_sdk/rerun/components/colormap.py +++ b/rerun_py/rerun_sdk/rerun/components/colormap.py @@ -79,8 +79,17 @@ class Colormap(Enum): It interpolates from dark purple to green to yellow. """ + CyanToYellow = 7 + """ + Rasmusgo's Cyan to Yellow colormap + + This is a perceptually uniform colormap which is robust to color blindness. + It is especially suited for visualizing signed values. + It interpolates from cyan to blue to dark gray to brass to yellow. + """ + -ColormapLike = Union[Colormap, Literal["grayscale", "inferno", "magma", "plasma", "turbo", "viridis"]] +ColormapLike = Union[Colormap, Literal["grayscale", "inferno", "magma", "plasma", "turbo", "viridis", "cyantoyellow"]] ColormapArrayLike = Union[ColormapLike, Sequence[ColormapLike]] @@ -98,6 +107,7 @@ def __init__(self) -> None: pa.field("Plasma", pa.null(), nullable=True, metadata={}), pa.field("Turbo", pa.null(), nullable=True, metadata={}), pa.field("Viridis", pa.null(), nullable=True, metadata={}), + pa.field("CyanToYellow", pa.null(), nullable=True, metadata={}), ]), self._TYPE_NAME, ) @@ -135,6 +145,8 @@ def _native_to_pa_array(data: ColormapArrayLike, data_type: pa.DataType) -> pa.A types.append(Colormap.Turbo.value) elif value.lower() == "viridis": types.append(Colormap.Viridis.value) + elif value.lower() == "cyantoyellow": + types.append(Colormap.CyanToYellow.value) else: raise ValueError(f"Unknown Colormap kind: {value}") else: @@ -144,7 +156,7 @@ def _native_to_pa_array(data: ColormapArrayLike, data_type: pa.DataType) -> pa.A None, pa.array(types, type=pa.int8()).buffers()[1], ] - children = (1 + 6) * [pa.nulls(len(data))] + children = (1 + 7) * [pa.nulls(len(data))] return pa.UnionArray.from_buffers( type=data_type,