manual alternative to glulookat ?

Started by
6 comments, last by Deception666 17 years, 6 months ago
Ive been using glulookat for a while but i think its time i understand exactly how it works so i can get the most from it. I normally just store cam pos and the rotations in x y z then apply those to the camera's center and location then pass it all to glulookat but now id prefer to do this manually so i can store the whole view matrix in memory.

1  0  0  0 //right vector
0  1  0  0 //up vector
0  0 -1  0 //forward vector
0  0  0  1

Multiply this by the Camera's translation matrix this is where im a bit cloudy...

1           0          0         0 
0           1          0         0 
0           0          1         0 
-Cam_Posx  -Cam_Posy  -Cam_Posz  1

Im confused where the rotations on the camera are applied do i keep applying the rotations to each individual right up forward vector then plonk them into the top matrix or do i apply the rotations to the camera's translation matrix and leave the original look vectors alone ? Thx for any help. Fishy
Advertisement
I think this would help understanding what gluLootAt() does inside.

void LookAt(const CVector3& pos, const CVector3& dir, const CVector3& up){	CVector3 dirN;	CVector3 upN;	CVector3 rightN;	dirN = dir;	dirN.Normalize();	upN = up;	upN.Normalize();	rightN = dirN.Cross(upN);	rightN.Normalize();	upN = rightN.Cross(dirN);	upN.Normalize();        float mat[16];	mat[ 0] = rightN.x;	mat[ 1] = upN.x;	mat[ 2] = -dirN.x;	mat[ 3] = 0.0;	mat[ 4] = rightN.y;	mat[ 5] = upN.y;	mat[ 6] = -dirN.y;	mat[ 7] = 0.0;	mat[ 8] = rightN.z;	mat[ 9] = upN.z;	mat[10] = -dirN.z;	mat[11] = 0.0;	mat[12] = -(rightN.Dot(pos));	mat[13] = -(upN.Dot(pos));	mat[14] = (dirN.Dot(pos));	mat[15] = 1.0;        glMultMatrixf(&mat[0]);}


I hope i haven't done any mistakes :) If somebody sees something wrong with the above code, say it. I think there is an old thread talking about how gluLookAt works and an alternative, so you may find something more useful in there.
I think the above code (with the exception of using 3d vectors) is exactly what gluLookAt does (glu32.dll).

Hope it helps anyway.

HellRaiZer

EDIT : Apparently gluLookAt() does a glMultMatrix and a glTranslate in case to build the final matrix. The code above should work, because the translation is inside mat.
HellRaiZer
Yeah thats pritty much what im doing at the moment i noticed that you dont take into account the eye look at position or am i missing something ?

My view matrix so far,
1           0          0         0 //right vector0           1          0         0 //up vector0           0         -1         0 //forward vector-Cam_Posx  -Cam_Posy  -Cam_Posz  1 //minus cam pos


So i apply rotations to the idividual up right forward vectors ?

I tried looking for the previous thread you mentioned cant seem to find it :(.
I posted this not too long ago. I'm too lazy to retype it.

Camera Matrix

this is what I use to construct the camera matrix.
So with your method you track the rotation of the camera given the camera's look at position i think :)...
    // determine the new n    Vector vN = vEye - vLookat;    // determine the new u by crossing with the up vector    Vector vU = vUp ^ vN;    // normalize both the u and n vectors    vU.Normalize(); vN.Normalize();    // determine v by crossing n and u    Vector vV = vN ^ vU;

Thing i dont get is you work out a new Forward vector by crossing Up X Right but the thing is Up may have changed.

At the very bottom of your matrix you scale the camera's current position by each of the up right forward vectors but why what effect does this have?

right.x up.x forw.xright.y up.y forw.yright.z up.z forw.z-(vEye.x * vU.x), -(vEye.y *  vV.y), -(vEye.z * vN.z), 1.0f


I noticed alot of people use column notation to represent the view matrix for opengl so im a tad confused to which one it will accept is it the column or row formation ?

[Edited by - fishleg003 on October 29, 2006 10:00:41 AM]
void SetLookAt( const Vector & vEye,                const Vector & vLookat,                const Vector & vUp ){    // determine the new n    Vector vN = vEye - vLookat;    // determine the new u by crossing with the up vector    Vector vU = vUp ^ vN;    // normalize both the u and n vectors    vU.Normalize(); vN.Normalize();    // determine v by crossing n and u    Vector vV = vN ^ vU;    // create a model view matrix    float fModelView[16] =    {       vU.fX,        vV.fX,        vN.fX,        0.0f,       vU.fY,        vV.fY,        vN.fY,        0.0f,       vU.fZ,        vV.fZ,        vN.fZ,        0.0f,       -(vEye * vU), -(vEye * vV), -(vEye * vN), 1.0f    }    // load the model view matrix    // the model view matrix should already be active    glLoadMatrixf(fModelView);}


Quote:
I noticed alot of people use column notation to represent the view matrix for opengl so im a tad confused to which one it will accept is it the column or row formation ?


OpenGL uses column major ordering. The modelview matrix, in the source above, visually looks like a row major matrix, but it is a column major matrix since the source requires a left to right read instead of a top to bottom.

Quote:So with your method you track the rotation of the camera given the camera's look at position i think :)...


The camera's position is truly just a position in space. It has no orientation associated to it. That is were the vLookAt come in.

Quote:Thing i dont get is you work out a new Forward vector by crossing Up X Right but the thing is Up may have changed.


No, I do not compute a new forward vector from the Up vector and the Right vector. The forward vector is the opposite of your vEye minus the vLookAt vectors ( -vN ). The termonology I used for my vectors might be bit confusing, but the U, V, and N vectors are considered the X, Y, and Z vectors respectively. Again, the forward vector is the opposite of the Z axis. You are trying to manipulate vertices by translating them into eye or camera space. That is what the modelview matrix is trying to do. Eye space, in OpenGL, is located with a position of (0, 0, 0) with the x-axis pointing to the right, the y-axis pointing up, and the z-axis coming out of the screen.

The Up vector is just a hint to the API to indicate which direction in the world is considered up. It is used by the camera to produce a valid x-axis vector which is then used to produce a new up vector for the camera. The values are used to create the orientation of the camera.

Quote:At the very bottom of your matrix you scale the camera's current position by each of the up right forward vectors but why what effect does this have?


You have to rotate around the camera's origin. This implies that I have a translation (T) and I am multiplying it by a rotation (R) to get TR = T * R.
By just placing the position of the camera in the modelview matrix, you would be creating the matrix RT = R * T. You do not want to do this because you would be taking the translation, which is moving coordinate frame to that position, and then rotating around the true, local origin. The matrix TR is really just rotating the camera around the local origin first and then creating translation based on that orientation. We take the opposite of that translation to undo what we are doing so the view will align with camera space.

We are really just skipping the matrix multiplication. Lets look at the matrices. Matrices below are in column major ordering. Note, we are taking the inverse of the translation matrix so we can undo what we have done.

--------------    ------------    --------------------------------------| Ux Uy Uz 0 |    | 1 0 0 -Tx |   | Ux Uy Uz (- Ux*Tx - Uy*Ty - Uz*Tz) || Vx Vy Vz 0 |    | 0 1 0 -Ty |   | Vx Vy Vz (- Vx*Tx - Vy*Ty - Vz*Tz) || Nx Ny Nz 0 | X  | 0 0 1 -Tz | = | Nx Ny Nz (- Zx*Tx - Zy*Ty - Zz*Tz) | =| 0  0  0  1 |    | 0 0 0  1  |   | 0  0  0     1                      |--------------    ------------    -------------------------------------------------------------| Ux Uy Uz -(U * Eye) || Vx Vy Vz -(V * Eye) || Nx Ny Nz -(Z * Eye) || 0  0  0    1        |-----------------------


I hope this helps you out. There are other ways of doing this. This one makes the most sense to me. I'm sure that a math major could do a much better job of explaining this than I can.
Yeah that makes it alot clearer but theres one last thing im a still a bit unsure of.

You work out the RIGHT vector using the UP vector but you dont seem to update it before hand does this have an impact on the camera axis i know a few lines down from that you do update the UP vector in relation to the others.
    Vector vN = vEye - vLookat; //forward vector    Vector vU = vUp ^ vN;//right vector (here you arnt taking into account any changes that have occured on Up vector or do you recalculate the new up vector before hand?)    vU.Normalize(); vN.Normalize();    Vector vV = vN ^ vU; //up vector

Its just if the UP vector has changed then the RIGHT vector would be wrong wouldnt it because you calculate the new right vector using the up vector before you update the up vector? sorry maybe its just me being daft.
Vector vN = vEye - vLookAt;

This statement is not the forward vector. It is close, but it represents the coordinate axis for the camera.

Vector vForward = vLookAt - vEye; or -(vN)

These two statments are your forward vectors.

Quote:Its just if the UP vector has changed then the RIGHT vector would be wrong wouldnt it because you calculate the new right vector using the up vector before you update the up vector? sorry maybe its just me being daft.


If your world up vector changes between frames, then all three of the orientation vectors would need to be recomputed.

The goal is to compute orthonormal vectors in the world frame corresponding to our view vectors. The up vector that we produce is trying to match the up vector of the world as closely as possible. Gram-Schmidt orthogonalization can be used to create the up vector based on the world up and the view direction. This is a process of creating a orthonormal basis from a possibly non-orthonormal basis.

Here is the formula: up = j - (j * dir) * dir

up - the new up vector for our frame
j - the world up vector
dir - the view direction

Lets take a look at what we did to create the up vector for our camera.

vV = vDir x (vUp x vDir);

We see that vUp x vDir is equal to the vU and then crossing that vector with the vDir gives us the new up vector for the camera. We can transform this equation into another equation using the triple product formulas.

U x (V x W) = (U * W) * V - (U * V) * W

The transformed vV: (vDir * vDir) * vUp - (vDir * vUp) * vDir

Assuming that the vDir vector is a unit vector, we can form the following for vV.

vV = (1) * vUp - (vDir * vUp) * vDir

Looks a lot like the formula above. What we are really trying to do is just get a vector that is close to the world up vector. As we see, we can leave calculating the up vector to be the last operation performed, or you can calculate it right away.

To give a visual example, the calculated up vector is just the projection of the world up vector onto the plane parallel to the right vector, which means the plane has a normal of the camera's coordinate z-axis. This would be the closest vector to up in this plane.

This topic is closed to new replies.

Advertisement