Convert yaw, pitch AND roll to x,y,z vector in world coordinates

11,629

I don't think you're going to find an answer that's pure trig. Not an elegant one, anyway.

Euler angles(Pitch/Yaw/Roll) are not the right tool for this job. Gimble-lock will be a problem, as well as the ambiguity of the order of operations.

I suggest storing your objects' current rotational state in either a Matrix or a Quaternion. Only use Euler angles for relatively small deltas.

Share:
11,629
ApproachingDarknessFish
Author by

ApproachingDarknessFish

main = putStrLn "Hello nerds!" I'm a mostly self-taught programmer and researcher who happens to have a degree in bioinformatics with a minor in CS. I haven't been very active on stack overflow since I accidentally hit 10K. I spend most of my time on scifi.se.

Updated on June 04, 2022

Comments

  • ApproachingDarknessFish
    ApproachingDarknessFish about 2 years

    I'm working on some simple 3d graphics in OpenGL (java LWGJL), and I'm trying to figure out how to convert yaw, pitch and roll to the x, y and z components of my movement Vector. I know how to do this with just pitch and yaw (as explained here), but I haven't found anything the explains how to integrate roll into this formula.

    I am aware that yaw and pitch are all that is needed to define a vector in 3d space, but I also need roll in this instance. I have keys bound to different movements relative to the camera in a basic WASD configuration (A is local left, W is local forward, SPACE is local up), so the roll affects how the camera moves (eg pressing D with a roll of pi/2 (the default) moves the camera right (in world coords), but pressing D with a roll of pi moves the camera up in world coords)).

    Here's the code I have so far:

    //b = back
    //f = forward
    //r = right
    //l = left
    //u = up
    //d = down
    
        private void move()
        {
            double dX = 0, dY = 0, dZ = 0;
    
    
            if (f ^ b)
            {
                dZ += cos(yaw) * cos(pitch) * (b ? 1 : -1);
                dX += sin(yaw) * cos(pitch) * (b ? 1 : -1);
                dY += -sin(pitch) * (b ? 1 : -1);
            }
    
            if (l ^ r)
            {
                dZ += sin(yaw) * sin(roll) * (l ? 1 : -1);
                dX += cos(yaw) * - sin(roll) * (l ? 1 : -1);
                dY += cos(roll) * (l ? 1 : -1);
            }
    
            if (u ^ d) //this part is particularly screwed up
            {
                dZ += sin(pitch) * sin(roll) * (u ? 1 : -1);
                dX += cos(roll) * (u ? 1 : -1);
                dY += cos(pitch) * sin(roll) * (u ? 1 : -1);
            }
    
    
    
            motion.x = (float) dX;
            motion.y = (float) dY;
            motion.z = (float) dZ;
    
            if (motion.length() != 0)
            {
                motion.normalise();
                motion.scale(2);
            }
    
            x += motion.x;
            y += motion.y;
            z += motion.z;
    

    This works for a few rotations, but for many it produces incorrect results.

    So the question is:

    How do I modify my code such that it successfully calculates the x, y, and z components of my motion vector based upon my desired direction (what key is pressed), accounting for my yaw, pitch, AND roll?

    I'm fine with using raw trig (as I am attempting to do), a solution involving matrices, or pretty much anything.

    EDIT:

    Please don't answer by just linking to the Wikipedia article on Euler Angles. I've read it and I don't have a strong enough background in math to understand how to apply it to my situation.

    EDIT #2:

    I'm only using Euler angles to store my orientation in between re-orienting the camera. For the actual camera manipulations, I use rotational matrices. If needed, I can drop the euler angles and just use a matrix. All that matters is that I can convert from my orientation to a vector.

    EDIT #3:

    Found a solution by multiplying my forward vector by my rotation matrix as described in the comments:

    //b = back
    //f = forward
    //r = right
    //l = left
    //u = up
    //d = down
    
    private Vector3f motion;
    
    protected void calcMotion()
    {
        //1 for positive motion along the axis, -1 for negative motion, 0 for no motion
        motion.x = r&&!l ? -1 : l ? 1 : 0; 
        motion.y = u&&!d ? 1 : d ? -1 : 0;
        motion.z = f&&!b ? 1 : b ? -1 : 0;
    
        if (motion.length() == 0)
        {
            return;         
        }
    
        motion.normalise();
    
        //transform.getRotation() returns a Matrix3f containing the current orientation
        Matrix3f.transform(transform.getRotation(), motion, motion);
    }
    

    Still having trouble with this, though.