LookAt rotation matrix computation

Started by
8 comments, last by tthibault 17 years, 6 months ago
How can I calculate a rotation matrix given a Position and ViewVector?
Advertisement
Depending on the type of coordinate system and vectors you're using, take a look at the documentation for D3DXMatrixLookAtLH (left-handed, row vectors), D3DXMatrixLookAtRH (right-handed, row vectors), and gluLookAt (right-handed, column vectors). They all contain some matrix diagrams showing you how to construct the matrix. If you're looking more for why's than how's, then ask away. Note that I didn't reference anything for left-handed, row vector configurations, because then you're just asking for trouble [smile]
Thanks Zipster, but I have a few more questions.
I'm crating a camera class, and I use Euler angles. Since I want a FPS-like camera I use only 2 angles: angle around X axis and angle around Y axes.
I need to have a function that passed in EyePos and ViewPoint would return a matrix with rotation and translation, that will orient/translate the scene correctly. I can use the gluLookAt function or the code to actually create the matrix, but there are problems. Whenever I look down th positive or negative Y axis(something like this:
gluLookAt(eye.x, eye.y, eye.z, eye.x, eye.y+1/eye.y-1, eye.z, 0, 1, 0))
problems occur. I'm using an Up vector that points dirrectly up ((0,1,0) that is) and because of this the 3 vectors will not create a 3D orthogonal system, because the up vector will be the same or opposite with the view vector.
How can I go arround this? How can I solve this and not use quaternions?
If your eye vector and up vector are parallel (as in this case), simply use a different vector for 'up'. (0,0,-1), for example.
That's one reason why I don't use LookAt-style methods for creating my view transformations, because you have to pick some magic up vector and hope your view is never parallel to it.

Instead of constructing the view matrix directly, what I usually do is construct it from three Euler angle rotations for yaw, pitch, and roll. Since you're not using roll, this boils down to a single matrix multiplication, which you can expand explicitly to avoid the matrix multiplication. It's better than using LookAt functions since you already have Euler angles to begin with. So take a Y-axis rotation matrix RY (yaw) and an X-axis rotation matrix RX (pitch) and expand out RXRY (for column vectors) or RYRX (for row vectors).
The up vector you select is niether magical, nor arbitrary... it defines the upward direction of the view space in the world space. If the view vector (also in world space) is (0,1,0), then obviously "up" should not be the same vector.
Exactly, and then you have a degenerate case to deal with [smile] Especially so in an FPS, where the player looking straight up or straight down is quite common. So I'll concede it's not as much arbitrary or magical as it is problematic in those cases.
Thanks for the replies guys, I've managed to get around the degenerate case.
If you use the up vector from the last frame, you're quite unlikely to bump into the degenerate case. That is unless you can spin 90 degrees in a single frame, which I find unlikely in any game. And if it did happen, you could then use the forward vector from the prior frame to construct the matrix.
void	Matrix4x4::BuildLookAtMatrix(float posx,float posy,float posz,float eyex,float eyey, float eyez,float upx,float upy, float upz){   float x[3], y[3], z[3];   float mag;   z[0] = eyex - posx;   z[1] = eyey - posy;   z[2] = eyez - posz;   mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );   if (mag>.0001)    {  	  mag	=	1/mag;      z[0] *= mag;      z[1] *= mag;      z[2] *= mag;   }   y[0] = upx;   y[1] = upy;   y[2] = upz;   x[0] =  y[1]*z[2] - y[2]*z[1];   x[1] = -y[0]*z[2] + y[2]*z[0];   x[2] =  y[0]*z[1] - y[1]*z[0];   y[0] =  z[1]*x[2] - z[2]*x[1];   y[1] = -z[0]*x[2] + z[2]*x[0];   y[2] =  z[0]*x[1] - z[1]*x[0];   mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );   if (mag > .0001)    {	  mag	=	1/mag;      x[0] *= mag;      x[1] *= mag;      x[2] *= mag;   }   mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );   if (mag > .0001)    {	  mag = 1/mag;	  y[0] *= mag;      y[1] *= mag;      y[2] *= mag;   }#define M(row,col)  mat[row][col]   M(0,0) = x[0];  M(0,1) = x[1];  M(0,2) = x[2];  M(0,3) = -x[0]*eyex + -x[1]*eyey + -x[2]*eyez;   M(1,0) = y[0];  M(1,1) = y[1];  M(1,2) = y[2];  M(1,3) = -y[0]*eyex + -y[1]*eyey + -y[2]*eyez;   M(2,0) = z[0];  M(2,1) = z[1];  M(2,2) = z[2];  M(2,3) = -z[0]*eyex + -z[1]*eyey + -z[2]*eyez;   M(3,0) = 0.0;   M(3,1) = 0.0;   M(3,2) = 0.0;   M(3,3) = 1.0;#undef M	}

...and do not wildly extrapolate. Just because Saddam Hussein gassed Kurds in 1990 doesn't mean he eats babies' brains.

This topic is closed to new replies.

Advertisement