Skip to content

Commit

Permalink
renaming and tests around RectTransform
Browse files Browse the repository at this point in the history
  • Loading branch information
Wumpf committed May 3, 2023
1 parent 8c71d37 commit f92a10e
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 13 deletions.
4 changes: 2 additions & 2 deletions crates/re_renderer/src/draw_phases/picking_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ impl PickingLayerProcessor {
});

let cropped_projection_from_projection = RectTransform {
from: picking_rect.into(),
to: RectF32 {
region_of_interest: picking_rect.into(),
region: RectF32 {
min: glam::Vec2::ZERO,
extent: screen_resolution.as_vec2(),
},
Expand Down
5 changes: 5 additions & 0 deletions crates/re_renderer/src/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ impl RectF32 {
self.min + self.extent
}

#[inline]
pub fn center(self) -> glam::Vec2 {
self.min + self.extent / 2.0
}

#[inline]
pub fn scale_extent(self, factor: f32) -> RectF32 {
RectF32 {
Expand Down
108 changes: 100 additions & 8 deletions crates/re_renderer/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,36 @@ pub fn ndc_from_pixel(pixel_coord: glam::Vec2, screen_extent: glam::UVec2) -> gl
)
}

/// Defines a transformation from a rectangular region of interest into a rectangular target region.
///
/// Transforms map the range of `region_of_interest` to the range of `region`.
#[derive(Clone, Debug)]
pub struct RectTransform {
pub from: RectF32,
pub to: RectF32,
pub region_of_interest: RectF32,
pub region: RectF32,
}

impl RectTransform {
/// No-op rect transform that transforms from a unit rectangle to a unit rectangle.
pub const IDENTITY: RectTransform = RectTransform {
from: RectF32::UNIT,
to: RectF32::UNIT,
region_of_interest: RectF32::UNIT,
region: RectF32::UNIT,
};

/// Computes a transformation matrix that applies the rect transform to the NDC space.
///
/// This matrix is expected to be the left most transformation in the vertex transformation chain.
/// It causes the area described by `region_of_interest` to be mapped to the area described by `region`.
/// Meaning, that `region` represents the full screen of the NDC space.
///
/// Note only the relation of the rectangles in `RectTransform` is important.
/// This means that only the relation of the rectangles in `RectTransform` is important.
/// Scaling or moving both rectangles by the same amount does not change the result.
pub fn to_ndc_scale_and_translation(&self) -> glam::Mat4 {
// It's easier to think in texcoord space, and then transform to NDC.
// This texcoord rect specifies the portion of the screen that should become the entire range of the NDC screen.
let texcoord_rect = RectF32 {
min: (self.from.min - self.to.min) / self.to.extent,
extent: self.from.extent / self.to.extent,
min: (self.region_of_interest.min - self.region.min) / self.region.extent,
extent: self.region_of_interest.extent / self.region.extent,
};
let texcoord_rect_min = texcoord_rect.min;
let texcoord_rect_max = texcoord_rect.max();
Expand All @@ -74,6 +80,92 @@ impl RectTransform {
}

pub fn scale(&self) -> glam::Vec2 {
self.to.extent / self.from.extent
self.region.extent / self.region_of_interest.extent
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
pub fn to_ndc_scale_and_translation() {
let region = RectF32 {
min: glam::vec2(1.0, 1.0),
extent: glam::vec2(2.0, 3.0),
};

// Identity
{
let rect_transform = RectTransform {
region_of_interest: region,
region,
};
let identity = rect_transform.to_ndc_scale_and_translation();
assert_eq!(identity, glam::Mat4::IDENTITY);
}

// Scale
{
let scale_factor = glam::vec2(2.0, 0.25);

let rect_transform = RectTransform {
region_of_interest: RectF32 {
// Move the roi to the middle of the region.
min: region.center() - region.extent * scale_factor * 0.5,
extent: region.extent * scale_factor,
},
region,
};
let scale = rect_transform.to_ndc_scale_and_translation();
assert_eq!(
scale,
glam::Mat4::from_scale(1.0 / scale_factor.extend(1.0))
);
}

// Translation
{
let translation_vec = glam::vec2(1.0, 2.0);

let rect_transform = RectTransform {
region_of_interest: RectF32 {
min: region.min + translation_vec * region.extent,
extent: region.extent,
},
region,
};
let translation = rect_transform.to_ndc_scale_and_translation();
assert_eq!(
translation,
glam::Mat4::from_translation(
glam::vec3(-translation_vec.x, translation_vec.y, 0.0) * 2.0
)
);
}

// Scale + translation
{
let scale_factor = glam::vec2(2.0, 0.25);
let translation_vec = glam::vec2(1.0, 2.0);

let rect_transform = RectTransform {
region_of_interest: RectF32 {
// Move the roi to the middle of the region and then apply translation
min: region.center() - region.extent * scale_factor * 0.5
+ translation_vec * region.extent,
extent: region.extent * scale_factor,
},
region,
};
let scale_and_translation = rect_transform.to_ndc_scale_and_translation();
assert_eq!(
scale_and_translation,
glam::Mat4::from_scale(1.0 / scale_factor.extend(1.0))
* glam::Mat4::from_translation(
glam::vec3(-translation_vec.x, translation_vec.y, 0.0) * 2.0
)
);
}
}
}
6 changes: 3 additions & 3 deletions crates/re_viewer/src/ui/view_spatial/ui_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,15 +456,15 @@ fn setup_target_config(

// Cut to the portion of the currently visible ui area.
let mut viewport_transformation = re_renderer::RectTransform {
from: egui_rect_to_re_renderer(painter.clip_rect()),
to: egui_rect_to_re_renderer(*canvas_from_ui.from()),
region_of_interest: egui_rect_to_re_renderer(painter.clip_rect()),
region: egui_rect_to_re_renderer(*canvas_from_ui.from()),
};

// The principal point might not be quite centered.
// We need to account for this translation in the viewport transformation.
let principal_point_offset = default_principal_point - pinhole.principal_point();
let ui_from_canvas_scale = canvas_from_ui.inverse().scale();
viewport_transformation.from.min +=
viewport_transformation.region_of_interest.min +=
principal_point_offset * glam::vec2(ui_from_canvas_scale.x, ui_from_canvas_scale.y);

Ok({
Expand Down

0 comments on commit f92a10e

Please sign in to comment.