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

Add a method for quats to set their direction #293

Open
00sos00 opened this issue Jun 11, 2022 · 12 comments
Open

Add a method for quats to set their direction #293

00sos00 opened this issue Jun 11, 2022 · 12 comments

Comments

@00sos00
Copy link

00sos00 commented Jun 11, 2022

I think it would be nice if quats had a method to make them look in a certain direction, for example if you have some direction vector and you want to make the quat look in that vector's direction, instead of making the user having to convert the vector into a rotation matrix and then into a matrix.

@bitshifter
Copy link
Owner

What would the method signature look like? Is there a method on Mat3 that you think should be on Quat as well?

@00sos00
Copy link
Author

00sos00 commented Jun 12, 2022

Probably something like fn look_at(&mut self, eye: Vec3, center: Vec3)

And you would get the direction vector by subtracting the 2 points, you would also need the current quaternion's direction vector and you can get that by just multiplying the quaternion by something like WORLD_FORWARD unit vector.

I also found this neat implementation which creates a quaternion to convert some vector direction into another:
http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors

And after creating the quaternion, you would multiply it by the current one.

@bitshifter
Copy link
Owner

@00sos00
Copy link
Author

00sos00 commented Jun 16, 2022

That does work if I'm using vectors for directions, however I am using quaternions.

Though there's a way to convert a vector into a quaternion, I think it would be better to just offer a method on quaternions to set their direction

@bitshifter
Copy link
Owner

I think you will always need two vectors to determine what the rotation should be.

@DGriffin91
Copy link

DGriffin91 commented Oct 17, 2022

I would also be interested in a look_at function. Something like this maybe?

pub fn from_look_at(forward: Vec3, up: Vec3) -> Self {
    let right = up.cross(forward).normalize();
    let up = forward.cross(right);
    Quat::from_mat3(&Mat3::from_cols(right, up, forward))
}

@jnhyatt
Copy link

jnhyatt commented Jan 20, 2024

Resurrecting this because I'd love to see something along these lines as well, and I'm happy to put up a PR if this is something that'll get accepted. Bevy has Transform::looking_to and look_to, and it'd be nice to move that function into glam. The signature is similar to what @DGriffin91 posted: fn look_to(&mut self, direction: Vec3, up: Vec3) and the corresponding looking_to. One possible concern is if direction == up, there's infinite possible Quats that could come out of it. Bevy's solution is just to use glam's any_orthonormal_vector to get an up direction if the given direction and up are equal, and I think that probably puts a reasonable amount of responsibility on the user of the API. Thoughts?

@bitshifter
Copy link
Owner

bevy has a definted co-ordinate system but glam tries to be coordinate system agnostic,, let right = up.cross(forward).normalize(); looks like it assumes a particular handedness?

@jnhyatt
Copy link

jnhyatt commented Jan 20, 2024

Ah, I hadn't thought of that, but that's an excellent reason to omit this function. Would you consider something like look_to_(rh/lh)? I know glm has lookAt(RH/LH) (not sure to what extent the design goals of glam and glm overlap, but it seems like as good a precedent as I'm going to find)

@bitshifter
Copy link
Owner

Yep I'd be OK with look_to_(rh/lh) variants.

@jnhyatt
Copy link

jnhyatt commented Jan 20, 2024

Alright, if nobody beats me to a pr, I'll have it up in the next couple days

@mweatherley
Copy link

mweatherley commented Feb 29, 2024

Popping in here to link this bevy pull request where I implemented a general version of this which looks like this:

    pub fn align(
        &mut self,
        handle: Vec3,
        direction: Vec3,
        weak_handle: Vec3,
        weak_direction: Vec3,
    ) {
        let handle = handle.try_normalize().unwrap_or(Vec3::X);
        let direction = direction.try_normalize().unwrap_or(Vec3::X);
        let weak_handle = weak_handle.try_normalize().unwrap_or(Vec3::Y);
        let weak_direction = weak_direction.try_normalize().unwrap_or(Vec3::Y);

        // The solution quaternion will be constructed in two steps.
        // First, we start with a rotation that takes `handle` to `direction`.
        let first_rotation = Quat::from_rotation_arc(handle, direction);

        // Let's follow by rotating about the `direction` axis so that the image of `weak_handle`
        // is taken to something that lies in the plane of `direction` and `weak_direction`. Since
        // `direction` is fixed by this rotation, the first criterion is still satisfied.
        let weak_image = first_rotation * weak_handle;
        let weak_image_ortho = weak_image.reject_from_normalized(direction).try_normalize();
        let weak_direction_ortho = weak_direction
            .reject_from_normalized(direction)
            .try_normalize();

        // If one of the two weak vectors was parallel to `direction`, then we just do the first part
        self.rotation = match (weak_image_ortho, weak_direction_ortho) {
            (Some(weak_img_ortho), Some(weak_dir_ortho)) => {
                let second_rotation = Quat::from_rotation_arc(weak_img_ortho, weak_dir_ortho);
                second_rotation * first_rotation
            }
            _ => first_rotation,
        };
    }

I would be a bit surprised if there wasn't a more expedient way to implement something equivalent, but I think the construction is at least pretty conceptually clear from this: handle is made to point in direction by a rotation, then a second rotation moves weak_handle into the plane of direction and weak_direction.

If you want to basically take this (and perhaps improve it!) I would be happy to see it or something similar upstreamed into glam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants