Skip to content

Commit

Permalink
heuristic for camera frustum length is now based on scene size (#1433)
Browse files Browse the repository at this point in the history
Introduces `EditableAutoValue` and per-frame heuristic updates on properties. In the future we can build more properties on top of this and update them in a central place like done here
  • Loading branch information
Wumpf authored and emilk committed Mar 2, 2023
1 parent edcd0a3 commit b7deb0d
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 38 deletions.
52 changes: 52 additions & 0 deletions crates/re_data_store/src/editable_auto_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// A value that is either determined automatically by some heuristic, or specified by the user.
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, Eq, PartialEq)]
#[serde(bound = "T: serde::Serialize, for<'de2> T: serde::Deserialize<'de2>")]
pub enum EditableAutoValue<T>
where
T: std::fmt::Debug + Eq + PartialEq + Clone + Default + serde::Serialize,
for<'de2> T: serde::Deserialize<'de2>,
{
/// The user explicitly specified what they wanted
UserEdited(T),

/// The value is determined automatically.
///
/// We may update this at any time or interpret the value stored here differently under certain circumstances.
Auto(T),
}

impl<T> Default for EditableAutoValue<T>
where
T: std::fmt::Debug + Eq + PartialEq + Clone + Default + serde::Serialize,
for<'de2> T: serde::Deserialize<'de2>,
{
fn default() -> Self {
EditableAutoValue::Auto(T::default())
}
}

impl<T> EditableAutoValue<T>
where
T: std::fmt::Debug + Eq + PartialEq + Clone + Default + serde::Serialize,
for<'de2> T: serde::Deserialize<'de2>,
{
pub fn is_auto(&self) -> bool {
matches!(self, EditableAutoValue::Auto(_))
}

/// Gets the value, disregarding if it was user edited or determined by a heuristic.
pub fn get(&self) -> &T {
match self {
EditableAutoValue::Auto(v) | EditableAutoValue::UserEdited(v) => v,
}
}

/// Returns other if self is auto, self otherwise.
pub fn or<'a>(&'a self, other: &'a EditableAutoValue<T>) -> &'a EditableAutoValue<T> {
if self.is_auto() {
other
} else {
self
}
}
}
35 changes: 7 additions & 28 deletions crates/re_data_store/src/entity_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use re_log_types::{
msg_bundle::DeserializableComponent, EntityPath,
};

use crate::log_db::EntityDb;
use crate::{log_db::EntityDb, EditableAutoValue};

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

Expand Down Expand Up @@ -39,44 +39,23 @@ pub struct EntityProperties {
pub visible_history: ExtraQueryHistory,
pub interactive: bool,

/// Distance of the projection plane.
/// Distance of the projection plane (frustum far plane).
///
/// Only applies to pinhole cameras when in a spatial view, using 3D navigation.
pinhole_image_plane_distance: Option<ordered_float::NotNan<f32>>,
pub pinhole_image_plane_distance: EditableAutoValue<ordered_float::NotNan<f32>>,
}

impl EntityProperties {
/// If this has a pinhole camera transform, how far away is the image plane.
///
/// Scale relative to the respective space the pinhole camera is in.
/// None indicates the user never edited this field (should use a meaningful default then).
///
/// Method returns a pinhole camera specific default if the value hasn't been set yet.
pub fn pinhole_image_plane_distance(&self, pinhole: &re_log_types::Pinhole) -> f32 {
self.pinhole_image_plane_distance
.unwrap_or_else(|| {
let distance = pinhole
.focal_length()
.unwrap_or_else(|| pinhole.focal_length_in_pixels().y());
ordered_float::NotNan::new(distance).unwrap_or_default()
})
.into()
}

/// see `pinhole_image_plane_distance()`
pub fn set_pinhole_image_plane_distance(&mut self, distance: f32) {
self.pinhole_image_plane_distance = ordered_float::NotNan::new(distance).ok();
}

/// Multiply/and these together.
pub fn with_child(&self, child: &Self) -> Self {
Self {
visible: self.visible && child.visible,
visible_history: self.visible_history.with_child(&child.visible_history),
interactive: self.interactive && child.interactive,
pinhole_image_plane_distance: child
pinhole_image_plane_distance: self
.pinhole_image_plane_distance
.or(self.pinhole_image_plane_distance),
.or(&child.pinhole_image_plane_distance)
.clone(),
}
}
}
Expand All @@ -87,7 +66,7 @@ impl Default for EntityProperties {
visible: true,
visible_history: ExtraQueryHistory::default(),
interactive: true,
pinhole_image_plane_distance: None,
pinhole_image_plane_distance: EditableAutoValue::default(),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/re_data_store/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![doc = document_features::document_features!()]
//!

mod editable_auto_value;
pub mod entity_properties;
pub mod entity_tree;
mod instance_path;
Expand All @@ -16,6 +17,7 @@ pub use log_db::LogDb;

use re_log_types::msg_bundle;

pub use editable_auto_value::EditableAutoValue;
pub use re_log_types::{ComponentName, EntityPath, EntityPathPart, Index, TimeInt, Timeline};

// ----------------------------------------------------------------------------
Expand Down
6 changes: 2 additions & 4 deletions crates/re_viewer/src/misc/transform_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,8 @@ fn transform_at(
// A pinhole camera means that we're looking at an image.
// Images are spanned in their local x/y space.
// Center it and move it along z, scaling the further we move.

let distance = entity_properties
.get(entity_path)
.pinhole_image_plane_distance(&pinhole);
let props = entity_properties.get(entity_path);
let distance: f32 = props.pinhole_image_plane_distance.get().into_inner();

let focal_length = pinhole.focal_length_in_pixels();
let focal_length = glam::vec2(focal_length.x(), focal_length.y());
Expand Down
12 changes: 8 additions & 4 deletions crates/re_viewer/src/ui/selection_panel.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use re_data_store::{query_latest_single, EntityPath, EntityProperties};
use re_data_store::{query_latest_single, EditableAutoValue, EntityPath, EntityProperties};
use re_log_types::{TimeType, Transform};

use crate::{
Expand Down Expand Up @@ -411,11 +411,12 @@ fn entity_props_ui(
if view_state.state_spatial.nav_mode == SpatialNavigationMode::ThreeD {
if let Some(entity_path) = entity_path {
let query = ctx.current_query();
if let Some(re_log_types::Transform::Pinhole(pinhole)) =
if let Some(re_log_types::Transform::Pinhole(_)) =
query_latest_single::<Transform>(&ctx.log_db.entity_db, entity_path, &query)
{
ui.label("Image plane distance");
let mut distance = entity_props.pinhole_image_plane_distance(&pinhole);
let mut distance: f32 =
entity_props.pinhole_image_plane_distance.get().into_inner();
let speed = (distance * 0.05).at_least(0.01);
if ui
.add(
Expand All @@ -426,7 +427,10 @@ fn entity_props_ui(
.on_hover_text("Controls how far away the image plane is.")
.changed()
{
entity_props.set_pinhole_image_plane_distance(distance);
entity_props.pinhole_image_plane_distance =
EditableAutoValue::UserEdited(
ordered_float::NotNan::new(distance).unwrap(),
);
}
ui.end_row();
}
Expand Down
3 changes: 3 additions & 0 deletions crates/re_viewer/src/ui/space_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ impl SpaceView {
);
let mut scene = view_spatial::SceneSpatial::new(ctx.render_ctx);
scene.load(ctx, &query, &transforms, highlights);
self.view_state
.state_spatial
.update_object_property_heuristics(ctx, &mut self.data_blueprint);
self.view_state
.ui_spatial(ctx, ui, &self.space_path, scene, self.id, highlights);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl CamerasPart {
return;
};

let frustum_length = props.pinhole_image_plane_distance(&pinhole);
let frustum_length: f32 = props.pinhole_image_plane_distance.get().into_inner();

scene.space_cameras.push(SpaceCamera3D {
entity_path: entity_path.clone(),
Expand Down
42 changes: 41 additions & 1 deletion crates/re_viewer/src/ui/view_spatial/ui.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use re_data_store::EntityPath;
use re_data_store::{query_latest_single, EditableAutoValue, EntityPath};
use re_format::format_f32;

use egui::{NumExt, WidgetText};
Expand Down Expand Up @@ -147,6 +147,46 @@ impl ViewSpatialState {
heuristic0.min(heuristic1)
}

pub fn update_object_property_heuristics(
&self,
ctx: &mut ViewerContext<'_>,
data_blueprint: &mut DataBlueprintTree,
) {
crate::profile_function!();

let scene_size = self.scene_bbox_accum.size().length();
let default_image_plane_distance = if scene_size.is_finite() && scene_size > 0.0 {
scene_size * 0.05
} else {
1.0
};

let query = ctx.current_query();

let entity_paths = data_blueprint.entity_paths().clone(); // TODO(andreas): Workaround borrow checker
for entity_path in entity_paths {
if let Some(re_log_types::Transform::Pinhole(_)) =
query_latest_single::<re_log_types::Transform>(
&ctx.log_db.entity_db,
&entity_path,
&query,
)
{
let mut properties = data_blueprint
.data_blueprints_individual()
.get(&entity_path);
if properties.pinhole_image_plane_distance.is_auto() {
properties.pinhole_image_plane_distance = EditableAutoValue::Auto(
ordered_float::NotNan::new(default_image_plane_distance).unwrap(),
);
data_blueprint
.data_blueprints_individual()
.set(entity_path, properties);
}
}
}
}

pub fn selection_ui(
&mut self,
ctx: &mut ViewerContext<'_>,
Expand Down

0 comments on commit b7deb0d

Please sign in to comment.