PDA

View Full Version : ? View Matrix: 1st person to 3rd person ?

Z-Knight
07-22-2008, 10:19 AM
I am writing a fly-through code to move through a scene in first person view but I also want to be able to stop and look at a desired point/object and then rotate around it and also be able to zoom and pan the view.

So, I started with the following code for First Person Shooter:
http://www.codesampler.com/oglsrc/oglsrc_5.htm#ogl_fps_controls

The code works great and I got the First Person view to work but I'm having trouble switching to the third person because I don't understand how to alter the view matrix.

The code uses the following view matrix:

| rx ry rz -(r.e) |
| ux uy uz -(u.e) |
| -lx -ly -lz (l.e) |
| 0 0 0 1 |

Where r = Right vector
u = Up vector
l = Look vector
e = Eye position in world space
. = Dot-product operation

The method to update the view looks like this (note this is in JOGL, but it is the basically the same as OpenGL).

private void updateView() {
// Normalize the look vector. setLook() method does this already but
// we can't assume that the reference wasn't changed so this is likely
// precautionary and redundant....but can't take chances.
// Make sure the look vector has some length
if (Math.abs(look.length()) < 1.0e-6){
throw new RuntimeException("Look vector cannot have zero length.");
}
look.normalize();

// Cross product of the 'look' and 'up' vectors gets the 'right' vector.
Vector3d.cross(right, look, up);

// Make sure the right vector has some length
if (Math.abs(right.length()) < 1.0e-6){
throw new RuntimeException("Right vector cannot have zero length.");
}
right.normalize();

// Cross product of the 'right' and 'look' vectors gets the 'up' vector.
Vector3d.cross(up, right, look);

// Make sure the up vector has some length
if (Math.abs(up.length()) < 1.0e-6){
throw new RuntimeException("Up vector cannot have zero length.");
}
up.normalize();

// Place the results into a matrix format for use with
// the OpenGL call to glMultMatrixd().

view[0] = right.x;
view[1] = up.x;
view[2] = -look.x;
view[3] = 0.0;

view[4] = right.y;
view[5] = up.y;
view[6] = -look.y;
view[7] = 0.0;

view[8] = right.z;
view[9] = up.z;
view[10] = -look.z;
view[11] = 0.0;

view[12] = -Vector3d.dot(right, eye);
view[13] = -Vector3d.dot(up, eye);
view[14] = Vector3d.dot(look, eye);
view[15] = 1.0;
}

So this piece of code lets me fly through and in this code the 'eye' point gets moved through the scene and everything else (look vector, up vector, right vector) gets adjusted accordingly.

So, now my problem...in order to now change to 3rd person mode where I focus on a particular point and rotate around it is what I can't figure out. Actually, let me say that if I change the position portion of the view matrix to the following code then I am now rotating my view around the 0,0,0 point but my 'eye' point never moves and so I can no longer do zooming and panning as before (where I would simply move the eye point to do the zoom/pan).

view[12] = -eye.x;
view[13] = -eye.y;
view[14] = -eye.z;
view[15] = 1.0;

Basically I want to figure out how I can add zoom/panning to my code for the 3rd person view...I realize this is kind of complicated concept so I'm not expecting much help, but if by chance someone has done this I would appreciate any info.

dletozeun
07-22-2008, 11:47 AM
If your eye is spinning around the (0,0,0) point that means that your eye is moving, isn't it?

Then to do panning movement you translate the eye position 'eye' along r and u vectors, so I don't understand why this does not affect the view.
How do you compute camera zooming/panning? In my case, I just move the eye position then the matrix you set just take care of moving from world space to camera space (4th column) and view orientation (the rest of the matrix that computes some rotations).
I just say this to show that this matrix as nothing to do with camera panning/zooming not to try to learn you something you may already know.

Z-Knight
07-22-2008, 11:57 AM
If your eye is spinning around the (0,0,0) point that means that your eye is moving, isn't it?

Then to do panning movement you translate the eye position 'eye' along r and u vectors, so I don't understand why this does not affect the view.
How do you compute camera zooming/panning? In my case, I just move the eye position then the matrix you set just take care of moving from world space to camera space (4th column) and view orientation (the rest of the matrix that computes some rotations).
I just say this to show that this matrix as nothing to do with camera panning/zooming not to try to learn you something you may already know.

My code outputs what the eye coordinates are and I've drawn a little sphere at those coordinates and NO, by changing the position vector (last line of the matrix) in the view matrix the eye doesn't seem to be moving at all. My look, up and right vector all seem to update correctly but my eye remains the same....I'll make an example and post it to show. And unfortunately all my panning and zooming are tied to changing the 'eye' coordinates but with that little matrix change that I "hacked" I don't know how to relate the changes to the rest of my code...also I'm probably not explaining it well in these posts.

dletozeun
07-22-2008, 12:26 PM
If you change the camera position this should at least affects the view (not necessary in a good way) since you change the 'eye' vector which is used in your matrix.

Then you need to update camera position when rotation around the target. You should keep the rotation part of your matrix in matrix that we may call 'orientationMat'. then compute the new camera position like this:

eye = transpose(orientationMat) * (eye - target) + target;

you need the matrix transpose because with only rotations this is also the matrix inverse since camera transformation is the inverse of the scene one.

EDIT:

And you need to move the target and the eye when doing panning movement.

Z-Knight
07-22-2008, 01:01 PM
Here's the link to my example code:
TestFPS_Camera.jnlp (http://www.zaczek.com/jogl/TestFPS_Camera.jnlp)

It is JOGL code but the same as OpenGL.

Pressing 'O' (letter o) switches between modes....by default it starts in the 3rd person view mode.

Press Mouse LEFT button to rotate the camera...note the blue sphere attached by the blue line...that represents the EYE point.

With the LEFT mouse button down to rotate the view, you can use the UP/DOWN/LEFT/RIGHT keys to fly through the scene when in the 1st person view....you'll see the eye point coordinates changing when you do this fly through.

In the 3rd person view the eye changes as well when you use the UP/DOWN/LEFT/RIGHT keys but it doesn't change as I would expect.

Ok, now to read the post above...I think you are correct that I need to update the eye with the matrix multiplication you provided because as a test before, I took the view matrix and multiplied it with the 'eye' point and I had that output to the screen and the coordinates that it was displaying equaled where in the scene my "new" eye point was...so I think you might be on to something there.

As for moving the target and eye, I don't actually have a target...I have a look direction but I understand what you are saying.

dletozeun
07-22-2008, 01:32 PM
It is a shame, your application don't work for me...I mean, the program launches correctly but I only see a gray window even if I try to move the camera. I have never had the opportunity to launch a JOGL application, maybe I forgot something.

I talked about a target because you said:

I focus on a particular point and rotate around it

The target is in my opinion this particular point you are looking at rotating around.

by moving "the target and the eye" I meant that in order to keep the same view vector, you have to translate both, eye and target. Without moving the target your eye will move looking always at the same point.

I hope I understand what I mean. Don't hesitate to ask more questions

ZbuffeR
07-22-2008, 02:00 PM
dletozeun, try to install Java 1.6 for your OS.
It works great here (but I can't help with the questions...)

Z-Knight
07-22-2008, 02:10 PM
It is a shame, your application don't work for me...I mean, the program launches correctly but I only see a gray window even if I try to move the camera. I have never had the opportunity to launch a JOGL application, maybe I forgot something.

hmm...weird. It might be the video card or the display settings...if you are in Windows try changing you screen resolution (sometimes that affects the view) or go into Properties, the advanced button in the Settings tab and enable or disable the hardware acceleration in the "troubleshoot" tab. Other than that I can't understand why it would gray out on your display...there is nothing specific that you have to do for JOGL per se unless you are developing in it...I thought the java webstart would automatically setup JOGL for the temporary session, unless I did something wrong.

Thank you for your help thus far, it got me thinking more and you made a lot of good points so now I need to pursue them...thanks.

Z-Knight
07-22-2008, 02:11 PM
dletozeun, try to install Java 1.6 for your OS.
It works great here (but I can't help with the questions...)

ahh..thanks for finding the issue.

btw, if anyone wants this code I can post it...yes, you can download the FPS code provided in my first post but I modified the code a little to allow for flying in any direction and rotating around the look vector - the original code assumed the standard FPS control/view where the up vector is along the global Y (if i recall) axis and that remains fixed, so you can't actually fly upside down.

dletozeun
07-22-2008, 02:42 PM
sorry but it does not seem to solve the problem java 1.6 is already installed. My OS is Ubuntu.
I launched the program in command line and got these exceptions:

\$>java TestFPS_Camera.jnlp

Exception in thread "main" java.lang.NoClassDefFoundError: TestFPS_Camera/jnlp
Caused by: java.lang.ClassNotFoundException: TestFPS_Camera.jnlp
at java.security.AccessController.doPrivileged(Native Method)

But this way no window is opened.

EDIT

Something must be wrong with your application, I have tried the gears demo here (https://jogl-demos.dev.java.net/)
and it works. But other applications like HDR demo don't work...

Z-Knight
07-22-2008, 02:52 PM
hmm...The Gears demo work but mine doesn't...interesting. I've checked the differences in my JNLP file with the Gears one and it seems to be very close...at least the important things appear the same.

In general, I don't believe you can just type: \$>java TestFPS_Camera.jnlp

You would then need to update your CLASSPATH and LD_LIBRARY_PATH to reflect the location of JOGL....editting the .bashrc file

JOGL=\$HOME/<PATH_TO_JOGL_FOLDER>/lib
export CLASSPATH=\$CLASSPATH:\$JOGL/jogl.jar:\$JOGL/gluegen-rt.jar
export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$JOGL

Then you would need to download the JAR file for the code...the JNLP file is the Java web start that takes care of setting things up for you for that session.

In my case the JAR file is located here: http://www.zaczek.com/jogl/TestFPS_Camera.jar

Also, to run that code you would then type

java -classpath .:\$CLASSPATH:TestFPS_Camera.jar TestFPS (my Main is called TestFPS and not TestFPS_Camera)

Z-Knight
07-23-2008, 01:45 PM
whew...I figured the darn thing out. It works now.

You can try it here if you want: TestFPS_Camera.jnlp (http://www.zaczek.com/jogl/TestFPS_Camera.jnlp)

Press the
'O' key to switch modes

mouse left mouse button down to rotate the view
right button down to pan
middle button down to zoom

up/down/left/right key to move through the scene.

Basically the fix has to do with the view matrix and what gets changed in 1st person vs 3rd person view.

The view matrix has this structure:

| rx ry rz -(r.e) |
| ux uy uz -(u.e) |
| -lx -ly -lz (l.e) |
| 0 0 0 1 |
Where r = Right vector
u = Up vector
l = Look vector
e = Eye position in world space
. = Dot-product operation

The 4th column, that includes the dot products, represents the "Position Vector" of the view. In 1st person mode the dot product is what should be there...the camera moves through the scene correctly.

Ok, now the problem I had was that I was applying the same code for panning/zooming in the 1st person mode to the 3rd person mode - but that wasn't working. In the 1st person mode the pan and zoom were accomplished by changing the location of the EYE position in the scene...makes sense. In 3rd person mode it does not work that same way - the fix was not to let the code calculate 4th column position vector based on the EYE coordinates but rather simply use the previous view matrix 4th column and directly add or subtract the pan movement from those components....so my view matrix effectively was this:

| rx ry rz (previousX +/- PanLeftRight) |
| ux uy uz (previousY +/- PanUpDown) |
| -lx -ly -lz (previousZ +/- ZoomInOut) |
| 0 0 0 1 |

And with this change the rotations are now about the 0,0,0 point and you are effectively 'orbiting' around the 0,0,0 point.

Basically I'm adjusting the view matrix "position" column directly based on the how much I move the mouse in the 2D screen coordinates instead of calculating the view matrix "position" column based on the look/up/right vector and the dot product with the eye position.

I hope that makes sense...check out the demo to see it work...if anyone wants the JOGL code I can post it (easy to convert to OpenGL) and if not, then you can always decompile (JAD) my class files. :)

dletozeun
07-24-2008, 12:27 AM
Yes that makes sense, but are you satisfied to always turn around the (0,0,0) point?
How do you transform the eye coordinates in third person mode?

I will look at your application this evening.

Z-Knight
07-24-2008, 09:10 AM
yes, I need to improve it to allow rotation about a different point other than 0,0,0 but for now in my scene I translate all of the objects in focus to 0,0,0. So I'm fine, for now, but you are correct that just rotating around 0,0,0 point would be useless for a fly through where you would be flying to different objects in the scene and would want to rotate around them...I don't have that figured out yet.

in 3rd person mode I don't actually transform the EYE coordinates...I simply adjust the position column of the view matrix...components view[12], view[13], view[14]

dletozeun
07-24-2008, 11:05 AM
fair enough.

But I still get errors when running your program. I have downloaded gluegen and jogl jar files from, export all pathes and i have errors but not the same as the ones from the 1st time:

java -classpath .:\$CLASSPATH:TestFPS_Camera.jar TestFPS
Exception in thread "main" java.lang.NoClassDefFoundError: javax/media/opengl/GLJPanel
Caused by: java.lang.ClassNotFoundException: javax.media.opengl.GLJPanel
at java.security.AccessController.doPrivileged(Native Method)

Zengar
07-24-2008, 11:09 AM
Is there no Java Webstart for Linux? Works fine on MacOS here...

Z-Knight
07-24-2008, 11:15 AM
if you simply exported the class path in your bashrc file and didn't source it then you don't have the classpath set...the exception you are getting says that it can't see the JOGL jar files...ie they must not actually be in your classpath.

Do echo \$CLASSPATH and make sure you are pointing to the jogl.jar and gluegen-rt.jar files. Or it could be that the LD_LIBRARY_PATH variable is not pointing to the directory containing the .so libraries for JOGL that you downloaded.

At least I believe that to be true, though I do all my current development on Windows.

ZbuffeR
07-24-2008, 12:14 PM
Your Java Webstart works fine too on oldish Ubuntu linux 6.10, with Sun Java 1.6.0, and I did not have to fiddle with classpath nor manually download jogl libs.

dletozeun
07-24-2008, 12:37 PM
Yes, my fault, I was too tired to see a syntax error... but I did not forget to reload the bashrc.

Now I have some exceptions saying that it did not succeed to make the context current. Maybe a driver error, I work on Ubuntu 8.04 with an ATI radeon mobility X1600 graphic card (with ATI catalyst 8.6 driver).

Z-Knight
07-24-2008, 01:46 PM
Yes, my fault, I was too tired to see a syntax error... but I did not forget to reload the bashrc.

Now I have some exceptions saying that it did not succeed to make the context current. Maybe a driver error, I work on Ubuntu 8.04 with an ATI radeon mobility X1600 graphic card (with ATI catalyst 8.6 driver).

that one I can't help on...not sure why the context error would come up...but you could be correct that the drivers are at issue. sorry.

ZbuffeR
07-24-2008, 02:48 PM
For sake of completeness, my linux system use Nvidia proprietary driver (87.76) for a Geforce 6800.

Z-Knight
10-02-2008, 08:35 AM
For my completeness sake, I would like to provide the JOGL (Java) source code...I can't believe I didn't attach it before...

since I can't actually attach files to posts, I'll have to direct you to this site to get the files:
TestFPS_Camera.zip (http://www.zaczek.com/jogl/TestFPS_Camera/TestFPS_Camera.zip)

Z-Knight
10-23-2008, 09:56 AM
Here is the link to the JOGL runtime demo again...can't edit my last post so had to create this new one:

Demo FPS (http://www.zaczek.com/jogl/TestFPS_Camera.jnlp)

Left mouse down to rotate view
middle mouse button to zoom
right mouse button to pan
up/down/left/right arrows to move into/around the scene

Basically the controls are much like you see in the fly through of most first person shooter games.

'O' key switches from "Standard mode" to "Orbiting Mode"
Standard mode is like a FPS mode. Orbiting mode you will orbit the object in the center.

Z-Knight
01-12-2009, 09:38 AM
Slight correction to the matRotate() method in the Camera.java class. Zip file link above has been updated and here is the correction

private double[] matRotate( double mat[], double angle, Vector3d axis ) {
double s = Math.sin(angle * Math.PI / 180.0);
double c = Math.cos(angle * Math.PI / 180.0);

axis.normalize();

// ERROR: mat[0] = c + (1 - c) * axis.x;
mat[0] = c + (1 - c) * Math.pow(axis.x, 2);
mat[1] = (1 - c) * axis.x * axis.y + s * axis.z;
mat[2] = (1 - c) * axis.x * axis.z - s * axis.y;
mat[3] = 0.0;

mat[4] = (1 - c) * axis.y * axis.x - s * axis.z;
mat[5] = c + (1 - c) * Math.pow(axis.y, 2);
mat[6] = (1 - c) * axis.y * axis.z + s * axis.x;
mat[7] = 0.0;

mat[8] = (1 - c) * axis.z * axis.x + s * axis.y;
// ERROR: mat[9] = (1 - c) * axis.z * axis.z - s * axis.x;
mat[9] = (1 - c) * axis.y * axis.z - s * axis.x;
mat[10] = c + (1 - c) * Math.pow(axis.z, 2);
mat[11] = 0.0;

mat[12] = 0.0;
mat[13] = 0.0;
mat[14] = 0.0;
mat[15] = 1.0;

return mat;
}