fu5ha / ultraviolet

A wide linear algebra crate for games and graphics.
https://crates.io/crates/ultraviolet
750 stars 81 forks source link

The terms "Rotation in the xz plane" and "Rotation arround the y axis" can lead to confusion #130

Open thenlevy opened 3 years ago

thenlevy commented 3 years ago

n ultraviolet, Bivector are represented in the basis (xy xz yz), and user are invited to think of rotation as happening in a plane rather than around and axis.

When thinking about rotations as happening around an axis, one must chose a convention for which direction is the "positive" rotation direction. Often, the convention used is the "right hand rule"

However, from the "right hand rule" perspective, a rotation in the plane xz is a rotation around the axis -y .

Because of that, some behaviors of ultraviolet may seem counterintuitive. For example

The method Rotor3::from_rotation_xz(theta) and Mat3::from_rotation_y(theta) produce two rotations that go in the opposite direction.

use ultraviolet::*; 

fn main() {
    let yaw = 0.3;
    let vec_1 = Rotor3::from_rotation_xz(yaw) * Vec3::unit_x();
    let vec_2 = Mat3::from_rotation_y(yaw) * Vec3::unit_x();
    println!("{:?}", vec_1);
    println!("{:?}", vec_2); // the z coordinates are opposed 
}

In my opinion the following things could reduce the confusion

fu5ha commented 3 years ago

I think the best solution to this problem is actually to change the Bivec3 to use the zx plane rather than xz... doing so is also the most common choice in the GA literature, so it makes sense. I've been meaning to for a little while but just haven't had the time to go back and redo the derivations/rewrite the code. It should just be a matter of adding/removing some -s.

iwikal commented 2 years ago

I'm probably misunderstanding something here, but the documentation for Mat4::from_euler_angles reads:

pub fn from_euler_angles(roll: f32, pitch: f32, yaw: f32) -> Self Angles are applied in the order roll -> pitch -> yaw

Roll is rotation inside the xy plane (“around the z axis”)
Pitch is rotation inside the yz plane (“around the x axis”)
Yaw is rotation inside the xz plane (“around the y axis”)

So if I pass 0. for roll and pitch, the Y axis should not change, right? But when I run dbg!(ultraviolet::Mat4::from_euler_angles(0., 0., std::f32::consts::PI / 2.));, I get this:

[src/main.rs:157] ultraviolet::Mat4::from_euler_angles(0., 0., std::f32::consts::PI / 2.) = Mat4 {
    cols: [
        Vec4 {
            x: -4.371139e-8,
            y: 1.0,
            z: -0.0,
            w: 0.0,
        },
        Vec4 {
            x: -1.0,
            y: -4.371139e-8,
            z: 0.0,
            w: 0.0,
        },
        Vec4 {
            x: 0.0,
            y: 0.0,
            z: 1.0,
            w: 0.0,
        },
        Vec4 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
            w: 1.0,
        },
    ],
}

It looks to me like a rotation in the XY plane; the X axis gets transformed to Y, and the Y axis ends up at -X. Through experimentation I think it's interpreting the arguments as from_euler_angles(pitch, yaw, roll) instead. What am I missing? Or is this a bug?