Implementing a LookAt matrix

Started by
4 comments, last by wolfscaptain 12 years, 11 months ago
I usually work with simple translations and rotations using the old style (but with my own functions) translatef and rotatef.
I need an actual way to set a modelview matrix to look from point A to point B for the first time, and while I googled the correct equations, I can't seem to get it to work.

I set a simple perspective projection, probably the one seen most on the internet (45, width / height, 0.1, depth).

To get the LookAt matrix I tried this http://www.opengl.org/wiki/GluLookAt_code , and this http://stackoverflow.com/questions/349050/calculating-a-lookat-matrix .

In the first one, it just doesn't aim the camera. For example, sending [0, 100, -600], [0, 0, 0], [0, 1, 0] (as in look at the origion from the point 0,100,-600), it just translates the objects by [0, 100, -600] instead of keeping them in the middle and rotating them a little about the X axis (since the camera is higher them them).

The second link gave weird results which I couldn't figure out.

Anyone got any ideas?

Thanks.
Advertisement
I just duplicated the results here in my own code.

http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml

It shouldn't be too difficult to figure out, maybe post your code? Also you can compare your matrix float by float versus the actual matrix generated by gluLookAt, to see if you've made a typo somewhere.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game

I just duplicated the results here in my own code.

http://www.opengl.or...l/gluLookAt.xml

It shouldn't be too difficult to figure out, maybe post your code? Also you can compare your matrix float by float versus the actual matrix generated by gluLookAt, to see if you've made a typo somewhere.


That didn't work correctly either, I don't understand what I am doing wrong.
Using the same names GLU uses, given [100, 100, 100] as the eye, [0, 0, 0] as the center, and [0, 1, 0] as up, it returns seemingly good numbers:
[source [color="#1C2837"]lang="javascript"[color="#000000"]]
s = -0.707,0,-0.707
u = 0.408,0,0.408
f = -0.577,-0.577,-0.577
matrix = -0.707,0,-0.707,0,0.408,0,0.408,0,0.577,0.577,0.577,0,0,0,0,1
matrix after multiplying by the reverse eye translation =
-0.707,0,-0.707,0,0.408,0,0.408,0,0.577,0.577,0.577,0,-27.849,-57.735,-27.849,1
[/source]
[font="Consolas,"]Yet again, it doesn't center the model, but rather translates it around (which suggests it isn't rotating for some reason).[/font]
[font="Consolas,"][/font]
[font="Consolas,"]My code is in JavaScript, but it should be pretty straightforward:[/font]
[font="Consolas,"][source [color="#1C2837"]lang="javascript"[color="#000000"]]
[/font]Array.prototype.lookAt = function (eye, center, up) {
var f = (center.sub(eye)).normalize();
up = up.normalize();
var s = (f.cross(up)).normalize();
var u = s.cross(f);
var m = [s[0], s[1], s[2], 0, u[0], u[1], u[2], 0, -f[0], -f[1], -f[2], 0, 0, 0, 0, 1];

return m.multMatrix([].translation(eye.negative()));
};
[/source]
I just did this exact thing, something useful to remember:
In a 4x4 transform matrix (orthonormal with no scale, i.e. a normal camera matrix) the top left 3x3 elements represents rotation. The columns of this matrix are actually the unit axis after rotation. So in the identity matrix they are <1,0,0>, <0,1,0>, and <0,0,1>, because these are the unit axis in an coordinate frame with no rotation (i.e. world space). The column vectors <0,-1,0>, <1,0,0>, <0,0,1> represents a rotation of -90degrees around the z axis (in a right handed system).
The 4th column in the 4x4 is the translation vector. Using this info should make it pretty easy to see what the glLookAt function is actually doing.
You should note that the gluLookAt code generates a matrix that is designed to be directly applies as the view matrix, WITHOUT inverting. You are probably used to having to invert your camera tranformations before using them (e.g. translate -100,0,0 to move the eye to 100,0,0 etc.). With the gluLookAt function you don't need to invert the result it is already inverted.

var m = [s[0], s[1], s[2], 0, u[0], u[1], u[2], 0, -f[0], -f[1], -f[2], 0, 0, 0, 0, 1];
[/quote]

This looks transposed from how it should be (if you're using standard opengl convention). When using opengl api functions, it expects the values in column major ordering, i.e.

var m = [s[0], u[0], -f[0], 0, s[1], u[1], -f[1], 0, s[2], u[2], -f[2], 0, 0, 0, 0, 1];
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Transposing didn't effect the result. This is also how the GLU page shows it being stored.

Now here are all the steps taking effect on the rendering:

The projection matrix is set as the normal perspective projection (45, width / height, 0.1, depth).
Every frame, the modelview matrix is set to the identity matrix, which is then multiplied by the matrix outputted from the above function, so identityMatirx * lookAt(eye, center, up) which in turn is identityMatirx * (lookAtMatrix(eye, center, up) * translationMatrix(-eye)).
The shader then receives the result of projectionMatirx * modelviewMatrix and transforms every vertex by it.

What have I done wrong? Why isn't this thing keeping a model - originally located at the origin - at the origin, and rotating around him like it should?

This topic is closed to new replies.

Advertisement