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 methods for swing-twist decomposition to Quat #536

Open
cactusdualcore opened this issue Jul 13, 2024 · 2 comments
Open

Add methods for swing-twist decomposition to Quat #536

cactusdualcore opened this issue Jul 13, 2024 · 2 comments

Comments

@cactusdualcore
Copy link

I ran into a problem where I wanted to decompose a rotation into a part which rotates around a specified axis and perpendicular to it. This can be done using the swing-twist decomposition of quaternions.

I now implemented an alternative solution to my problem, but I think this library would still profit from this feature.

I implemented a crude function to do this for me based on this stackoverflow question.

/// Decompose the rotation on to 2 parts.
///
/// 1. Twist - rotation around the "direction" vector
/// 2. Swing - rotation around axis that is perpendicular to "direction" vector
///
/// The rotation can be composed back by
/// `rotation = swing * twist`.
/// Order matters!
///
/// has singularity in case of swing_rotation close to 180 degrees rotation.
/// if the input quaternion is of non-unit length, the outputs are non-unit as well
/// otherwise, outputs are both unit
fn swing_twist_decomposition(rotation: Quat, axis: Dir3) -> Option<(Quat, Quat)> {
    let rotation_axis = rotation.xyz();
    let projection = rotation_axis.project_onto(*axis);

    let twist = {
        let maybe_flipped_twist = Quat::from_vec4(projection.extend(rotation.w));
        if rotation_axis.dot(projection) < 0.0 {
            -maybe_flipped_twist
        } else {
            maybe_flipped_twist
        }
    };

    if twist.length_squared() != 0.0 {
        let swing = rotation * twist.conjugate();
        Some((twist.normalize(), swing))
    } else {
        None
    }
}

The above code is fully written by me, but the mechanism was adapted from a StackOverflow answer.
I have no clues about licensing here. If I am legally allowed, I'd like to give up any rights to the code.

There seem to be many resources on this topic online.
I have neither thoroughly tested nor benchmarked the above snipped and I assume it requires more polish. If desired, I could try putting together a PR for a full implementation?

@cactusdualcore
Copy link
Author

There's a proposal for this for Godot too!
godotengine/godot-proposals#8906

@johannesvollmer
Copy link

johannesvollmer commented Jul 13, 2024

I too was looking for this but couldn't find it in glam. This use case is valuable and general enough to be included. +1

Edit (Context):
I'm trying to do something in bevy, which uses Quat to store rotation, and I want to find out the current rotation along a particular axis.

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

2 participants