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

ApproachingDarknessFish picture ApproachingDarknessFish · Sep 16, 2013 · Viewed 10k times · Source

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.

Answer

apLundell picture apLundell · Sep 16, 2013

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.