I've been learning opengl for 1.5 weeks now and i just finished a simple 3d-world in which i can move in any direction. it's similar to NeHe's lesson10 program, i just added strafing, mouse look support and moving/rotating objects.

There are a few things i don't understand when it comes to moving in the world. The first thing is moving forward/backward:

In NeHe's lesson10, if you move forward/backward, you don't only move on the z axis, but on the x axis (because you have to take in count the direction in which you're heading) )as well.
If you move forward, the new x and z positions are calculated as following:
xpos -= (float)sin(heading*piover180) * 0.05f;
zpos -= (float)cos(heading*piover180) * 0.05f;

heading is the direction in which you're facing. heading*piover180 converts degrees to radians.
but now....why is xpos the SIN of the angle and zpos the COS?
doesn't that trigonometric stuff say, that for a given point on a circle, the x-coordinate for that point is the COS value of the angle and y-coordinate is the SIN?
so why is x here the SIN and not the COS?

Now i tried around to get a strafing effect. i found the following formula to work:
camera.position[0] += (float) cos(DEG2RAD(-camera.direction[1])) * vel_x;
camera.position[2] += (float) sin(DEG2RAD(-camera.direction[1])) * vel_x;

vel_x is negative when you strafe left and pos. when you strafe right.

I just wanted to know if this formula is THE correct one. i haven't found any bugs with this formula yet, but maybe it's not THE correct way to do strafing.
If this is the right formula, could somebody explain it to me why this is like this? i don't really get that geometric stuff.

The next thing is that the Scene is rotated by 360.0f - yrot to rotate the scene on the y axis to look into the correct direction.
Why 360.0f - yrot? Can't you just as well rotate by -yrot instead of 360.0f - yrot. in my program i rotate by -yrot and it works just fine.

Now i'd also like to know which is the best way to implement a camera.
Is it better to do it like in NeHe's lesson 10, or should you do it via gluLookAt and vectors for the direction etc.?
Posted on 2002-03-15 05:13:11 by darester
oh, i forgot to ask how you can move in the 3d-world not only on the xz-plane, but on all planes.
i mean not just walk on the ground, but "fly around". for example if i look up into the sky, then if you push VK_UP, you should move towards the sky instead of moving forward on the ground.
Posted on 2002-03-15 05:57:18 by darester
darester, I don't know the answer to your problem, but I could solve it with the equation for a line in 3D. If you know your position (X,Y,Z) and the line which your moving on F(x,y,z).

I think in 3D games it's done in an easier way: every object has a local coordinate system. So, moving forward is just adding to one dimension. When the transformation is done from the local to global coordinate system, the 3D move will be in any direction (speaking globally).

If you want to do it manually (without the local-global transformation) then solve the 3D line for your object and the direction your moving.
Posted on 2002-03-15 10:32:55 by bitRAKE

There is actually a completely different method, it involves matrices. It gets a bit complicated but basically you have a 4x4 matrix for the player. Set it initially to the identity

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

You multiply the modelview matrix by this before drawing the world, in this way the world moves around the character, rather than the character moving through the world.

To move or rotate the player you multiply his matrix by various transformation matrices. For example movement is done by the matrix:

1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1

You post-multiply the player matrix i.e. you multiply the rows of the player matrix into the columns of the transformation matrix. The advantage of this is that it all happen relative to the player. For example if your world were set up such that the z axis represented the initial direction the player faced then post-multiplying by the matrix

1 0 0 0
0 1 0 0
0 0 1 1
0 0 0 1

would always move the player forward in the direction s/he is facing regardless of which direction that actually is.

I don?t know if this is the best method for a game where you only allow movement ?on the ground?, but for fully 3d games such as aeroplanes or spaceships then it is by far the best.

Unfortunately this is very hard to explain, and it would take a lot more that I have here, but if you wish to pursue this method then I?ll help you as much as I can.

Good Luck
Posted on 2002-03-15 12:21:24 by Eóin
Hi !

The question of rotation: to do "-yrotate" or to do "360 - yrotate"

Seems that someone fears negativ numbers ? (a relict from the 18. century ???)

What will you do if the plane you move on isn't on the xy-plane ?

A correct way would be to get the triangle you stay above and calculate the two vectors defining the triangle's plane and the normal one (if it isn't already present in the vertex-buffer). Than you should rotate the figures moving-base (the plane on which the figure's walking is done) to be parallel to the triangle-plane and rotate it around the triangle's normal by the direction's angle the figure wants to move.

This seems to be a lot of calculations. Perhabs it's easier to precalculate paths the figure may walk along ...
Posted on 2002-03-15 16:44:37 by Caleb
Afternoon, darester.

The idea of rotating the world about the character works well if there aren't many "world" objects to update. If there are many individual static (i.e. not moving) objects, then it'd still be better to leave the "world" objects in place, and move the character and view (camera) -> less calculations needed.:grin:

I use the 4x4 matrice approach. Strange - the matrices I use are a little different to the ones E?in posted (is this a difference between OGL and D3D? maybe I should stay out of an OGL thread:grin: ).

This is the type I use:
1 0 0 0
0 1 0 0
0 0 1 0
x y z 1

x,y,z are for the position. The columns (except for the bottom row) represent the X, Y and Z axis rotations. The last column *always* has 0,0,0,1 in it.

If you wish to move and rotate in a fully 3D environment, then you're probably going to have to drop the rotation method you're currently using. If more than two matrices are calculated together, and you're rotating on the X,Y, and Z axis, then you'll lose "gimball lock". That means that there will be incremental errors in the calculations, and the objects/character won't be rotated correctly. To fix that, you need to shift to using a "right vector", "up vector", and "lookat vector" method of calculating direction and movement.

As E?in said, the info and code describing this would take up quite a bit of space.
i.e. here's a little code snippet on updating an objects' vectors, which also keeps the object in "gimball lock".

; update the opponent...
INVOKE D3DXMatrixIdentity, ADDR matspacebuggyRed

INVOKE D3DXVec3Normalize, ADDR Redsb_lookat_vector,ADDR Redsb_lookat_vector
INVOKE D3DXVec3Cross, ADDR Redsb_right_vector,ADDR Redsb_up_vector,ADDR Redsb_lookat_vector
INVOKE D3DXVec3Normalize, ADDR Redsb_right_vector,ADDR Redsb_right_vector
INVOKE D3DXVec3Cross, ADDR Redsb_up_vector, ADDR Redsb_lookat_vector, ADDR Redsb_right_vector
INVOKE D3DXVec3Normalize, ADDR Redsb_up_vector, ADDR Redsb_up_vector

INVOKE D3DXMatrixRotationAxis, addr Redbuggyrollmatrix, addr Redsb_lookat_vector, RedRoll
INVOKE D3DXVec3TransformCoord, addr Redsb_right_vector , addr Redsb_right_vector, addr Redbuggyrollmatrix
INVOKE D3DXVec3TransformCoord, addr Redsb_up_vector, addr Redsb_up_vector, addr Redbuggyrollmatrix

INVOKE D3DXMatrixRotationAxis, addr Redbuggyyawmatrix, addr Redsb_up_vector, RedYaw
INVOKE D3DXVec3TransformCoord, addr Redsb_lookat_vector , addr Redsb_lookat_vector, addr Redbuggyyawmatrix
INVOKE D3DXVec3TransformCoord, addr Redsb_right_vector, addr Redsb_right_vector, addr Redbuggyyawmatrix

INVOKE D3DXMatrixRotationAxis, addr Redbuggypitchmatrix, addr Redsb_right_vector, RedPitch
INVOKE D3DXVec3TransformCoord, addr Redsb_lookat_vector , addr Redsb_lookat_vector, addr Redbuggypitchmatrix
INVOKE D3DXVec3TransformCoord, addr Redsb_up_vector, addr Redsb_up_vector, addr Redbuggypitchmatrix

It may look a bit messy, however - once the code is in place - you can very easily move/rotate in *any* direction.

I'll leave any explanations for another post, just incase nobody is interested in it.

Posted on 2002-03-15 17:17:03 by Scronty
Hi Scronty, the difference in the matrics isn't a big deal. The example I show is the official maths format, however depending on how you multiply the version you showed can do the exact same thing.

AFAIK the way D3D linearly stores that matrix in memory is;
1 0 0 x 0 1 0 y 0 0 1 z 0 0 0 1
Whereas OGL is
1 0 0 0 0 1 0 0 0 0 1 0 x y z 1

However the idea of moving the objects instead of the player can be the most efficient, but it needs to be done right. The camera never moves in 3d stuff, everything moves around it. In OGL this happens when things are multiplied by the modelview matrix which happens when something is rendered. I'm sure D3D is somewhat similar.

But again this is a complicated topic. I'll knock up some code if it would be of help, let me know if you want it darester :alright:
Posted on 2002-03-15 18:26:03 by Eóin
Wow, thanks for all those replies so far.
First of all, i'd like to say, that i managed to make my camera move in a fully 3d environment.
My method is moving the world around the camera not the camera in the world.
What i actually do is storing the camera position/orientation and then rotating/moving the world the other way round. For example if i move forward, i move the world backward, which gives the illusion, that the camera moved forward.
So my method is actually like E?in's, only in another way, right?
But which way is better, mine or E?in's? Since E?in is more experienced, his method is probably better, right?

E?in said that moving the world around the camera is faster.
That's what NeHe's lesson10 also says.
Scronty said that is depends on the number of static objects in the scene.
He also said that when moving in a fully 3d environment, i should do the gluLookAt thing (right vector, up vector, lookat vector).

So which method is now better in general? moving the world or the camera?
And what does that gluLookAt thing belong to? moving the world or the camera?
i should only use the gluLookAt thing when moving in a fully 3d environment, right? if i only use on xz-Plane, i should just move the camera/world (either one which is faster, which i don't know yet), right?
is this THE way to do it?

Yes E?in, i could really need your code, i think it could help me a lot. i'd really appreciate it.
Posted on 2002-03-16 03:32:34 by darester
i've just been searching the q2 source for its "camera positioning". in the whole source, i couldn't find a single call to glMultMatrix and not a single call to gluLookAt.
I've just found the following:

qglRotatef (-90, 1, 0, 0); // put Z going up
qglRotatef (90, 0, 0, 1); // put Z going up
qglRotatef (-r_newrefdef.viewangles[2], 1, 0, 0);
qglRotatef (-r_newrefdef.viewangles[0], 0, 1, 0);
qglRotatef (-r_newrefdef.viewangles[1], 0, 0, 1);
qglTranslatef (-r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1], -r_newrefdef.vieworg[2]);

This seems to be the camera positioning code. it at least looks like it, right?
So q2 seems to position the camera just like NeHe's lesson 10 (and i also did it like this, since i only knew this method).
Does this mean, that for games like q2, it's best to do it like this?

BTW: why do they do these 2 rotations at the beginning:
qglRotatef (-90, 1, 0, 0); // put Z going up
qglRotatef (90, 0, 0, 1); // put Z going up
what is that good for?
Posted on 2002-03-16 06:39:22 by darester