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.
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.