6

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.

Community
  • 1
  • 1
ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79

2 Answers2

3

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.

apLundell
  • 177
  • 7
  • 1
    I only use the Euler angles to store my orientation because matrices are cumbersome to modify. When actually aiming the camera, I convert these to a rotational matrix. – ApproachingDarknessFish Sep 16 '13 at 20:26
  • Euler angles are easy to modify, but the resulting transformation will be wrong if you're using all three angles. – apLundell Sep 16 '13 at 20:29
  • In that case, assume I store my orientation in a matrix. Then how would I go about answering my original question? – ApproachingDarknessFish Sep 16 '13 at 20:32
  • 1
    You can multiply a unit-vector with the rotation matrix and get the forward vector. (Or the up or left vector, for that matter.) – apLundell Sep 16 '13 at 20:46
  • @ValekHalfHeart: Matrices should not be cumbersome to modify, the real beauty of them is that you can apply all fundamental transformations on them with nothing more than matrix multiplication. Likewise, transforming vectors using matrices can be accomplished by multiplication. – Andon M. Coleman Sep 16 '13 at 23:07
  • @AndonM.Coleman Relative operations are easy, but it very cumbersome to say, for instance, set the rotation about the x-axis to five without knowing the current rotation about the x axis. That is to matrix rotations only have a += operator, and no = operator. – ApproachingDarknessFish Sep 17 '13 at 18:07
  • Ok, as per your advice I am using a 3x3 matrix to sore my rotations and use the matrix to transform my and it ALMOST works except certain components of the resulting vector are negated for non-zero values of the relevant rotation. You fixed my main problem however so you get an accept. – ApproachingDarknessFish Sep 24 '13 at 19:26
0

You can use Homogeneous Transformation matrix method which is widely used to calculate the final position after all the rotations.