PDA

View Full Version : Camera & Projection matrixes in OpenGl

11-21-2010, 12:48 PM
Hello everybody. I'm now learning mathematical basics of perspective projection and camera positioning. I want to make my own gluLookAt function, which I did, but it is not doing the task it should do. So a few questions about this.

Firstly OpenGl has model-viev matrix known as current vertex transformation: CT = V*M; To add some affine transformation to vertexes I do this: CT = CT * MNew - which works fine in my program. But how do I add new camera transformation? Is it done in this way: CT = VNew * CT? How do I need to apply my new camera transformation, setted by matrix V? Doing so in my program it functions somewhat strange...

If apply new transformation like this:

TVector3D eye = {0, 0, 1};
TVector3D look = {0, 0, 0};
TVector3D up = {0, 1, 0};
LookAt(eye, look, up);

- my program results in simple picture zooming.

if apply this:

TVector3D eye = {0, 0, -1}; //notice sign -
TVector3D look = {0, 0, 0};
TVector3D up = {0, 1, 0};
LookAt(eye, look, up);

the new image is turned in some different way, it is like it was mirrored, turned in 90 degrees and zoomed out a little bit.

Here is the code for my function LookAt:

void LookAt(TVector3D eye, TVector3D look, TVector3D up)
{
//here i'm calculating this:
//n = eye - look;
//u = up x n;
//v = n x u;
TVector3D n, u, v;
Diff(eye, look, n);
VectMult(up, n, u);
Normalize(&amp;n);
Normalize(&amp;u);
VectMult(n, u, v);

float x, y, z, c;
//Now i'm calculating this: CT = V * CT;
x = u.x * CT[0][0] + u.y * CT[1][0] + u.z * CT[2][0];
y = u.x * CT[0][1] + u.y * CT[1][1] + u.z * CT[2][1];
z = u.x * CT[0][2] + u.y * CT[1][2] + u.z * CT[2][2];
c = u.x * CT[0][3] + u.y * CT[1][3] + u.z * CT[2][3] - (eye.x * u.x + eye.y * u.y + eye.z * u.z);

CT[0][0] = x;
CT[0][1] = y;
CT[0][2] = z;
CT[0][3] = c;

x = v.x * CT[0][0] + v.y * CT[1][0] + v.z * CT[2][0];
y = v.x * CT[0][1] + v.y * CT[1][1] + v.z * CT[2][1];
z = v.x * CT[0][2] + v.y * CT[1][2] + v.z * CT[2][2];
c = v.x * CT[0][3] + v.y * CT[1][3] + v.z * CT[2][3] - (eye.x * v.x + eye.y * v.y + eye.z * v.z);

CT[1][0] = x;
CT[1][1] = y;
CT[1][2] = z;
CT[1][3] = c;

x = n.x * CT[0][0] + n.y * CT[1][0] + n.z * CT[2][0];
y = n.x * CT[0][1] + n.y * CT[1][1] + n.z * CT[2][1];
z = n.x * CT[0][2] + n.y * CT[1][2] + n.z * CT[2][2];
c = n.x * CT[0][3] + n.y * CT[1][3] + n.z * CT[2][3] - (eye.x * n.x + eye.y * n.y + eye.z * n.z);

CT[2][0] = x;
CT[2][1] = y;
CT[2][2] = z;
CT[2][3] = c;

}
//-------------------------------------------------------------
void Diff(TVector3D &amp;eye, TVector3D &amp;look, TVector3D &amp;result)//finds vector difference
{
result.x = eye.x - look.x;
result.y = eye.y - look.y;
result.z = eye.z - look.z;
}
//-------------------------------------------------------------
void VectMult(TVector3D &amp;a, TVector3D &amp;b, TVector3D &amp;result)
{//finds vectors vector multiplication
//|i j k |
//|a.x a.y a.z|
//|b.x b.y b.z|
result.x = a.y * b.z - b.y * a.z;
result.y = -(a.x * b.z - b.x * a.z);
result.z = a.x * b.y - b.x * a.y;
}
//-------------------------------------------------------------
void Normalize(TVector3D *vect)
{
float len = Sqrt(vect->x * vect->x + vect->y * vect->y + vect->z * vect->z);
vect->x /= len;
vect->y /= len;
vect->z /= len;
}

11-22-2010, 05:18 AM
People! Why you're ignoring my posts? I know that I'm asking thing nobody cares about because of OpenGl which has done all work for programmers. But I want to go deeper, I want to undarstand what I'm dooing, so please help! Haven't I provided enought information for you to poing me out the problem?

ugluk
11-27-2010, 09:23 PM
I never use gluLookAt(), here's some code I use:

//////////////////////////////////////////////////////////////////////////////
template <typename T, std::size_t Sz>
inline void modelview_matrixa(Vector<T, Sz> const&amp; origin,
Vector<T, Sz> const&amp; xv, Vector<T, Sz> const&amp; yv, Vector<T, Sz> const&amp; zv,
Matrix<T, 4, 4>&amp; matrix)
{
typedef Matrix<T, 4, 4> Matrix;

Matrix matrixa;

matrixa(0, 0) = xv(0);
matrixa(0, 1) = xv(1);
matrixa(0, 2) = xv(2);
matrixa(0, 3) = 0;

matrixa(1, 0) = yv(0);
matrixa(1, 1) = yv(1);
matrixa(1, 2) = yv(2);
matrixa(1, 3) = 0;

matrixa(2, 0) = zv(0);
matrixa(2, 1) = zv(1);
matrixa(2, 2) = zv(2);
matrixa(2, 3) = 0;

matrixa(3, 0) = 0;
matrixa(3, 1) = 0;
matrixa(3, 2) = 0;
matrixa(3, 3) = 1;

Matrix matrixb(identity<Matrix>());

matrixb(0, 3) = -origin(0);
matrixb(1, 3) = -origin(1);
matrixb(2, 3) = -origin(2);

matrix = matrixa * matrixb;
}

//////////////////////////////////////////////////////////////////////////////
template <typename T, std::size_t Szv, std::size_t Szm>
inline void modelview_matrixb(Vector<T, Szv> const&amp; origin, T theta, T phi,
Matrix<T, Szm, Szm>&amp; matrix)
{
T ct(std::cos(theta));
T st(std::sin(theta));

T cp(std::cos(phi));
T sp(std::sin(phi));

Vector<T, 3> xv(cp, 0, sp);
Vector<T, 3> yv(sp * st, ct, -cp * st);
Vector<T, 3> zv(-sp * ct, st, cp * ct);

modelview_matrixa(origin, xv, yv, zv, matrix);
}

You can use this also, if you download and install the tvmet library. But watch it, by default the GL, if you've used the fixed pipeline, will expect a transposed modelview matrix. Some folks call this kind of a viewing matrix a fps viewing matrix.

I think the matrix gluLookAt() produces is actually documented in the docs somewhere. Check here:

http://www.opengl.org/sdk/docs/man/

And look for gluLookAt().

Come to think of it, I ought to optimize these 2 functions a bit.

12-01-2010, 10:49 AM
ugluk
Thank you for your code and the link! I have now solved the problem with my LookAt function, actually a had 2 problems with the function:
1: The computations were a little bit wrong, because the computations of CT[0][1]..CT[0][4] at the beginning of my function are used 2 more times at further residual computations, which surely influences the result of calculation, I'm now saving the result of matrix multiplication to another ct[3][4] array & then copy result back to CT.
2: And the way I used camera transformation were also wrong, I had to call LookAt function one time per frame & then draw all other objects of my scene & at the end of drawing I had to return to ModelViewIdentity matrix, which wasn't obvious for me before.

But now I have another trouble, I'm trying to implement Cohen–Sutherland clipping algorthithm in 3D space. 2D version of my algorithm works fine, lines are cutted accordingly to screen height & width, but 3D version which works with viewing volume is not working properly, and I don't know should I post a question about this.. will I get the answer..

ugluk
12-01-2010, 12:35 PM
Don't know if you will, try testing your algorithm on some dummy data. If 2d version works, that's good news.

Anyway, if you need more help with gluLookAt() and other utility functions you can always download mesa3d and look at it's source code.

My advice to you is, learn how to batch, that's the most important thing.