Game Development Community

The Camera Matrix

by Peter Christensen · in Torque Game Engine · 08/31/2002 (10:07 pm) · 18 replies

I'm not entirely sure this is the right forum for this, but whatever.

I'm piecing through some Torque code (radar, specifically). It utilizes the camera matrix.

If anyone knows exactly what each number in that matrix stands for, I'd appreciate hearing it.

Thanks,

Peter C.

About the author

Recent Threads


#2
09/01/2002 (9:13 am)
Thanks for trying to help.

What I'm interested in is what comes of this code:
MatrixF cam;
GameConnection* conn = GameConnection::getServerConnection();
conn->getControlCameraTransform(0,&cam);

What I would like to know is what every value in "cam" stands for.
#3
09/01/2002 (9:40 am)
From my understanding, that returns the DGL transformation matrix for the camera's location. It's not really possible to get a listing of what every element in the matrix is, because of the way it's generated. It starts with an identity matrix I, which is:

1 0 0 0
[b]I[/b] = 0 1 0 0
    0 0 1 0
    0 0 0 1

That doesn't mean anything in and of itself, but it's special because any matrix multiplied by I returns the first matrix. You start with this matrix, then postmultiply it with the translation, rotation, and scale matrices like this:

M = T(Rz)(Ry)(Rx)SI

where

1 0 0 x
[b]T[/b] = 0 1 0 y
    0 0 1 z
    0 0 0 1

(t = theta = angle in radians)

     1  0      0        0
[b]Rx[/b] = 0 (cos t) -(sin t) 0
     0 (sin t) (cos t)  0
     0 0       0        1

     (cos t)  0 (sin t) 0
[b]Ry[/b] = 0        1 0       0
     -(sin t) 0 (cos t) 0
     0        0 0       1

     (cos t) -(sin t) 0 0
[b]Rz[/b] = (sin t) (cos t)  0 0 
     0       0        1 0
     0       0        0 1

    
(Sx, Sy, Sz are the scale factors for each axis)

    Sx 0  0  0
[b]S[/b] = 0  Sy 0  0  
    0  0  Sz 0
    0  0  0  1

Coming up with a transformation matrix by multiplying all these matrices together is really a one-way operation, and you can't really look at it and determine what each element is from the result. About the only thing you can do is look at the last column (in I, it's

0
0
0
1

). The top element in this vector is the object's X position, the second is Y position, and the third is Z position. Other than that, there's not a whole lot you can do with the other elements.

-Corvi

(Bleah, the first line won't indent. Just pretend it does, okay?)
#4
09/01/2002 (3:51 pm)
Indeed I can pretend as though the first line indents. No problem there.

Thanks for informing me. I wish someone had just said it was the matrix to transform from world space to view/eye space. That is the case, isn't it? If I multiply a 3D coordinate (Actually, 4D with the 4th element as 1) defined in world space, it will translate and rotate it to view space, right?

Or is the idea the camera matrix moves the camera to the world origin? This way doesn't make to much sense to me, but I'm just making sure.

Again, thanks for the help.
#5
09/01/2002 (4:00 pm)
I'll admit I haven't really looked into this too much in TGE, but in OpenGL, this transformation matrix moves/reorients the camera from the origin facing down the X axis to wherever you want it with the desired orientation. I think this is an eyespace->worldspace conversion... I can't ever keep them straight. :) I just think of it as moving/rotating the camera.
#6
09/01/2002 (9:21 pm)
Well, I implemented the code like I thought it should be, and the results were nowhere close.

My guess was that I could multiply the coordinates of a player's position by the camera matrix, and I'd have the player's position relative to the camera. This is not the case.

I can post the code later if you think that'd help.
#7
09/02/2002 (7:00 am)
Multiplication should only probably be used to generate the camera matrix, not to work with it. If you want go get, say, (10, 0, 0) relative to the camera, you can do something like this:

ShapeBase* control = conn->getControlObject();
if (!control) return;

// Target pos to test, if it's a player run the LOS to his eye
// point, otherwise we'll grab the generic box center.
Point3F shapePos;
	
if (control->getType() & PlayerObjectType) 
{
  MatrixF eye;
  control->getEyeTransform(&eye);
  eye.getColumn(3, &shapePos);
}
else shapePos = control->getBoxCenter();

// We have the camera location in shapePos, so we can use that as an origin for whatever we want to do:

shapePos.x += 10;

We now have (10, 0, 0) relative to the camera to do whatever we want.

You can also apparently do something like this (after looking at code):

cam.getColumn(1,&camRot);

to get the camera angle in a Point3F as a vector. If you want to get 10 units in front of the player, you can normalize this vector and use it something like this:

destloc = shapePos + forward * 10;

-Corvi
#8
09/02/2002 (9:29 am)
The first example makes lots of sense. Unfortunately, that's only getting an object to (x, y, z) in world space away from the camera. If the camera were always looking down the +Y axis with the up vector as the +Z axis, this would work. But I'm sure I cannot assume either of those things.

Getting the camera direction helps. But, position and direction still leave at least one variable (roll, I think) open.

I don't want to sound like I'm ragging on you, for you've been a great help to me. I just still am in the dark as to defining an orthogonal space as defined by the camera's position and orientation in terms of world space.
#9
09/02/2002 (1:47 pm)
The first example makes lots of sense. Unfortunately, that's only getting an object to (x, y, z) in world space away from the camera. If the camera were always looking down the +Y axis with the up vector as the +Z axis, this would work. But I'm sure I cannot assume either of those things.

Well, it depends on what you're doing with it. If you're doing an FPS with no vehicles or anything like that, you can design things so you don't use the roll component at all. However, the spiffy vehicle code uses roll for banking around turns, so this method likely won't work for it.

Getting the camera direction helps. But, position and direction still leave at least one variable (roll, I think) open.

That'd be it, yeah. Roll is the one thing we're missing, and I'm not sure how to grab that from the camera matrix. If you can get the other two components (in vector form), it has to be possible to get the roll; I'm just not sure exactly how. Sorry. =/

[Edit: it's possible that the roll is stored as the fourth element in that column. I don't have code with me ATM, but I'll check it out when I get home.]

I don't want to sound like I'm ragging on you, for you've been a great help to me. I just still am in the dark as to defining an orthogonal space as defined by the camera's position and orientation in terms of world space.

Nonono... it doesn't seem like that at all. I'd be doing exactly the same thing. :)

Are you working on something in particular that needs this information? I might be able to explain better if I had a specific example to work with.

[Edit 2: After looking at the link at the top of the thread, that might be a better approach to take for this, as you get position, orientation, AND roll out of the function. Might be worth a shot, and is significantly easier than pulling things from the matrix. :) ]
-Corvi
#10
09/02/2002 (10:03 pm)
Technically, I don't need to know any of this stuff for the piece of code to work. It already works. I'm just trying to get this down so that later I won't have a problem with it.

Today I did the math of multiplying the matrices out. Personally, I cannot see how anything can be pulled from the camera matrix except the location. Kinda makes me wonder why the information is kept in that form, when the 3x3 part of the matrix would be far easier to understand if it were the x, y and z vectors.

The complexity of the final multiplication matrix makes me think that the camera matrix is not actually a transform. It makes me think they just stacked camera info in a matrix. Also, the matrix as-is does not seem to be useful for any purpose. If you want info, you have to wrangle around with it. Oh well. Maybe I'm wrong.

It seems like defining a 3D orthogonal space that is the camera view should only take 1 or 2 lines of code. But from what I've seen, it's not already in the engine. This is not a strange request, is it?
#11
09/03/2002 (11:45 am)
Actually, I thought of something.

Say the matrix returned is actually a transform from (0, 0, 0) in world space to (x, y, z) in world space with the correct orientation. If we multiplied the unit vectors {(0,0,1);(0,1,0);(1,0,0)} by the inverse transpose of the camera matrix, shouldn't they be the unit vectors for the camera view? I would think so, although the vectors may need renormalizing.

Sound plausible?
#12
09/03/2002 (1:35 pm)
You know, that may be right. Worth a try, at least. :)

I'd verify it, but I'm HORRIBLE at matrix math.

Err, that is what the transformation matrix is. Dunno about the unit vector trick, though.
#13
09/03/2002 (3:53 pm)
speaking of cams- you guys know if the matrix defines how the screen is rendered;
fisheye or flat?

?

just curious, no reason
#14
09/03/2002 (3:57 pm)
The matrix should only handle the positioning, not the render proterties. You'd need to look for things like the glPerspective() and glFrustrum() calls to set up the scene to determine those settings (FOV, view volume, etc.)
#15
09/03/2002 (4:11 pm)
The matrix should only handle the positioning, not the render proterties. You'd need to look for things like the glPerspective() and glFrustrum() calls to set up the scene to determine those settings (FOV, view volume, etc.)

Yup. Perspective is set in a different place than the camera transform.
#16
09/04/2002 (2:02 am)
Oh yeah!

Not only is the radar code far simpler, but it's faster. I figured that a concatenation of translation and rotation would be an orthogonal transform, so the computation of the inverse transpose was not needed. If scaling factors were added, the inverse transpose would need computed, I think.

Plus, I updated it to stretch the base texture to the UI rectangle size and draw the player objects accordingly.

So indeed the camera matrix is a transform.
#17
09/04/2002 (8:56 am)
Glad to hear it. Congratulations. :)
#18
09/04/2002 (10:42 am)
After looking at the matrix/vector multiplication, I realized that another speed increase can be made.

MatrixF cam; // Assume it's initialized correctly
VectorF xAxis(1, 0, 0);

// Assume that the inverse transpose of cam is cam

cam*xAxis = |aa ab ac ad|*|1| = |aa|
            |ba bb bc bd| |0|   |ba|
            |ca cb cc cd| |0|   |ca|
            |da db dc dd| |0|   |da|

// Now, why bother when we know where all the zeros in the vector are?
// The faster version would be:
cam.getColumn(0, &xAxis);
A similar version will speed up finding the y axis. And, of course, you could get the z axis as well, although for radar, I'm not concerned with it.



EDIT: This way introduces a bug. The radar works perfectly when the camera is faced basically parallel to the ground. If the camera is faced perpendicularly to the ground, then the y axis of the radar measures height above the model. I'll see if I can work with the vectors in 2D to correct this problem.