Camera Matrix

Started by
7 comments, last by angry 18 years, 10 months ago
edit: Read my post at post 8 for a better explanation. I'm not really sure how to describe my problem, however, I will do my best. I have this camera class which has only one matrix which contains it's orientation and position in the world. The negative z-axis of the camera matrix tell which direction the camera is looking at. Now if I multiply this camera matrix with the world matrix, which is an identity matrix, it will change the current reference system to the cameras reference system, right? So if I then create and move any objects in the scene they will all be moved relative to the camera and it's reference system, but I want them to move by the world reference system. Anyone know how I can do that? It should be a really simple task, really, but I can't figure it out. [Edited by - angry on June 13, 2005 4:20:59 AM]
Advertisement
If I do it this way:
// renderworld.identity();camera.rotate(0.0, yRot, 0.0);camera.translate(0.0, 0.0, zPos);world = world * camera.inverse();object.rotate(0.0, 45.0, 0.0);object.translate(0.0, 0.0, -5.0); // z goes into the screenworld = world * object;// do the same for other objects...


the objects in the scene will rotate and not the camera. So if I change place of rotate and translate for the camera, it will rotate the camera, though you won't be able to move towards the axis it's facing. It will only move in the z axis of the world.

Any ideas, of how I can make my camera move in the direction it's negative z-axis i facing?
Think about it this way. The camera's orientation/position matrix transforms the camera's space into world space. That is, a position in the camera's space is transformed into world space by multiplying it by the camera's orientation/position matrix. Now, to transform a world space position into to the camera's space, you do the opposite -- multiply it by the inverse of the camera's orientation/position matrix.

The inverse of the camera's orientation/position matrix is called the view matrix.

The world matrix in D3D transforms model coordinates into world space. It is not related to the camera. It is used to move objects around in world space. In OpenGL, the world matrix is combined with the view matrix and called the model-view matrix.

So, in D3D use the world matrix to move objects around, and set the view matrix according to the camera's orientation/position. In OpenGL, set the model-view matrix according to the camera's orientation/position first, then use push, pop, rotate, translate, etc. to position objects.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Hmm... I'm using openGL, and to me it seems like im doing just as you say I should do... Here's the real code:
// in render method...glMatrixMode(GL_MODELVIEW);glLoadIdentity();camera.identity();camera.transform.rotate(0.0f, rotY, 0.0f); // rotY is changed by the left and right arrows on the keyboardcamera.transform.translate(0.0f, 0.0f, posZ); // posZ is changed by the up and down arrows on the keyboardglLoadMatrixf(camera.transform.inverse());glPushMatrix();	glTranslatef(-1.0f, 0.0f, 0.0f);	drawWireBox(2.0f, 0.4f, 1.0f);glPopMatrix();

, but still my camera won't move in the direction it's z-axis is facing...

[Edited by - angry on June 12, 2005 5:53:45 AM]
You probably want to rotate then translate, but really that depends on how your operations concatenate matrices. In OpenGL notation/convention, transformation A followed by transformation B should result in AB, not BA.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
If I rotate the camera before I translate it, the rendered object will spin around, and not the camera. And if I translate and then rotate the camera, it will rotate the camera, but still just move forward and backwards and not in the direction it's negative z-axis is facing, or where it's negative z-axis should be facing, ehm...
As John mentioned, it's not completely clear from your code how your camera matrix is constructed, so it's difficult to give specific advice on how to fix the problem.

Here's a brief description of how my camera is set up - perhaps it will be helpful to you in some way.

The camera is an object just like everything else. It has an orientation, and a position. The orientation is a 3x3 matrix, and the position is a vector. These can of course be combined into a 4x4 matrix when necessary.

The columns (for consistency with OpenGL) of the matrix are the direction vectors (local axes) of the object. You can move your object by adjusting the position vector by multiples of these vectors. In your case you would use the negative of the third column.

To transform a vertex from the local space of an object into the local space of the camera, you would first multiply it by the object's transformation matrix, and then by the camera's inverse transformation matrix:

vWorld = objectMatrix * vLocal
vCamera = inverse(cameraMatrix) * vWorld

Or:

vCamera = inverse(cameraMatrix) * objectMatrix * vLocal

Or:

vCamera = M * vLocal

Where:

M = inverse(cameraMatrix) * objectMatrix

So the OpenGL sequence might look something like this:

cameraInverseMatrix = inverse(cameraMatrix);
glLoadIdentity();
glMultMatrix(cameraInverseMatrix);
glMultMatrix(objectMatrix);

I don't know if any of that will be helpful to you, but feel free to ask if you have questions about any of the above.
Im getting more and more confused, as when I see your examples it looks just like what I'm doing...

My matrix/transform class looks like this, it's a 4x4 matrix:

edit: oh, and I have compared the results of my rotate() and translate() methods with the glTranslate and glRotate functions, and the matrix results are the same. So there shouldn't be any errors in my translate, rotate and multiply methods.
class Transform{public:	float m[16];public:	inline Transform();	inline Transform(const float* fmatrix);	inline Transform(const Transform& transform);	inline Transform& 	operator = (const float* fmatrix);	inline Transform&	operator = (const Transform& transform);	inline Transform& 	operator*= (const Transform& transform);	inline Transform	operator * (const Transform& transform);	inline float&		operator [] (unsigned int i);	inline const float&	operator [] (unsigned int i) const;	inline			operator float*();	inline			operator const float*() const;	inline void		identity();	inline Transform&	multiply(const Transform&);	static Transform&	multiply(Transform&, const Transform&, const Transform&);	Transform		inverse();	void			invert();	void			translate(float x, float y, float z);	void			rotate(float x, float y, float z);	inline void	reset();protected:	inline void copy(const float* fmatrix);	inline void copy(const Transform& transform);};//---------------------------------------------------------------------inline Transform& Transform::multiply(const Transform& transform){	return multiply(*this, *this, transform);}//---------------------------------------------------------------------Transform& Transform::multiply(Transform& mr, const Transform& m1, const Transform& m2){	float res[16];	res[ 0] = m2[ 0]*m1[0] + m2[ 1]*m1[4] + m2[ 2]*m1[ 8] + m2[ 3]*m1[12];	res[ 1] = m2[ 0]*m1[1] + m2[ 1]*m1[5] + m2[ 2]*m1[ 9] + m2[ 3]*m1[13];	res[ 2] = m2[ 0]*m1[2] + m2[ 1]*m1[6] + m2[ 2]*m1[10] + m2[ 3]*m1[14];	res[ 3] = m2[ 0]*m1[3] + m2[ 1]*m1[7] + m2[ 2]*m1[11] + m2[ 3]*m1[15];	res[ 4] = m2[ 4]*m1[0] + m2[ 5]*m1[4] + m2[ 6]*m1[ 8] + m2[ 7]*m1[12];	res[ 5] = m2[ 4]*m1[1] + m2[ 5]*m1[5] + m2[ 6]*m1[ 9] + m2[ 7]*m1[13];	res[ 6] = m2[ 4]*m1[2] + m2[ 5]*m1[6] + m2[ 6]*m1[10] + m2[ 7]*m1[14];	res[ 7] = m2[ 4]*m1[3] + m2[ 5]*m1[7] + m2[ 6]*m1[11] + m2[ 7]*m1[15];	res[ 8] = m2[ 8]*m1[0] + m2[ 9]*m1[4] + m2[10]*m1[ 8] + m2[11]*m1[12];	res[ 9] = m2[ 8]*m1[1] + m2[ 9]*m1[5] + m2[10]*m1[ 9] + m2[11]*m1[13];	res[10] = m2[ 8]*m1[2] + m2[ 9]*m1[6] + m2[10]*m1[10] + m2[11]*m1[14];	res[11] = m2[ 8]*m1[3] + m2[ 9]*m1[7] + m2[10]*m1[11] + m2[11]*m1[15];	res[12] = m2[12]*m1[0] + m2[13]*m1[4] + m2[14]*m1[ 8] + m2[15]*m1[12];	res[13] = m2[12]*m1[1] + m2[13]*m1[5] + m2[14]*m1[ 9] + m2[15]*m1[13];	res[14] = m2[12]*m1[2] + m2[13]*m1[6] + m2[14]*m1[10] + m2[15]*m1[14];	res[15] = m2[12]*m1[3] + m2[13]*m1[7] + m2[14]*m1[11] + m2[15]*m1[15];	mr.copy(res);	return mr;}//---------------------------------------------------------------------Transform Transform::inverse(){	Transform trans(*this);	register float 	r00, r01, r02,			r10, r11, r12,			r20, r21, r22;	r00 = trans[0];	r01 = trans[1];	r02 = trans[2];	r10 = trans[4]; r11 = trans[5]; r12 = trans[6];	r20 = trans[8]; r21 = trans[9]; r22 = trans[10];	// partially compute the inverse of the rotation matrix	trans[0] = r11*r22 - r12*r21;	trans[1] = r02*r21 - r01*r22;	trans[2] = r01*r12 - r02*r11;	// compute the determinant of the rotation matrix	register float oneOverDet = 1.0f / (r00*trans[0] + r10*trans[1] + r20*trans[2]);	r00 *= oneOverDet;	r10 *= oneOverDet;	r20 *= oneOverDet;	trans[ 0]*= oneOverDet;	trans[ 1]*= oneOverDet;	trans[ 2]*= oneOverDet;	trans[ 3] = 0.0f;	trans[ 4] = r12*r20 - r10*r22;	trans[ 5] = r00*r22 - r02*r20;	trans[ 6] = r02*r10 - r00*r12;	trans[ 7] = 0.0f;	trans[ 8] = r10*r21 - r11*r20;	trans[ 9] = r01*r20 - r00*r21;	trans[10] = r00*r11 - r01*r10;	trans[11] = 0.0f;	trans[15] = 1.0f;	// compute the inverse of the translation part of the matrix	register float tx, ty, tz;	tx = trans[12];	ty = trans[13];	tz = trans[14];	trans[12] = -(tx*trans[0] + ty*trans[4] + tz*trans[ 8]);	trans[13] = -(tx*trans[1] + ty*trans[5] + tz*trans[ 9]);	trans[14] = -(tx*trans[2] + ty*trans[6] + tz*trans[10]);	return trans;}//---------------------------------------------------------------------void Transform::translate(float x, float y, float z){	Transform mTran;	mTran.identity();	mTran[12] = x;	mTran[13] = y;	mTran[14] = z;	multiply(mTran);}//---------------------------------------------------------------------void Transform::rotate(float x, float y, float z){	Transform rot, res;	res.identity();	rot.identity();	rot[ 5] = angle_cos(x);	rot[ 6] = angle_sin(x);	rot[ 9] =-angle_sin(x);	rot[10] = angle_cos(x);	res.multiply(rot);	rot.identity();	rot[ 0] = angle_cos(y);	rot[ 2] =-angle_sin(y);	rot[ 8] = angle_sin(y);	rot[10] = angle_cos(y);	res.multiply(rot);	rot.identity();	rot[ 0] = angle_cos(z);	rot[ 1] = angle_sin(z);	rot[ 4] =-angle_sin(z);	rot[ 5] = angle_cos(z);	res.multiply(rot);	multiply(res);}

I only kept the methods that might be of interest, so there's nothing missing in the real source...

And how I use it with openGL is shown in my previous post.

Uhm... I guess I need to explain my problem even more, as this shouldn't be much of a problem for anyone except me on this forum =) So here comes another explanation...

What I Want?
I want to rotate my camera's coordinate space so that I then can translate it by it's local z-axis only and by that way make the camera move forward relative to it's own coordinate space, but to somewhere else relative to the world coordinate space. For example:
camera.matrix.rotate(0.0, 90.0, 0.0); // rotate the camera's space by 90degrees so that it's z-axis where it's x-axis used to be, and it x-axis iswhere it's z-axis used to be.camera.matrix.translate(0.0, 0.0, 10.0); // translate the camera by 10 units on it's z-axis, which is where it's x-axis used to be since I rotated thecoordinate space of the camera. So relative to the world coordinate space it will move along the world's x-axis.


How Am I Currently Trying To Do It?
I have this camera class which contains a 4x4 matrix, and that is the only data structure it contains. It looks like this in source:
class Transformable{public:  Matrix44 matrix;};class Camera: public Transformable{};class SomeModelOrWhatever: public Transformable{};

So as you can see it doesn't contain alot of other members that keep track of rotation, angles and positions as all camera tutorials I've found around the net. Instead I want my matrix to do that job.
So in my render method I do the following:
//.. render()if( GetKeyState(VK_LEFT)&0x80 ) yRot = yRot + 5;if( GetKeyState(VK_RIGHT)&0x80 ) yRot = yRot - 5;if( GetKeyState(VK_UP)&0x80 ) zPos = zPos - 1; // negative z-axis goes into screenif( GetKeyState(VK_DOWN)&0x80 ) zPos = zPos + 1;glLoadIdentity();camera.matrix.rotate(0.0f, yRot, 0.0f);camera.matrix.translate(0.0f, 0.0f, zPos);glMultMatrixf(camera.matrix); // i've tried both the inverse and normal and neither worksglPushMatrix();  glTranslatef(-1.0f, 0.0f, 0.0f);  drawWireBox(1.0f, 1.0f, 1.0f);glPopMatrix();// SwapBuffers()


I myself thinks that the problem lies in how I translate my camera or that I am multiplying the objects matrices with the camera's local matrix and not it's world matrix.
Anyways, if you look at those camera tutorials which doesn't use matrices and instead uses members with names like, position, yaw, pitch, heading, and such they look something like this:
// in render// NOTE that these are just fantasy numbers! And does probably not work. It's only for you to get the idea.float camX = cos(camera.xRotation) * speed; float camY = sin(camera.yRotation) * speed;float camZ = sin(camera.zRotation) * speed;glRotatef(camera.lookAtX, 1.0f, 0.0f, 0.0f);glRotatef(camera.lookAtY, 0.0f, 1.0f, 0.0f);glRotatef(camera.lookAtZ, 0.0f, 0.0f, 1.0f);glTranslatef(camX, camY, camZ);


And as you can see they translate the camera by exact coordinates while I rely on local coordinates, ehh... i think... As my camera works like so; it first rotates it's coordinate space and then translates by a single axis.
camera.matrix.rotate(0.0f, rotY, 0.0f); // rotate camera's coordinate spacecamera.matrix.translate(0.0f, 0.0f, posZ); // translate camera's position along it's z-axis
´
And in the above example, that shows how most camera tutorials handle their cameras, they rotate the camera's coordinate space, and then translates it by it's world coordinates, i think...



So from my own conclusion, I guess the question is; how can I extract my camera's world coordinates from it's matrix?

[Edited by - angry on June 13, 2005 4:58:57 AM]

This topic is closed to new replies.

Advertisement