Archived

This topic is now archived and is closed to further replies.

Captian Goatse

Third person camera w/o trigonometry

Recommended Posts

Is it possible to do third person camera without trigonometric functions? U = x cam axis V = y cam axis N = z cam axis I''m using UVN based camera, and right now I understand that my front vector should go from view-pos to the center of the object. I use the triangle rule here to get the N vector, so that Vab = Vb-Va. Now I normalize the result to get unit vector (orthogonal), but this is where my knowledge stops. How to get U and V vectors? My V vector can''t be the same as the objects V vector. If I can''t find the U and V vectors, is there any way to make the camera point to the N direction? I understand gluLookAt takes in N vector, but how to accomplish this with the transformation matrix alone. I''m doing this, because I have a feeling that vector 3rd person camera is more intuitive than trig one. So basically I want to specify the point where my camera looks. For example set it to follow other objects.

Share this post


Link to post
Share on other sites
Yes, it's possible.

Let M be the matrix that positions the object the camera is behind. (For instance the player character). You should have M computed somewhere (since it's this matrix you use to render the character anyway.)

Let C be the matrix that positions the camera object relative to the player character, when the player character is at (0,0,0) looking down the z-axis. (This is not hard to do : simply build it yourself, since you know how it has to be.)

Then C*M is the matrix that positions the camera behind the character wherever the character may be in world space.

Which means M^(-1) * C^(-1) is the view matrix you have to use.

I'm doing this, because I feel like a matrix-based camera system is more intuitive than its trigonometric or vectorial equivalents.

ToohrVyk

EDIT : I seem to have problems with typing today...



[edited by - ToohrVyk on October 21, 2003 2:52:11 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by ToohrVyk
Yes, it''s possible.

Let M be the matrix that positions the object the camera is behind. (For instance the player character). You should have M computed somewhere (since it''s this matrix you use to render the character anyway.)

Let C be the matrix that positions the camera object relative to the player character, when the player character is at (0,0,0) looking down the z-axis. (This is not hard to do : simply build it yourself, since you know how it has to be.)

Then C*M is the matrix that positions the camera behind the character wherever the character may be in world space.

Which means M^(-1) * C^(-1) is the view matrix you have to use.

I''m doing this, because I feel like a matrix-based camera system is more intuitive than its trigonometric or vectorial equivalents.

ToohrVyk

EDIT : I seem to have problems with typing today...



Can you explain the C matrix that positions the camera object relative to the player character?

The result matrices are not orthogonal so there will be two matrix inverses, shouldn''t be that bad and does the infamous hack to do the transpose(M*C) * (Mtrans*Ctrans) work here, because I could technically store the transformation and orientation sperately if the inverses start to gap it out, which I highly doubt.

Anyhow, could you please elaborate the C matrix. Do I put the camera orientation and position into it or what exactly? Could you post an example.

Thanks a million anyway.

Share this post


Link to post
Share on other sites
This is inherently tied to the way the camera matrix works.
It''s really simple, first of all imagine the character is at (0,0,0), looking down the Z axis. Then, imagine you''re trying to position (by hand) a "camera" or "eyeball" mesh behind the character. This is like positioning any other mesh, so you shouldn''t have trouble placing the "eyeball" mesh, using a transform matrix that we''ll call C. Hypothetically, if you render the eyeball with a C matrix and the character the Identity matrix, and look at the two meshes with another, independent camera, they should be in the position you want the camera to be behind the player.

Now, if you multiply both positions by M (which puts the character mesh in its rightful, wanted position), the relative positioning of the character and the eyeball will stay unchanged (still behind the character). And the matrix of the eyeball will be M*C (that is, move it by C, then by M).

Finally, if you want to look through an object''s "eyes", all you have to do is set the view matrix to the inverse of that object''s matrix. What does that mean? The matrix takes all points (including the mesh ones) and moves them to a determined position. The inverse of the matrix will do the inverse transformation : move all the points of space so that the determined position above becomes "0,0,0 facing z". Since all the relative positioning of the other points will be unchanges, the inverse matrix will simply compute the coordinates of all points relative to the position determined by the matrix. Which is exaclty what the view matrix has to do. So you need to inverse M*C to look through your eyeball''s eyes.

The C matrix (which is an affine transform matrix) is orthogonal, and since so is M, M*C is orthogonal as well, which means (M*C)^(-1) = tC * tM (that''s not a hack, it''s real math).

I should write an article about that... Anyway, that''s basic linear algebra all you need to do is "see" it the right way and it becomes clear.

AND, off topic, O''Caml rulezz. ;-)

ToohrVyk

Share this post


Link to post
Share on other sites
Your last post confused me a little bit.

So what would this be in pseudo code?


This does not work for some reason, although if I understood this correct it should.

Matrix4f camera = view;
camera.transform(0, 0, -10); (z axis points forward transform behind the triangle)
transform = camera * triangle.transform;
transform.transpose();

view[ 0] = transform[0]; view[1] = transform[4]; view[ 2] = transform[ 8]; view[ 3] = 0;
view[ 4] = transform[1]; view[5] = transform[5]; view[ 6] = transform[ 9]; view[ 7] = 0;
view[ 8] = transform[2]; view[9] = transform[6]; view[10] = transform[10]; view[11] = 0;
view[12] = -(transform[0]*transform[12] +
transform[1]*transform[13] +
transform[2]*transform[14]);

view[13] = -(transform[4]*transform[12] +
transform[5]*transform[13] +
transform[6]*transform[14]);

view[14] = -(transform[8]*transform[12] +
transform[9]*transform[13] +
transform[10]*transform[14]);
view[15] = 1;
glLoadMatrixf(view);


However it doesn't work, since when I move the triangle the view frustum does not follow.

[edited by - Captian Goatse on October 22, 2003 11:09:38 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by ToohrVyk
I seem to have problems with typing today...

Don''t you just HATE that?! When I''m having a bad typing day (when I make many errors) I usually smash my hands on the keyboard because of the frustration...

Share this post


Link to post
Share on other sites
...

Why do you insist on going down into the matrix coefficients? Can't you use provided helper functions for translation, rotation, inversion and multiplication?

pseudocode :

START FRAME

(*move camera back, and up from the player*)
let X1 = matrix_translation( 0, -2, -5 );;

(*make the camera look down a little*)
let X2 = matrix_rotation_X_axis( PI / 12 );;

(*multiply the two parts to get the final camera matrix*)
let C = X1 * X2;;

(*compute your M matrix*)
let M = compute_character_position_matrix( );;

(*multiply C and M together*)
let Final = M * C;;

(*inverse the final matrix to get the viewmatrix*)
let View = matrix_inverse( Final );;

(* apply the view matrix *)
set_view_matrix( View );;


RENDER, then END FRAME

ToohrVyk



[edited by - ToohrVyk on October 22, 2003 11:24:38 AM]

Share this post


Link to post
Share on other sites
just a very simple way (as in simple to do but not the most efficient).

you know the matrix for the object, copy that for your camera.

assuming opengl placing it behind the object would be:

Mat[12] -= distance * Mat[8];
Mat[13] -= distance * Mat[9];
Mat[14] -= distance * Mat[10];

to rotate it, just apply the rotation to the matrix before you translate back. to end up a little above the object just rotate down:

as we're lazy, dont care about the last bit of performance and dont like trig we let opengl do it.

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(Mat);
glRotatef(-30, 1,0,0);
glTranslatef(0,0,-distance); //if we REALLY dont want to do it ourself
glGetFloatv(GL_MODELVIEW_MATRIX, Mat);

to orbit the object you could even get away with euler angles for a change (if you dont want to roll). to store a relative position instead of rotating and translating again and again ToohrVyks way should definitely work. the camera matrix would store its orientation/position relative to the origin and multiplying with the objects matrix should give the correct result.

btw. looking at captians code again he is not doing any transformations, just handles the inversion himself. just the first part is confusing me. if view is the inverted (ie view matrix) shouldnt that be inverted first to get the camera transform before applying the translation? and i admit i dont get it why transform is transposed before inverting. so without being sure what some of those things really are i might be cheap and try switching camera and triangle.transform.

[edited by - Trienco on October 22, 2003 1:11:10 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Trienco
and i admit i dont get it why transform is transposed before inverting. so without being sure what some of those things really are i might be cheap and try switching camera and triangle.transform.

[edited by - Trienco on October 22, 2003 1:11:10 PM]


Matrix M is orthogonal if and only if its inverse is equal to its transpose, thus I can directly just transposing it and not inverting at all. So all vectors are perpendicular in the three dimensions and U cross V cross N = 0.

Damn, I don''t think the matrices I''m using are orthogonal, since orthogonal matrices can only express rotations according to mathematics for 3d fame programming & computer graphics.

Share this post


Link to post
Share on other sites
quote:
Original post by DrEvil
Can't you make a very simple and easy hard attach camera if you multiply the objects matrix by an "offset" matrix and use that for the cameras matrix?


No, because the initial plan was to have the camera to always point to the object it is following so that the object is in the center of the screen.

So basically what I want is my N vector pointing towards object.center


Edit: Yeah, I wasn't really clear in the beginning. I don't want to have any approximations at all. I just want my camera to point to the center of the object, and I got confused what Thoor said, since fundamentally his approach too needs to have the camera adjusted via trig (PI/12).

Apparently I'm left with vector equations UxVxN=0 where N is the only one I know.

[edited by - Captian Goatse on October 22, 2003 2:08:38 PM]

Share this post


Link to post
Share on other sites
So basically a follow cam combined with a "look at".

Mult the camera by the objects matrix and an offset matrix and apply a lookat behavior.(sorry it's renderware code, but should be easy to understand.

// Target and camera position
RwV3d targetPosition = *RwMatrixGetPos(RwFrameGetLTM(targetFrame));
RwV3d eyePosition = *RwMatrixGetPos(RwFrameGetLTM(eyeFrame));

// Look-At Vector
RwV3d *zAxis = RwMatrixGetAt(RwFrameGetMatrix(eyeFrame));

// Find the look at vector and normalize it.
RwV3dSub(zAxis, &targetPosition, &eyePosition); // RwV3dSub = subtract
RwV3dNormalize(zAxis, zAxis);

// Rebuild the camera X & Y vectors.
RwV3d *xAxis = RwMatrixGetRight(RwFrameGetMatrix(eyeFrame));
RwV3d *yAxis = RwMatrixGetUp(RwFrameGetMatrix(eyeFrame));

RwV3dCrossProduct(xAxis, &RW::yAxis, zAxis);
RwV3dNormalize(xAxis, xAxis);

RwV3dCrossProduct(yAxis, zAxis, xAxis);
RwV3dNormalize(yAxis, yAxis);

// Note first parameter of the sub, crossproduct, & normalize is where it will be stored.

[edited by - drevil on October 22, 2003 2:25:59 PM]

Share this post


Link to post
Share on other sites
If you''re using 4x4 matrices, then rotation, translation and scaling all have orthogonal matrices. And any combination thereof, will be orthogonal as well. So unless you are doing *shearing* or *projection*, your matrices will be orthogonal.

I still stand by my method. I could create this effect without accessing even a single matrix coefficient, so you should be able to do it too.

ToohrVyk

Share this post


Link to post
Share on other sites
quote:
Original post by ToohrVyk
If you''re using 4x4 matrices, then rotation, translation and scaling all have orthogonal matrices. And any combination thereof, will be orthogonal as well. So unless you are doing *shearing* or *projection*, your matrices will be orthogonal.

I still stand by my method. I could create this effect without accessing even a single matrix coefficient, so you should be able to do it too.

ToohrVyk





Hey, I had a glitch in my matrix. Thanks for point it out. I didn''t multiply my matrix by the translation, but kept adding it to the spatial component :/

That''s probably the reason why your method didn''t work.

Share this post


Link to post
Share on other sites