Skip to content

Commit b64a438

Browse files
authored
Integrate GPU color maps into depth clouds (#1486)
* integrate color maps into depth clouds * clean mess * pad
1 parent 2a73bfc commit b64a438

File tree

7 files changed

+146
-11
lines changed

7 files changed

+146
-11
lines changed

crates/re_data_store/src/entity_properties.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ pub struct EntityProperties {
4747
pub visible_history: ExtraQueryHistory,
4848
pub interactive: bool,
4949

50+
/// Enable color mapping?
51+
///
52+
/// See [`Self::color_mapper`] to select an actual mapping.
53+
pub color_mapping: bool,
54+
/// What kind of color mapping should be applied (none, map, texture, transfer..)?
55+
pub color_mapper: EditableAutoValue<ColorMapper>,
56+
5057
/// Distance of the projection plane (frustum far plane).
5158
///
5259
/// Only applies to pinhole cameras when in a spatial view, using 3D navigation.
53-
///
5460
pub pinhole_image_plane_distance: EditableAutoValue<f32>,
5561

5662
/// Should the depth texture be backprojected into a point cloud?
@@ -76,10 +82,15 @@ impl EntityProperties {
7682
visible: self.visible && child.visible,
7783
visible_history: self.visible_history.with_child(&child.visible_history),
7884
interactive: self.interactive && child.interactive,
85+
86+
color_mapping: self.color_mapping || child.color_mapping,
87+
color_mapper: self.color_mapper.or(&child.color_mapper).clone(),
88+
7989
pinhole_image_plane_distance: self
8090
.pinhole_image_plane_distance
8191
.or(&child.pinhole_image_plane_distance)
8292
.clone(),
93+
8394
backproject_depth: self.backproject_depth || child.backproject_depth,
8495
backproject_pinhole_ent_path: self
8596
.backproject_pinhole_ent_path
@@ -101,6 +112,8 @@ impl Default for EntityProperties {
101112
visible: true,
102113
visible_history: ExtraQueryHistory::default(),
103114
interactive: true,
115+
color_mapping: false,
116+
color_mapper: EditableAutoValue::default(),
104117
pinhole_image_plane_distance: EditableAutoValue::default(),
105118
backproject_depth: false,
106119
backproject_pinhole_ent_path: None,
@@ -133,6 +146,53 @@ impl ExtraQueryHistory {
133146
sequences: self.sequences.max(child.sequences),
134147
}
135148
}
149+
} // ----------------------------------------------------------------------------
150+
151+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
152+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
153+
pub enum ColorMap {
154+
Grayscale,
155+
Turbo,
156+
Viridis,
157+
Plasma,
158+
Magma,
159+
Inferno,
160+
}
161+
162+
impl std::fmt::Display for ColorMap {
163+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164+
f.write_str(match self {
165+
ColorMap::Grayscale => "Grayscale",
166+
ColorMap::Turbo => "Turbo",
167+
ColorMap::Viridis => "Viridis",
168+
ColorMap::Plasma => "Plasma",
169+
ColorMap::Magma => "Magma",
170+
ColorMap::Inferno => "Inferno",
171+
})
172+
}
173+
}
174+
175+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
176+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
177+
pub enum ColorMapper {
178+
/// Use a well-known color map, pre-implemented as a wgsl module.
179+
ColorMap(ColorMap),
180+
// TODO(cmc): support textures.
181+
// TODO(cmc): support custom transfer functions.
182+
}
183+
184+
impl std::fmt::Display for ColorMapper {
185+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186+
match self {
187+
ColorMapper::ColorMap(colormap) => colormap.fmt(f),
188+
}
189+
}
190+
}
191+
192+
impl Default for ColorMapper {
193+
fn default() -> Self {
194+
Self::ColorMap(ColorMap::Grayscale)
195+
}
136196
}
137197

138198
// ----------------------------------------------------------------------------

crates/re_renderer/examples/depth_cloud.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ impl RenderDepthClouds {
178178
radius_scale: *radius_scale,
179179
depth_dimensions: depth.dimensions,
180180
depth_data: depth.data.clone(),
181+
colormap: re_renderer::ColorMap::ColorMapTurbo,
181182
}],
182183
)
183184
.unwrap();

crates/re_renderer/shader/colormap.wgsl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ const COLORMAP_INFERNO: u32 = 5u;
1111

1212
fn colormap_srgb(which: u32, t: f32) -> Vec3 {
1313
if which == COLORMAP_TURBO {
14-
return colormap_turbo(t);
14+
return colormap_turbo_srgb(t);
1515
} else if which == COLORMAP_VIRIDIS {
16-
return colormap_viridis(t);
16+
return colormap_viridis_srgb(t);
1717
} else if which == COLORMAP_PLASMA {
18-
return colormap_plasma(t);
18+
return colormap_plasma_srgb(t);
1919
} else if which == COLORMAP_MAGMA {
20-
return colormap_magma(t);
20+
return colormap_magma_srgb(t);
2121
} else if which == COLORMAP_INFERNO {
22-
return colormap_inferno(t);
22+
return colormap_inferno_srgb(t);
2323
} else { // assume grayscale
2424
return linear_from_srgb(Vec3(t));
2525
}

crates/re_renderer/shader/depth_cloud.wgsl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! See `src/renderer/depth_cloud.rs` for more documentation.
44

5+
#import <./colormap.wgsl>
56
#import <./global_bindings.wgsl>
67
#import <./types.wgsl>
78
#import <./utils/camera.wgsl>
@@ -26,8 +27,8 @@ fn compute_point_data(quad_idx: i32) -> PointData {
2627
// TODO(cmc): expose knobs to linearize/normalize/flip/cam-to-plane depth.
2728
let norm_linear_depth = textureLoad(depth_texture, texcoords, 0).x;
2829

29-
// TODO(cmc): support color maps & albedo textures
30-
let color = Vec4(linear_from_srgb(Vec3(norm_linear_depth)), 1.0);
30+
// TODO(cmc): albedo textures
31+
let color = Vec4(colormap_srgb(depth_cloud_info.colormap, norm_linear_depth), 1.0);
3132

3233
// TODO(cmc): This assumes a pinhole camera; need to support other kinds at some point.
3334
let intrinsics = depth_cloud_info.depth_camera_intrinsics;
@@ -62,6 +63,12 @@ struct DepthCloudInfo {
6263

6364
/// The scale to apply to the radii of the backprojected points.
6465
radius_scale: f32,
66+
radius_scale_row_pad0: f32,
67+
radius_scale_row_pad1: f32,
68+
radius_scale_row_pad2: f32,
69+
70+
/// Configures color mapping mode, see `colormap.wgsl`.
71+
colormap: u32,
6572
};
6673
@group(1) @binding(0)
6774
var<uniform> depth_cloud_info: DepthCloudInfo;

crates/re_renderer/src/renderer/depth_cloud.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::{
2424
GpuRenderPipelineHandle, GpuTexture, PipelineLayoutDesc, RenderPipelineDesc,
2525
ShaderModuleDesc, TextureDesc,
2626
},
27+
ColorMap,
2728
};
2829

2930
use super::{
@@ -42,8 +43,9 @@ mod gpu_data {
4243
pub depth_camera_extrinsics: crate::wgpu_buffer_types::Mat4,
4344
pub depth_camera_intrinsics: crate::wgpu_buffer_types::Mat3,
4445
pub radius_scale: crate::wgpu_buffer_types::F32RowPadded,
46+
pub colormap: crate::wgpu_buffer_types::U32RowPadded,
4547

46-
pub end_padding: [crate::wgpu_buffer_types::PaddingRow; 16 - 8],
48+
pub end_padding: [crate::wgpu_buffer_types::PaddingRow; 16 - 9],
4749
}
4850
}
4951

@@ -89,6 +91,9 @@ pub struct DepthCloud {
8991
///
9092
/// See [`DepthCloudDepthData`] for more information.
9193
pub depth_data: DepthCloudDepthData,
94+
95+
/// Configures color mapping mode.
96+
pub colormap: ColorMap,
9297
}
9398

9499
impl Default for DepthCloud {
@@ -99,6 +104,7 @@ impl Default for DepthCloud {
99104
radius_scale: 1.0,
100105
depth_dimensions: glam::UVec2::ZERO,
101106
depth_data: DepthCloudDepthData::default(),
107+
colormap: ColorMap::ColorMapTurbo,
102108
}
103109
}
104110
}
@@ -144,6 +150,7 @@ impl DepthCloudDrawData {
144150
depth_camera_extrinsics: info.depth_camera_extrinsics.into(),
145151
depth_camera_intrinsics: info.depth_camera_intrinsics.into(),
146152
radius_scale: info.radius_scale.into(),
153+
colormap: (info.colormap as u32).into(),
147154
end_padding: Default::default(),
148155
}),
149156
);

crates/re_viewer/src/ui/selection_panel.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use egui::NumExt as _;
2-
use re_data_store::{query_latest_single, EditableAutoValue, EntityPath, EntityProperties};
2+
use re_data_store::{
3+
query_latest_single, ColorMap, ColorMapper, EditableAutoValue, EntityPath, EntityProperties,
4+
};
35
use re_log_types::{
46
component_types::{Tensor, TensorDataMeaning},
57
TimeType, Transform,
@@ -418,6 +420,45 @@ fn entity_props_ui(
418420
});
419421
}
420422

423+
fn colormap_props_ui(ui: &mut egui::Ui, entity_props: &mut EntityProperties) {
424+
ui.checkbox(&mut entity_props.color_mapping, "Color mapping")
425+
.on_hover_text("Toggles color mapping");
426+
ui.end_row();
427+
428+
if !entity_props.color_mapping {
429+
return;
430+
}
431+
432+
let current = *entity_props.color_mapper.get();
433+
434+
ui.label("Color map");
435+
egui::ComboBox::from_id_source("color_mapper")
436+
.selected_text(current.to_string())
437+
.show_ui(ui, |ui| {
438+
ui.style_mut().wrap = Some(false);
439+
ui.set_min_width(64.0);
440+
441+
// TODO(cmc): that is not ideal but I don't want to import yet another proc-macro...
442+
let mut add_label = |proposed| {
443+
if ui
444+
.selectable_label(current == proposed, proposed.to_string())
445+
.clicked()
446+
{
447+
entity_props.color_mapper = EditableAutoValue::Auto(proposed);
448+
}
449+
};
450+
451+
add_label(ColorMapper::ColorMap(ColorMap::Grayscale));
452+
add_label(ColorMapper::ColorMap(ColorMap::Turbo));
453+
add_label(ColorMapper::ColorMap(ColorMap::Viridis));
454+
add_label(ColorMapper::ColorMap(ColorMap::Plasma));
455+
add_label(ColorMapper::ColorMap(ColorMap::Magma));
456+
add_label(ColorMapper::ColorMap(ColorMap::Inferno));
457+
});
458+
459+
ui.end_row();
460+
}
461+
421462
fn pinhole_props_ui(
422463
ctx: &mut ViewerContext<'_>,
423464
ui: &mut egui::Ui,
@@ -520,6 +561,10 @@ fn depth_props_ui(
520561
entity_props.backproject_radius_scale = EditableAutoValue::UserEdited(radius_scale);
521562
}
522563
ui.end_row();
564+
565+
// TODO(cmc): This should apply to the depth map entity as a whole, but for that we
566+
// need to get the current hardcoded colormapping out of the image cache first.
567+
colormap_props_ui(ui, entity_props);
523568
} else {
524569
entity_props.backproject_pinhole_ent_path = None;
525570
}

crates/re_viewer/src/ui/view_spatial/scene/scene_part/images.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use re_log_types::{
1313
use re_query::{query_primary_with_history, EntityView, QueryError};
1414
use re_renderer::{
1515
renderer::{DepthCloud, DepthCloudDepthData},
16-
Size,
16+
ColorMap, Size,
1717
};
1818

1919
use crate::{
@@ -307,12 +307,27 @@ impl ImagesPart {
307307

308308
let world_from_obj = extrinsics * glam::Mat4::from_scale(glam::Vec3::splat(scale));
309309

310+
let colormap = properties
311+
.color_mapping
312+
.then(|| match *properties.color_mapper.get() {
313+
re_data_store::ColorMapper::ColorMap(colormap) => match colormap {
314+
re_data_store::ColorMap::Grayscale => ColorMap::Grayscale,
315+
re_data_store::ColorMap::Turbo => ColorMap::ColorMapTurbo,
316+
re_data_store::ColorMap::Viridis => ColorMap::ColorMapViridis,
317+
re_data_store::ColorMap::Plasma => ColorMap::ColorMapPlasma,
318+
re_data_store::ColorMap::Magma => ColorMap::ColorMapMagma,
319+
re_data_store::ColorMap::Inferno => ColorMap::ColorMapInferno,
320+
},
321+
})
322+
.unwrap_or(ColorMap::Grayscale);
323+
310324
scene.primitives.depth_clouds.push(DepthCloud {
311325
depth_camera_extrinsics: world_from_obj,
312326
depth_camera_intrinsics: intrinsics.image_from_cam.into(),
313327
radius_scale,
314328
depth_dimensions: dimensions,
315329
depth_data: data,
330+
colormap,
316331
});
317332
}
318333
}

0 commit comments

Comments
 (0)