Skip to content

Commit e2ab6ba

Browse files
committed
Add pitch-yaw-roll camera transform
1 parent 8d7fa21 commit e2ab6ba

File tree

1 file changed

+80
-38
lines changed

1 file changed

+80
-38
lines changed

core/src/render/cam.rs

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::math::{
77
Angle, Vec3, orient_z, rotate_x, rotate_y, spherical, translate, turns,
88
};
99
use crate::math::{
10-
Lerp, Mat4, Point3, ProjMat3, SphericalVec, Vary, mat::RealToReal,
11-
orthographic, perspective, pt2, viewport,
10+
Lerp, Mat3, Mat4, Point3, ProjMat3, SphericalVec, Vary, orthographic,
11+
perspective, pt2, rotate_z, viewport,
1212
};
1313
use crate::util::{Dims, rect::Rect};
1414

@@ -67,34 +67,44 @@ pub struct Camera<Tf> {
6767
///
6868
/// This is the familiar "FPS" movement mode, based on camera
6969
/// position and heading (look-at vector).
70-
#[derive(Copy, Clone, Debug)]
70+
#[derive(Copy, Clone, Debug, Default)]
7171
pub struct FirstPerson {
7272
/// Current position of the camera in **world** space.
7373
pub pos: Point3<World>,
7474
/// Current heading of the camera in **world** space.
7575
pub heading: SphericalVec<World>,
7676
}
7777

78-
pub type ViewToWorld = RealToReal<3, View, World>;
79-
80-
/// Creates a unit `SphericalVec` from azimuth and altitude.
81-
#[cfg(feature = "fp")]
82-
fn az_alt<B>(az: Angle, alt: Angle) -> SphericalVec<B> {
83-
spherical(1.0, az, alt)
84-
}
8578
/// Orbiting camera transform.
8679
///
8780
/// Keeps the camera centered on a **world-space** point, and allows free
8881
/// 360°/180° azimuth/altitude rotation around that point as well as setting
8982
/// the distance from the point.
90-
#[derive(Copy, Clone, Debug)]
83+
#[derive(Copy, Clone, Debug, Default)]
9184
pub struct Orbit {
9285
/// The camera's target point in **world** space.
9386
pub target: Point3<World>,
9487
/// The camera's direction in **world** space.
9588
pub dir: SphericalVec<World>,
9689
}
9790

91+
/// Camera transform implementing airplane-like controls based on three angles.
92+
///
93+
/// The pitch (elevation) angle controls rotation about the local lateral (x)
94+
/// axis, the yaw (bearing) angle about the local vertical (y) axis, and the
95+
/// roll (bank) angle about the local longitudinal (z) axis.
96+
#[derive(Copy, Clone, Debug, Default)]
97+
pub struct PitchYawRoll {
98+
pub rot: Mat4<View, World>,
99+
pub trans: Vec3<World>,
100+
}
101+
102+
/// Creates a unit `SphericalVec` from azimuth and altitude.
103+
#[cfg(feature = "fp")]
104+
fn az_alt<B>(az: Angle, alt: Angle) -> SphericalVec<B> {
105+
spherical(1.0, az, alt)
106+
}
107+
98108
//
99109
// Inherent impls
100110
//
@@ -240,10 +250,7 @@ impl FirstPerson {
240250
/// Creates a first-person transform with position in the origin
241251
/// and heading in the direction of the positive x-axis.
242252
pub fn new() -> Self {
243-
Self {
244-
pos: Point3::origin(),
245-
heading: az_alt(turns(0.0), turns(0.0)),
246-
}
253+
Self::default()
247254
}
248255

249256
/// Rotates the camera to center the view on a **world-space** point.
@@ -282,6 +289,11 @@ impl FirstPerson {
282289

283290
#[cfg(feature = "fp")]
284291
impl Orbit {
292+
/// TODO
293+
pub fn new() -> Self {
294+
Self::default()
295+
}
296+
285297
/// Adds the azimuth and altitude to the camera's current direction.
286298
///
287299
/// Wraps the resulting azimuth to [-180°, 180°) and clamps the altitude to [-90°, 90°].
@@ -329,10 +341,59 @@ impl Orbit {
329341
}
330342
}
331343

344+
#[cfg(feature = "fp")]
345+
impl PitchYawRoll {
346+
/// TODO
347+
pub fn new() -> Self {
348+
Self::default()
349+
}
350+
351+
/// Moves the camera position in view space.
352+
pub fn translate(&mut self, v: Vec3<View>) {
353+
self.trans += self.view_to_world().apply(&v);
354+
}
355+
356+
/// Moves the camera to the given position in world space.
357+
pub fn translate_to(&mut self, pt: Point3<World>) {
358+
self.trans = pt.to_vec();
359+
}
360+
361+
/// Returns the matrix from view to world space.
362+
fn view_to_world(&self) -> Mat4<View, World> {
363+
let trans: Mat4<World, World> = translate(self.trans.to()).to();
364+
let rot = self.rot;
365+
rot.then(&trans)
366+
}
367+
368+
/// Adjusts the orientation of the camera by the given delta angles.
369+
pub fn rotate(&mut self, pitch: Angle, yaw: Angle, roll: Angle) {
370+
let p = rotate_x(pitch);
371+
let y = rotate_y(yaw);
372+
let r = rotate_z(roll);
373+
let delta_rot: Mat4<View, View> = p.then(&y).then(&r).to();
374+
375+
self.rot = self.rot.compose(&delta_rot);
376+
}
377+
378+
/// Sets the orientation of the camera to the given **world-space** angles.
379+
pub fn rotate_to(&mut self, pitch: Angle, yaw: Angle, roll: Angle) {
380+
let p = rotate_x(pitch);
381+
let y = rotate_y(yaw);
382+
let r = rotate_z(roll);
383+
self.rot = p.then(&y).then(&r).to();
384+
}
385+
}
386+
332387
//
333388
// Local trait impls
334389
//
335390

391+
impl Transform for Mat4<World, View> {
392+
fn world_to_view(&self) -> Mat4<World, View> {
393+
*self
394+
}
395+
}
396+
336397
#[cfg(feature = "fp")]
337398
impl Transform for FirstPerson {
338399
fn world_to_view(&self) -> Mat4<World, View> {
@@ -366,31 +427,12 @@ impl Transform for Orbit {
366427
}
367428
}
368429

369-
impl Transform for Mat4<World, View> {
430+
impl Transform for PitchYawRoll {
370431
fn world_to_view(&self) -> Mat4<World, View> {
371-
*self
372-
}
373-
}
374-
375-
//
376-
// Foreign trait impls
377-
//
432+
let trans = translate(-self.trans.to()).to();
433+
let rot = self.rot.transpose();
378434

379-
#[cfg(feature = "fp")]
380-
impl Default for FirstPerson {
381-
/// Returns [`FirstPerson::new`].
382-
fn default() -> Self {
383-
Self::new()
384-
}
385-
}
386-
387-
#[cfg(feature = "fp")]
388-
impl Default for Orbit {
389-
fn default() -> Self {
390-
Self {
391-
target: Point3::default(),
392-
dir: az_alt(turns(0.0), turns(0.0)),
393-
}
435+
trans.then(&rot)
394436
}
395437
}
396438

0 commit comments

Comments
 (0)