glam-rs icon indicating copy to clipboard operation
glam-rs copied to clipboard

`slerp` for vectors (feature request)

Open kovaxis opened this issue 2 years ago • 2 comments

I'm in a situation where I would like to slerp two Vec3s, something like the following pseudocode:

fn slerp(from: Vec3, to: Vec3, alpha: f32):
    angle = angle_between(from, to) * alpha
    return from.rotate_by(amount: angle, plane: plane_between(from, to))

I think this can be implemented in terms of quaternions, but it is not directly obvious to me and I'm not sure if it is the most performant way either.

Does this fit in the scope of the library?

kovaxis avatar Feb 22 '23 19:02 kovaxis

You can create a Quat rotation between two vectors with https://docs.rs/glam/latest/glam/f32/struct.Quat.html#method.from_rotation_arc.

For slerp you need a start and end orientation to slerp between though, you can probably get that via:

let q0 = Quat::from_rotation_arc(FORWARD_DIR, from);
let q1 = Quat::from_rotation_arc(FORWARD_DIR, to);
let qa = q0.slerp(q1, alpha);

Where FORWARD_DIR is the bind pose of your object (i.e. what direction it faces with no rotation applied).

Whether that achieves what you want I am not sure. I would need to see some wider code context of how you are using this to determine if it makes sense to add a helper.

The Bevy 2D rotation example might help, it's in 2D but they're using quaternions for all rotations so the same thing should work in 3D - https://github.com/bevyengine/bevy/blob/main/examples/2d/rotation.rs.

bitshifter avatar Feb 22 '23 21:02 bitshifter

I was iterating on a dual contouring implementation, and I was interpolating normals between two points, so it really was just taking two unit Vec3 and interpolating them across the unit sphere. I was doing a simple hack of lerp-ing them and then re-normalizing the result (nlerp), but I was getting odd results, so I wanted to quickly experiment by interpolating the normals "correctly".

I could kind of guess how to implement this in terms of quaternions, although it wasn't an instantly obvious solution as I'm not really familiar with quaternions. I did something along these lines:

Quat::IDENTITY.slerp(Quat::from_rotation_vec(from, to), alpha).mul_vec3(from)

I don't have the exact code I used because it turned out that normal interpolation was not the cause of my issues, and I quickly scrapped the code. I just thought that a proper Vec3 slerp would be a nice quality-of-life addition to this library and it would have saved me some time. Also, at least according to this stackoverflow answer, a proper Vec3::slerp function can be more efficient than a quaternion-based implementation.

Of course, it's up to you whether it's worth it to include this functionality. As a precedent, Unity provides a Vec3.slerp function.

kovaxis avatar Mar 01 '23 19:03 kovaxis