Skip to main content

Crate trackball

Crate trackball 

Source
Expand description

Virtual Trackball Orbiting via the Exponential Map

This is an alternative trackball technique using the exponential map for inducing coherent and intuitive trackball rotations.1 Displacements on straight radial lines through the screen’s center are carried to arcs of the same length on great circles of the trackball, whose half circumference is the maximum of the screen’s width and height. This is in contrast to state-of-the-art techniques using orthogonal projection which distorts radial distances further away from the screen’s center. Each rotation carries the trackball’s point under the previous cursor/finger position along the shortest arc to the one under the current position, keeping the grabbed point under the cursor/finger. This follows the paper’s differential of the exponential map rather than its recipe, which takes the differential to be parallel transport, preserving the lengths of displacements but letting the grabbed point drift. Screen corners beyond the trackball’s border are mapped beyond its equator, keeping radial displacements linear.

§Features

  • Common trackball operations split into several operation handlers.
  • Coherent and intuitive orbiting via the exponential map, see Orbit operation handler.
  • Identical C11 implementation for Orbit operation handler behind cc feature gate.
  • Coherent First person view aka free look or mouse look wrt Orbit operation handler.
  • Observer Frame with Frame::slide(), Frame::orbit(), Frame::scale() operations in world space and their local complements in camera space and with orbit and slide operations around arbitrary points in either world or camera space.
  • Gliding Clamp operation handler trait ensuring boundary conditions of observer Frame. When Delta between initial and final Frame is not orthogonal to a boundary Plane, Delta is changed in such a way that the clamped movement glides along the plane.
  • Rigid transformation as direct isometry of Frame::view() and Bound::transform.
  • Bound implementing Clamp providing customizable orthogonal boundary conditions.
  • Object inspection mode scaling clip plane distances by measuring from target instead of eye.
  • Scale-preserving transitioning between orthographic and perspective projection mode.
  • Converting between Fixed quantities wrt to field of view, see Scope::set_fov().
  • Time-free Touch gesture recognition for slide, orbit, scale, and focus operations.

§Math Backend

Like glam, this crate requires one of the following math backends, forwarded to glam:

  • std (default) for using the math functions of the standard library.
  • libm for using libm instead of std, e.g., for consistent results across platforms.
  • nostd-libm for using libm only if std is disabled, e.g., in no_std environments.

This crate is no_std with default-features = false and libm or nostd-libm enabled.

§Optional Features

Following features are disabled unless their corresponding feature gate is enabled:

  • serde for serde support of various structures of this crate and its dependencies.
  • rkyv-08 for rkyv 0.8 support of various structures of this crate and its dependencies.
  • cc for testing the behaviorally identical C implementation of the exponential map.

§Example

A trackball camera mode implementation can be as easy as this by delegating events of your 3D graphics library of choice to the Orbit operation handler along with other handlers.

use trackball::{Frame, Image, Orbit, glam::Vec2};

/// Trackball camera mode.
pub struct Trackball {
    // Frame wrt camera eye and target.
    frame: Frame,
    // Image as projection of `Scope` wrt `Frame`.
    image: Image,
    // Orbit induced by displacement on screen.
    orbit: Orbit,
}

impl Trackball {
    // Usually, a cursor position event with left mouse button being pressed.
    fn handle_left_button_displacement(&mut self, pos: Vec2) {
        // Maximum position as screen's width and height.
        let max = self.image.max();
        // Induced rotation in camera space.
        let rot = self.orbit.compute(pos, max).unwrap_or_default();
        // Apply induced rotation to local observer frame.
        self.frame.local_orbit(rot);
    }
    // Event when left mouse button is released again.
    fn handle_left_button_release(&mut self) {
        // Can also or instead be invoked on `Self::handle_left_button_press()`.
        self.orbit.discard();
    }
}

  1. G. Stantchev, “Virtual Trackball Modeling and the Exponential Map”, S2CID 44199608 (2004) , Archived PDF  ↩

Re-exports§

pub use glam;

Structs§

Bound
Orthogonal boundary conditions implementing Clamp.
First
First person view induced by displacement on screen.
Frame
Frame wrt camera eye and target.
Image
Image as projection of Scope wrt Frame.
Orbit
Orbit induced by displacement on screen.
Plane
Plane encoding position with signed bias along unit normal.
Rigid
Rigid transformation as rotation followed by translation, i.e., a direct isometry.
Scale
Scale induced by relative input.
Scope
Scope defining enclosing viewing frustum.
Slide
Slide induced by displacement on screen.
Touch
Touch gestures inducing slide, orbit, scale, and focus.

Enums§

Delta
Delta transform from initial to final Frame.
Fixed
Fixed quantity wrt field of view.

Traits§

Clamp
Clamp wrt abstract boundary conditions of Frame and Scope.