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

Improve log_pinhole and support non-RDF pinholes #2614

Merged
merged 67 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
81599ef
remove somewhat redundant SpaceSpecs
Wumpf Jun 28, 2023
a91c502
Camera frustums orient now correctly along view coordinates
Wumpf Jun 28, 2023
881343b
don't cache view coordinates on space view state
Wumpf Jun 28, 2023
eced0ca
remove unused unproject_as_ray method
Wumpf Jun 28, 2023
49b3f1e
fix camera ray and make image coordinate convention more explicit
Wumpf Jun 28, 2023
ba27b00
3D to 2D hover point projection works now also with weird view coordi…
Wumpf Jun 28, 2023
c39606f
use RUB/RDF constants and remove misleading comment about defaults. u…
Wumpf Jun 29, 2023
f57a3f5
add test scene for view coordinates
Wumpf Jun 29, 2023
228dbbf
fix frustum ray casting not working on left handed coordinate systems
Wumpf Jun 29, 2023
816b4b2
Merge remote-tracking branch 'origin/main' into andreas/fix-frustum-v…
Wumpf Jun 29, 2023
399c6d9
add arrows to the pinhole zoo
Wumpf Jun 29, 2023
c52fe59
Merge branch 'main' into andreas/fix-frustum-view-coordinates
emilk Jul 3, 2023
d69c7ce
Set the correct coordinate system for the camera in the OPF example
emilk Jul 3, 2023
f72a057
Import the future in the test
emilk Jul 3, 2023
24d6527
Write out the left-handed coordinates we encounter
emilk Jul 3, 2023
6c535f2
Ignore left-handed coordinate system in test
emilk Jul 3, 2023
3d33117
Make sure we lint and format test code
emilk Jul 3, 2023
c1bf004
Link to https://github.com/rerun-io/rerun/issues/1387 in docs
emilk Jul 3, 2023
b8011f5
Use `up=` argument for world coordinates
emilk Jul 3, 2023
7fd44cf
Merge branch 'main' into andreas/fix-frustum-view-coordinates
emilk Jul 5, 2023
c80616f
Inline from_rub_quat
emilk Jul 5, 2023
1e48660
Add camera_xyz=… argument to log_pinhole
emilk Jul 5, 2023
c4bbc10
Only look for the view coordinates on the pinhole entity
emilk Jul 5, 2023
4ece9fd
Better copy
emilk Jul 5, 2023
931116e
Add docstrings
emilk Jul 5, 2023
119daaf
Improve the documentation
emilk Jul 5, 2023
f84b73f
py-format
emilk Jul 5, 2023
cca15ad
Merge branch 'main' into andreas/fix-frustum-view-coordinates
emilk Jul 5, 2023
dadfda8
Test and handle depth cloud projection
emilk Jul 5, 2023
328a627
py-format and py-lint
emilk Jul 5, 2023
7735ba8
log_pinhole: no need to set matrix, just focal length
emilk Jul 5, 2023
d2bd364
Add more sanity checks to test
emilk Jul 5, 2023
9c62127
Better depth image for tests
emilk Jul 5, 2023
8a7add7
Fix RUB vs RDF in depth cloud shader
emilk Jul 5, 2023
80e73c4
Handle principal point when painting camera frustum
emilk Jul 5, 2023
4ac9358
Better naming: world_from_rub_view
emilk Jul 5, 2023
26dfb6d
py-format
emilk Jul 5, 2023
bf797bc
Track down and patch non-finite numbers
emilk Jul 5, 2023
a9d38b1
Change back default pinhole to RDF
emilk Jul 5, 2023
b76c61f
chmod +x blueprint example
emilk Jul 5, 2023
2bffc47
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 5, 2023
dea108b
chmod +x
emilk Jul 5, 2023
959952a
Remove todo
emilk Jul 5, 2023
e8ef570
build fix
emilk Jul 5, 2023
e747e91
Self-review
emilk Jul 6, 2023
1ba2063
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 6, 2023
48a7ea3
Update source_hash.txt goddammit
emilk Jul 6, 2023
5fee0c0
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 6, 2023
238ab3b
improve comment
emilk Jul 7, 2023
c8ec5d9
Add warning
emilk Jul 7, 2023
8699522
Update source_hash.txt
emilk Jul 7, 2023
7177111
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 7, 2023
c96de33
Remove unnecessary camera_xyz in rgbd example
emilk Jul 7, 2023
7aece38
be explicit
emilk Jul 7, 2023
3e2caa6
Add try-catch blocks
emilk Jul 7, 2023
ff020e7
py-format
emilk Jul 7, 2023
5f756f8
Better docstring
emilk Jul 7, 2023
62fad9c
Make RDF the default, and add helper for converting between coordinates
emilk Jul 7, 2023
8cba3af
Even better docstring
emilk Jul 7, 2023
4cddaa5
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 7, 2023
280cf1a
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 7, 2023
2075442
Improve docs even more
emilk Jul 7, 2023
ac29a55
fix typos
emilk Jul 7, 2023
7d2c4e2
FML
emilk Jul 7, 2023
309c4c5
GOD DAMMIT THERE ARE TWO OF THEM
emilk Jul 7, 2023
c65e61e
Merge branch 'main' into emilk/improve-pinhole
emilk Jul 7, 2023
a1314f7
update source_hash.txt
emilk Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
97 changes: 89 additions & 8 deletions crates/re_components/src/coordinates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ impl re_log_types::Component for ViewCoordinates {
}

impl ViewCoordinates {
/// Default right-handed pinhole, camera, and image coordinates: X=Right, Y=Down, Z=Forward.
pub const RDF: Self = Self([ViewDir::Right, ViewDir::Down, ViewDir::Forward]);

/// Default right-handed view coordinates of `re_renderer`: X=Right, Y=Up, Z=Back.
pub const RUB: Self = Self([ViewDir::Right, ViewDir::Up, ViewDir::Back]);

/// Choses a coordinate system based on just an up-axis.
pub fn from_up_and_handedness(up: SignedAxis3, handedness: Handedness) -> Self {
use ViewDir::{Back, Down, Forward, Right, Up};
Expand Down Expand Up @@ -203,18 +209,45 @@ impl ViewCoordinates {
)
}

/// Returns a matrix that translates RUB to this coordinate system.
/// Returns a matrix that transforms from another coordinate system to this (self) one.
#[cfg(feature = "glam")]
#[inline]
pub fn from_other(&self, other: &Self) -> glam::Mat3 {
self.from_rdf() * other.to_rdf()
}

/// Returns a matrix that transforms this coordinate system to RDF.
///
/// (RUB: X=Right, Y=Up, B=Back)
/// (RDF: X=Right, Y=Down, Z=Forward)
#[cfg(feature = "glam")]
#[inline]
pub fn from_rub(&self) -> glam::Mat3 {
self.to_rub().transpose()
pub fn to_rdf(&self) -> glam::Mat3 {
fn rdf(dir: ViewDir) -> [f32; 3] {
match dir {
ViewDir::Right => [1.0, 0.0, 0.0],
ViewDir::Left => [-1.0, 0.0, 0.0],
ViewDir::Up => [0.0, -1.0, 0.0],
ViewDir::Down => [0.0, 1.0, 0.0],
ViewDir::Back => [0.0, 0.0, -1.0],
ViewDir::Forward => [0.0, 0.0, 1.0],
}
}

glam::Mat3::from_cols_array_2d(&[rdf(self.0[0]), rdf(self.0[1]), rdf(self.0[2])])
}

/// Returns a matrix that transforms from RDF to this coordinate system.
///
/// (RDF: X=Right, Y=Down, Z=Forward)
#[cfg(feature = "glam")]
#[inline]
pub fn from_rdf(&self) -> glam::Mat3 {
self.to_rdf().transpose()
}

/// Returns a matrix that translates this coordinate system to RUB.
/// Returns a matrix that transforms this coordinate system to RUB.
///
/// (RUB: X=Right, Y=Up, B=Back)
/// (RUB: X=Right, Y=Up, Z=Back)
#[cfg(feature = "glam")]
#[inline]
pub fn to_rub(&self) -> glam::Mat3 {
Expand All @@ -232,11 +265,46 @@ impl ViewCoordinates {
glam::Mat3::from_cols_array_2d(&[rub(self.0[0]), rub(self.0[1]), rub(self.0[2])])
}

/// Returns a matrix that transforms from RUB to this coordinate system.
///
/// (RUB: X=Right, Y=Up, Z=Back)
#[cfg(feature = "glam")]
#[inline]
pub fn from_rub(&self) -> glam::Mat3 {
self.to_rub().transpose()
}

/// Returns a quaternion that rotates from RUB to this coordinate system.
///
/// Errors if the coordinate system is left-handed or degenerate.
///
/// (RUB: X=Right, Y=Up, Z=Back)
#[cfg(feature = "glam")]
#[inline]
pub fn from_rub_quat(&self) -> Result<glam::Quat, String> {
let mat3 = self.from_rub();

let det = mat3.determinant();
if det == 1.0 {
Ok(glam::Quat::from_mat3(&mat3))
} else if det == -1.0 {
Err(format!(
"Rerun does not yet support left-handed coordinate systems (found {})",
self.describe()
))
} else {
Err(format!(
"Found a degenerate coordinate system: {}",
self.describe()
))
}
}

#[cfg(feature = "glam")]
#[inline]
pub fn handedness(&self) -> Option<Handedness> {
let to_rub = self.to_rub();
let det = to_rub.determinant();
let to_rdf = self.to_rdf();
let det = to_rdf.determinant();
if det == -1.0 {
Some(Handedness::Left)
} else if det == 0.0 {
Expand Down Expand Up @@ -417,6 +485,14 @@ impl std::str::FromStr for SignedAxis3 {
}
}

#[cfg(feature = "glam")]
impl From<SignedAxis3> for glam::Vec3 {
#[inline]
fn from(signed_axis: SignedAxis3) -> Self {
glam::Vec3::from(signed_axis.as_vec3())
}
}

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

/// Left or right handedness. Used to describe a coordinate system.
Expand Down Expand Up @@ -453,13 +529,18 @@ impl Handedness {
fn view_coordinates() {
use glam::{vec3, Mat3};

assert_eq!(ViewCoordinates::RUB.to_rub(), Mat3::IDENTITY);
assert_eq!(ViewCoordinates::RUB.from_rub(), Mat3::IDENTITY);

{
assert!("UUDDLRLRBAStart".parse::<ViewCoordinates>().is_err());
assert!("UUD".parse::<ViewCoordinates>().is_err());

let rub = "RUB".parse::<ViewCoordinates>().unwrap();
let bru = "BRU".parse::<ViewCoordinates>().unwrap();

assert_eq!(rub, ViewCoordinates::RUB);

assert_eq!(rub.to_rub(), Mat3::IDENTITY);
assert_eq!(
bru.to_rub(),
Expand Down
4 changes: 2 additions & 2 deletions crates/re_renderer/examples/depth_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ impl RenderDepthClouds {
..
} = self;

let world_from_obj = glam::Affine3A::from_scale(glam::Vec3::splat(*scale));
let world_from_rdf = glam::Affine3A::from_scale(glam::Vec3::splat(*scale));

let depth_cloud_draw_data = DepthCloudDrawData::new(
re_ctx,
&DepthClouds {
clouds: vec![DepthCloud {
world_from_obj,
world_from_rdf,
depth_camera_intrinsics: *intrinsics,
world_depth_from_texture_depth: 1.0,
point_radius_from_world_depth: *point_radius_from_world_depth,
Expand Down
9 changes: 5 additions & 4 deletions crates/re_renderer/shader/depth_cloud.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const SAMPLE_TYPE_UINT = 3u;
/// Same for all draw-phases.
struct DepthCloudInfo {
/// The extrinsincs of the camera used for the projection.
world_from_obj: Mat4,
world_from_rdf: Mat4,

/// The intrinsics of the camera used for the projection.
///
Expand Down Expand Up @@ -127,12 +127,13 @@ fn compute_point_data(quad_idx: u32) -> PointData {
let focal_length = Vec2(intrinsics[0][0], intrinsics[1][1]);
let offset = Vec2(intrinsics[2][0], intrinsics[2][1]);

let pos_in_obj = Vec3(
// RDF: X=Right, Y=Down, Z=Forward
let pos_in_rdf = Vec3(
(Vec2(texcoords) - offset) * world_space_depth / focal_length,
world_space_depth,
world_space_depth, // RDF, Z=forward, so positive depth
);

let pos_in_world = depth_cloud_info.world_from_obj * Vec4(pos_in_obj, 1.0);
let pos_in_world = depth_cloud_info.world_from_rdf * Vec4(pos_in_rdf, 1.0);

data.pos_in_world = pos_in_world.xyz;
data.unresolved_radius = depth_cloud_info.point_radius_from_world_depth * world_space_depth;
Expand Down
13 changes: 7 additions & 6 deletions crates/re_renderer/src/renderer/depth_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ mod gpu_data {
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct DepthCloudInfoUBO {
/// The extrinsics of the camera used for the projection.
pub world_from_obj: wgpu_buffer_types::Mat4,
pub world_from_rdf: wgpu_buffer_types::Mat4,

pub depth_camera_intrinsics: wgpu_buffer_types::Mat3,

Expand Down Expand Up @@ -89,7 +89,7 @@ mod gpu_data {
depth_cloud: &super::DepthCloud,
) -> Result<Self, DepthCloudDrawDataError> {
let super::DepthCloud {
world_from_obj,
world_from_rdf: world_from_obj,
depth_camera_intrinsics,
world_depth_from_texture_depth,
point_radius_from_world_depth,
Expand All @@ -114,7 +114,7 @@ mod gpu_data {
};

Ok(Self {
world_from_obj: (*world_from_obj).into(),
world_from_rdf: (*world_from_obj).into(),
depth_camera_intrinsics: (*depth_camera_intrinsics).into(),
outline_mask_id: outline_mask_id.0.unwrap_or_default().into(),
world_depth_from_texture_depth: *world_depth_from_texture_depth,
Expand All @@ -132,8 +132,9 @@ mod gpu_data {
}

pub struct DepthCloud {
/// The extrinsics of the camera used for the projection.
pub world_from_obj: glam::Affine3A,
/// The extrinsics of the camera used for the projection,
/// with a RDF coordinate system on the right-hand side.
pub world_from_rdf: glam::Affine3A,

/// The intrinsics of the camera used for the projection.
///
Expand Down Expand Up @@ -190,7 +191,7 @@ impl DepthCloud {
for corner in corners {
let depth = corner.z;
let pos_in_obj = ((corner.truncate() - offset) * depth / focal_length).extend(depth);
let pos_in_world = self.world_from_obj.transform_point3(pos_in_obj);
let pos_in_world = self.world_from_rdf.transform_point3(pos_in_obj);
bbox.extend(pos_in_world);
}

Expand Down
48 changes: 29 additions & 19 deletions crates/re_space_view_spatial/src/eye.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::space_camera_3d::SpaceCamera3D;
/// Our view-space uses RUB (X=Right, Y=Up, Z=Back).
#[derive(Clone, Copy, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Eye {
pub world_from_view: IsoTransform,
pub world_from_rub_view: IsoTransform,

/// If no angle is present, this is an orthographic camera.
pub fov_y: Option<f32>,
Expand All @@ -32,7 +32,7 @@ impl Eye {
.unwrap_or(Self::DEFAULT_FOV_Y);

Some(Self {
world_from_view: space_cameras.world_from_rub_view()?,
world_from_rub_view: space_cameras.world_from_rub_view()?,
fov_y: Some(fov_y),
})
}
Expand Down Expand Up @@ -72,7 +72,7 @@ impl Eye {
Mat4::from_translation(vec3(space2d_rect.center().x, space2d_rect.center().y, 0.0))
* Mat4::from_scale(0.5 * vec3(space2d_rect.width(), -space2d_rect.height(), 1.0))
* projection
* self.world_from_view.inverse()
* self.world_from_rub_view.inverse()
}

pub fn is_perspective(&self) -> bool {
Expand All @@ -93,38 +93,38 @@ impl Eye {
let px = (2.0 * (pointer.x - screen_rect.left()) / w - 1.0) * f * aspect_ratio;
let py = (1.0 - 2.0 * (pointer.y - screen_rect.top()) / h) * f;
let ray_dir = self
.world_from_view
.world_from_rub_view
.transform_vector3(glam::vec3(px, py, -1.0));
macaw::Ray3::from_origin_dir(self.pos_in_world(), ray_dir.normalize())
} else {
// The ray originates on the camera plane, not from the camera position
let ray_dir = self.world_from_view.rotation().mul_vec3(glam::Vec3::Z);
let origin = self.world_from_view.translation()
+ self.world_from_view.rotation().mul_vec3(glam::Vec3::X) * pointer.x
+ self.world_from_view.rotation().mul_vec3(glam::Vec3::Y) * pointer.y
let ray_dir = self.world_from_rub_view.rotation().mul_vec3(glam::Vec3::Z);
let origin = self.world_from_rub_view.translation()
+ self.world_from_rub_view.rotation().mul_vec3(glam::Vec3::X) * pointer.x
+ self.world_from_rub_view.rotation().mul_vec3(glam::Vec3::Y) * pointer.y
+ ray_dir * self.near();

macaw::Ray3::from_origin_dir(origin, ray_dir)
}
}

pub fn pos_in_world(&self) -> glam::Vec3 {
self.world_from_view.translation()
self.world_from_rub_view.translation()
}

pub fn forward_in_world(&self) -> glam::Vec3 {
self.world_from_view.rotation() * -Vec3::Z // because we use RUB
self.world_from_rub_view.rotation() * -Vec3::Z // because we use RUB
}

pub fn lerp(&self, other: &Self, t: f32) -> Self {
let translation = self
.world_from_view
.world_from_rub_view
.translation()
.lerp(other.world_from_view.translation(), t);
.lerp(other.world_from_rub_view.translation(), t);
let rotation = self
.world_from_view
.world_from_rub_view
.rotation()
.slerp(other.world_from_view.rotation(), t);
.slerp(other.world_from_rub_view.rotation(), t);

let fov_y = if t < 0.02 {
self.fov_y
Expand All @@ -141,7 +141,7 @@ impl Eye {
};

Eye {
world_from_view: IsoTransform::from_rotation_translation(rotation, translation),
world_from_rub_view: IsoTransform::from_rotation_translation(rotation, translation),
fov_y,
}
}
Expand All @@ -154,8 +154,12 @@ impl Eye {
position: glam::Vec3,
viewport_size: egui::Vec2,
) -> f32 {
if !self.world_from_rub_view.is_finite() {
return 1.0 / viewport_size.y;
}

if let Some(fov_y) = self.fov_y {
let distance = position.distance(self.world_from_view.translation());
let distance = position.distance(self.world_from_rub_view.translation());
(fov_y * 0.5).tan() * 2.0 / viewport_size.y * distance
} else {
1.0 / viewport_size.y
Expand Down Expand Up @@ -217,7 +221,7 @@ impl OrbitEye {

pub fn to_eye(self) -> Eye {
Eye {
world_from_view: IsoTransform::from_rotation_translation(
world_from_rub_view: IsoTransform::from_rotation_translation(
self.world_from_view_rot,
self.position(),
),
Expand All @@ -233,7 +237,7 @@ impl OrbitEye {
.dot(self.orbit_center - eye.pos_in_world());
self.orbit_radius = distance.at_least(self.orbit_radius / 5.0);
self.orbit_center = eye.pos_in_world() + self.orbit_radius * eye.forward_in_world();
self.world_from_view_rot = eye.world_from_view.rotation();
self.world_from_view_rot = eye.world_from_rub_view.rotation();
self.fov_y = eye.fov_y.unwrap_or(Eye::DEFAULT_FOV_Y);
self.velocity = Vec3::ZERO;
}
Expand Down Expand Up @@ -446,8 +450,14 @@ impl OrbitEye {
let fwd = Quat::from_axis_angle(right, pitch) * fwd; // Tilt up/down
let fwd = fwd.normalize(); // Prevent drift

self.world_from_view_rot =
let new_world_from_view_rot =
Quat::from_affine3(&Affine3A::look_at_rh(Vec3::ZERO, fwd, self.up).inverse());

if new_world_from_view_rot.is_finite() {
self.world_from_view_rot = new_world_from_view_rot;
} else {
re_log::debug_once!("Failed to rotate camera: got non-finites");
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/re_space_view_spatial/src/scene/contexts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::sync::atomic::AtomicUsize;
pub use annotation_context::AnnotationSceneContext;
pub use depth_offsets::EntityDepthOffsets;
pub use shared_render_builders::SharedRenderBuilders;
pub use transform_context::TransformContext;
pub use transform_context::{pinhole_camera_view_coordinates, TransformContext};

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

Expand Down