Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show previews of colormaps when selecting them #1846

Merged
merged 3 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions crates/re_viewer/src/gpu_bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn viewport_resolution_in_pixels(clip_rect: egui::Rect, pixels_from_point: f
[resolution.x as u32, resolution.y as u32]
}

pub fn get_or_create_texture<'a, Err>(
pub fn try_get_or_create_texture<'a, Err>(
render_ctx: &mut RenderContext,
texture_key: u64,
try_create_texture_desc: impl FnOnce() -> Result<Texture2DCreationDesc<'a>, Err>,
Expand All @@ -64,6 +64,23 @@ pub fn get_or_create_texture<'a, Err>(
)
}

pub fn get_or_create_texture<'a>(
render_ctx: &mut RenderContext,
texture_key: u64,
create_texture_desc: impl FnOnce() -> Texture2DCreationDesc<'a>,
) -> GpuTexture2DHandle {
enum Never {}
let result: Result<GpuTexture2DHandle, Never> = render_ctx
.texture_manager_2d
.get_or_create_with(texture_key, &mut render_ctx.gpu_resources.textures, || {
Ok(create_texture_desc())
});
match result {
Ok(handle) => handle,
Err(never) => match never {},
}
}

/// Render a `re_render` view using the given clip rectangle.
pub fn renderer_paint_callback(
render_ctx: &mut re_renderer::RenderContext,
Expand Down Expand Up @@ -132,6 +149,11 @@ pub fn render_image(

use re_renderer::renderer::{TextureFilterMag, TextureFilterMin};

let clip_rect = painter.clip_rect().intersect(image_rect_on_screen);
if !clip_rect.is_positive() {
return Ok(());
}

// Where in "world space" to paint the image.
let space_rect = egui::Rect::from_min_size(egui::Pos2::ZERO, image_rect_on_screen.size());

Expand Down Expand Up @@ -163,10 +185,10 @@ pub fn render_image(
let space_from_pixel = space_from_points * points_from_pixels;

let resolution_in_pixel =
crate::gpu_bridge::viewport_resolution_in_pixels(painter.clip_rect(), pixels_from_points);
crate::gpu_bridge::viewport_resolution_in_pixels(clip_rect, pixels_from_points);
anyhow::ensure!(resolution_in_pixel[0] > 0 && resolution_in_pixel[1] > 0);

let camera_position_space = space_from_ui.transform_pos(painter.clip_rect().min);
let camera_position_space = space_from_ui.transform_pos(clip_rect.min);

let top_left_position = glam::vec2(camera_position_space.x, camera_position_space.y);
let target_config = re_renderer::view_builder::TargetConfiguration {
Expand Down Expand Up @@ -196,7 +218,7 @@ pub fn render_image(
render_ctx,
command_buffer,
view_builder,
painter.clip_rect(),
clip_rect,
painter.ctx().pixels_per_point(),
));

Expand Down
23 changes: 10 additions & 13 deletions crates/re_viewer/src/gpu_bridge/tensor_to_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use re_renderer::{
RenderContext,
};

use crate::misc::caches::TensorStats;
use crate::{gpu_bridge::get_or_create_texture, misc::caches::TensorStats};

use super::get_or_create_texture;
use super::try_get_or_create_texture;

// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -63,7 +63,7 @@ fn color_tensor_to_gpu(
tensor: &Tensor,
tensor_stats: &TensorStats,
) -> anyhow::Result<ColormappedTexture> {
let texture_handle = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let texture_handle = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
let [height, width, depth] = height_width_depth(tensor)?;
let (data, format) = match (depth, &tensor.data) {
// Use R8Unorm and R8Snorm to get filtering on the GPU:
Expand Down Expand Up @@ -161,10 +161,8 @@ fn class_id_tensor_to_gpu(
let colormap_width = 256;
let colormap_height = (max as usize + colormap_width - 1) / colormap_width;

let colormap_texture_handle = get_or_create_texture(
render_ctx,
hash(annotations.row_id),
|| -> anyhow::Result<_> {
let colormap_texture_handle =
get_or_create_texture(render_ctx, hash(annotations.row_id), || {
let data: Vec<u8> = (0..(colormap_width * colormap_height))
.flat_map(|id| {
let color = annotations
Expand All @@ -175,17 +173,16 @@ fn class_id_tensor_to_gpu(
})
.collect();

Ok(Texture2DCreationDesc {
Texture2DCreationDesc {
label: "class_id_colormap".into(),
data: data.into(),
format: TextureFormat::Rgba8UnormSrgb,
width: colormap_width as u32,
height: colormap_height as u32,
})
},
)?;
}
});

let main_texture_handle = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let main_texture_handle = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
general_texture_creation_desc_from_tensor(debug_name, tensor)
})?;

Expand Down Expand Up @@ -214,7 +211,7 @@ fn depth_tensor_to_gpu(
);
let (min, max) = depth_tensor_range(tensor, tensor_stats)?;

let texture = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let texture = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
general_texture_creation_desc_from_tensor(debug_name, tensor)
})?;

Expand Down
2 changes: 1 addition & 1 deletion crates/re_viewer/src/ui/view_tensor/tensor_slice_to_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn upload_texture_slice_to_gpu(
) -> Result<re_renderer::resource_managers::GpuTexture2DHandle, TensorUploadError> {
let id = egui::util::hash((tensor.id(), slice_selection));

crate::gpu_bridge::get_or_create_texture(render_ctx, id, || {
crate::gpu_bridge::try_get_or_create_texture(render_ctx, id, || {
texture_desc_from_tensor(tensor, slice_selection)
})
}
Expand Down
87 changes: 82 additions & 5 deletions crates/re_viewer/src/ui/view_tensor/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl ViewTensorState {
Some(ctx.cache.tensor_stats(tensor)),
);
self.texture_settings.ui(ctx.re_ui, ui);
self.color_mapping.ui(ctx.re_ui, ui);
self.color_mapping.ui(ctx.render_ctx, ctx.re_ui, ui);
});

ui.separator();
Expand Down Expand Up @@ -245,17 +245,29 @@ impl Default for ColorMapping {
}

impl ColorMapping {
fn ui(&mut self, re_ui: &re_ui::ReUi, ui: &mut egui::Ui) {
fn ui(
&mut self,
render_ctx: &mut re_renderer::RenderContext,
re_ui: &re_ui::ReUi,
ui: &mut egui::Ui,
) {
let ColorMapping { map, gamma } = self;

re_ui.grid_left_hand_label(ui, "Color map");
egui::ComboBox::from_id_source("color map select")
.selected_text(map.to_string())
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
for option in Colormap::ALL {
ui.selectable_value(map, option, option.to_string());
}

egui::Grid::new("colormap_selector")
.num_columns(2)
.show(ui, |ui| {
for option in Colormap::ALL {
ui.selectable_value(map, option, option.to_string());
colormap_preview_ui(render_ctx, ui, option);
ui.end_row();
}
});
});
ui.end_row();

Expand All @@ -267,6 +279,71 @@ impl ColorMapping {
}
}

/// Show the given colormap as a horizontal bar.
fn colormap_preview_ui(
render_ctx: &mut re_renderer::RenderContext,
ui: &mut egui::Ui,
colormap: Colormap,
) -> egui::Response {
crate::profile_function!();

let desired_size = egui::vec2(128.0, 16.0);
let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::hover());

if ui.is_rect_visible(rect) {
if let Err(err) = paint_colormap_gradient(render_ctx, colormap, ui, rect) {
re_log::error_once!("Failed to paint colormap preview: {err}");
}
}

response
}

fn paint_colormap_gradient(
render_ctx: &mut re_renderer::RenderContext,
colormap: Colormap,
ui: &mut egui::Ui,
rect: egui::Rect,
) -> anyhow::Result<()> {
let horizontal_gradient_id = egui::util::hash("horizontal_gradient");
let horizontal_gradient =
crate::gpu_bridge::get_or_create_texture(render_ctx, horizontal_gradient_id, || {
let width = 256;
let height = 1;
let data: Vec<u8> = (0..width)
.flat_map(|x| {
let t = x as f32 / (width as f32 - 1.0);
half::f16::from_f32(t).to_le_bytes()
})
.collect();

re_renderer::resource_managers::Texture2DCreationDesc {
label: "horizontal_gradient".into(),
data: data.into(),
format: wgpu::TextureFormat::R16Float,
width,
height,
}
});

let colormapped_texture = re_renderer::renderer::ColormappedTexture {
texture: horizontal_gradient,
range: [0.0, 1.0],
gamma: 1.0,
color_mapper: Some(re_renderer::renderer::ColorMapper::Function(colormap)),
};

let debug_name = format!("colormap_{colormap}");
crate::gpu_bridge::render_image(
render_ctx,
ui.painter(),
rect,
colormapped_texture,
egui::TextureOptions::LINEAR,
&debug_name,
)
}

// ----------------------------------------------------------------------------

/// Should we scale the rendered texture, and if so, how?
Expand Down