matrix camera theory

Started by
3 comments, last by Dmytry 19 years, 6 months ago
I'm working on a matrix-based camera. I'm new to this type of (non-OGL-based) camera - is my code right? I'm using mtxlib (from GPG1) for linear algebra operations. Also, I'm wondering how I can input this camera state to OGL - is there a better way than calculatiog the vectors for gluLookAt()?

bool Camera::init()
{
    localToWorld=IdentityMatrix44(); //world origin, no rotation
	forward  =  vector3(0,0,1);
	right    =  vector3(1,0,0);
	up       =  vector3(0,1,0);
    return true;
}
bool Camera::tick()
{
    localToWorld= rotation * translation * localToWorld;
    forward=vector3(localToWorld[0][2],localToWorld[1][2],localToWorld[2][2]);
    up     =vector3(localToWorld[0][1],localToWorld[1][1],localToWorld[2][1]);
    right  =vector3(localToWorld[0][0],localToWorld[1][0],localToWorld[2][0]);

    rotation=IdentityMatrix44();
    translation=IdentityMatrix44();
    return true;
}
Camera::~Camera() {}

void Camera::move(vector3 d) //d=displacement
{ translation=translation*TranslateMatrix44(d.x, d.y, d.z); }

void Camera::pitch(float rad)
{ rotation = rotation * RotateRadMatrix44('x', rad); }

void Camera::yaw(float rad)
{ rotation = rotation * RotateRadMatrix44('y', rad); }

void Camera::roll(float rad)
{ rotation = rotation * RotateRadMatrix44('z', rad); }



edit: updated the code to current condition [Edited by - thedustbustr on October 14, 2004 1:06:50 AM]
Advertisement
Some comments:

1) What are you doing with the localToWorld variable? It seems to just be the identity matrix for all time

2) If the translation variable is a vector, there is no need to multiply by a translation matrix. Just do this, which is cheaper:

translation = translation + d;

3) You're defining pitch to be rotation about x, yaw as rotation about y, roll as rotation about z. The axes about which these things are defined are not universal---there are other interpretations. But, your choices are okay. See docs on rotations at Magic Software for a comprehensive discussion.

4) You can load your matrix directly into OpenGL using glLoadMatrix, with matrix mode set to GL_MODELVIEW. This takes an array of 16 floats that contains the values in your 4x4 transformation matrix. You've listed translation and rotation separately in your code. I'm assuming translation is a vector3 and rotation is a matrix3x3 (sorry, not familiar with mtxlib object names). If my assumption is true, you'd have to stuff translation and rotation into a single float[4][4] array. The way you place the values in the array is is important. See the OpenGL Red Book chapter 3 for details:

OpenGL Red Book version 1

About 25% into the chapter you'll see a definition for transformation matrix M. The entries m1 through m16 correspond to the entries in your float[4][4] array. The book describes the mapping. The rotation part goes in the upper-left 3x3 part of M. The translation vector goes in the first 3 rows of the last column. You may need to transpose rotation before stuffing it into the upper-left 3x3 corner, but otherwise you just stuff it as is.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Also, you need to re-orthonormalize upperleft 3x3 part of your matrix time to time. (precision issue)

Can be done by, say,
Column1=normalized(Column2 cross Column3);
Column2=normalized(Column3 cross Column1);
Column3=normalized(Column3);
where Column1, Column2, Column3 it's 3d vectors corresponding to columns in upperleft 3x3 matrix.

where normalized(A)=A/|A| where |A| is length of A
It's assuming convention that x^ = y^ cross z^ where ^ mean unit-length vector....
update: all problems solved.

Ok I have the assert problem solved (minor precision issue). I also found a much better way to find the vectors (from GPG1) - see updated Camera::tick method. I'm still having issues with movement: after some rotation the forward vector and right vector are effectively switched. Why is this happening?

Dmytry, what time scale are we talking here- do I need to do this every frame?

Thanks. Dustin

edit:several additions to source and comments and more questions
edit2: updated source code in initial post, removed things i figured out
edit3:I have a demo put together with the relevant source but my host is down, i'll put it up tomorrow if someone is willing to look at it
edit4: figured it all out. thanks guys for the help :)

[Edited by - thedustbustr on October 14, 2004 10:25:49 AM]
Quote:
Dmytry, what time scale are we talking here- do I need to do this every frame?

Don't really know. Depends.

In fact you don't really need to do it at every frame(maybe, even every 100th frame will do, maybe even 1000), but it's not THAT slow and i would do it at every frame if camera has been modified, for simplicity and to be sure. Why it's should be done only if camera was modified : otherwise camera *might* very slowly drift due to inprecision caused by re-orthonormalization itself...

If your camera class is made using get/set , you can make a counter that is decremented by each "set" and when it's <0 , matrix is re-orthonormalized and counter is set to, say, 100 .

I just use quaternions for camera. It's simpler once you have quaternion class. Quaternions can be multiplied in exactly same way as rotation matrices, and easily converted to rotation matrix when needed. So once you have quaternion class/struct, it's almost the same. Both quaternion and matrices is a transforms.

In fact, auto-orthonormalizing matrix works exactly as quaternion except that it is more complicated than quaternion.

This topic is closed to new replies.

Advertisement