Skip to main content
GameDev.net gamedev.net
🔒 Locked

Camera Question

Started by Jason2Jason May 20, 2002 at 12:24 PM 21 replies 950+ views
Original Post
Jason2Jason
Jason2Jason
Hi, i know this has been asked many time, and I have done a search, but thought I''d understand the answers more if they related to my situation. I''ve made a camera class that works fine, even the rotating it fine how it should. But how do you make the camera move (or the scene if u want) in the direction your facing. I warn you I''m not very good with this vector stuff yet! Another thing: I saw a eg that centres the mouse pos, then get the new pos, to make a vector to go in the direction (gametutorials.com), but I''m using DX input, so thats not quite the same since it (in my program) add and subtracts to a variable. Just thought I''d say. If you need any of the code just say, but its all basic stuff at the moment. Thx, -J
Penance
Penance
if you know how many degrees you are rotated then
glTranslatef( r*cos(angle), 0.0f, r*sin(angle) );
should get you where you want to be.
angle is your rotation, r is how far you want to move.
0 degrees means the camera is facing along the x-axis.
so if you have rotated 45 degrees and want to move 10 units
you will
glTranslatef( 7.0711f, 0.0f, 7.0711f );
Jason2Jason
Jason2Jason
That didn't work at all! anyother ideas?

thx,

-J

EDIT: Heres my code for the camera (theres more, but this actully does the work):


        
glRotatef(Roll, 0.0,0.0,1.0);
glRotatef(Pitch, 1.0,0.0,0.0);
glRotatef(Heading, 0.0,1.0,0.0);
glTranslatef(Posit[0]*(float)sin(Heading), Posit[1], Posit[2]*(float)cos(Heading));



[edited by - jason2jason on May 21, 2002 2:57:01 PM]
Palidine
Palidine
yeah figure out your view vector (view coords - position coords)

view vector = (x,y,z)

you should normalize the view vector (do a google search on normalizing vectors). it's basically dividing all the terms by the lenght of the vector which is sqrt(x^2 + y^2 + z^2)

give yourself a speed at which you'd like the camera to move = s

velocity - (x * s, y * s, z * s)

add velocity to position vector

new position = (p.x + x * s, p.y + y * s, p.z + z * s)

that'll do a constant speed per frame which is bad. to be better about it you want framerate independant velocity for which you would use:

p.x = x * s * timeSinceLastLoop + p.x;

then the same for y and z coords

framerate indepentant velocity assums you have implemented some sort of timing mechanism to figure out how long it's been since the last game loop ran. you can use that number for all sorts of useful things like FPS calculations. so if you haven't implemented that you can do the frame dependant movement to get a leg up and at least be able to see your camera moving.

-me

[edited by - Palidine on May 21, 2002 3:01:38 PM]
Jason2Jason
Jason2Jason
Right.... I just got lost in all the math there!! Is there an english version of what you said. Sorry, but we''ve only just covered the basics of cos sin and tan at skool, we haven''t done all this advanced stuff yet! I''m only 15! Is there a tutorial that is clear that explains vectors AND how to uses them in practise, like with a camera?

thx,

-J
LockePick
LockePick
http://www.gametutorials.com/Tutorials/OpenGL/OpenGL_Pg1.htm

Go through all (yes, ALL) of the camera tutorials veeery slowly, and you''ll be damned glad you did. =)
Not only will it give you a fully functional camera class to work with (extremely easy to use and modify), but you''ll get a great understanding of vectors and their uses.

I''m 14, while I don''t understand every line of it (not used to using trig functions yet) it''s helped me a ton.
Palidine
Palidine
heh. sorry.

ok. so first i assume you''re using gluLookAt. which takes view, up and position coordinates, yes? or are you using a different way to position the camera?

if you are using gluLookAt, then you are storing the view up and position coods in some camera struct presumably.

a vector (in 3D space) is just 3 numbers (x,y,z) sometimes you''ll see (x,y,z,w) but ignore w for now. a vector can be just a point or it can be an arrow pointing from one point to another. if it''s an arrow then the x,y,z coords are the x,y,z coords of the tip of the arrow if the base of the arrow is at 0,0,0 (the origin). it''s a way of defining a direction in 3D space

so basically you can get an arrow type of vector form your view coords and your position coords by just subtracting the position from the view coords:

viewVector = (v.x - p.x, v.y - p.y, v.z - p.z)

see how you still get 3 numbers out of that? an (x,y,z) triplet? that basically tells you which DIRECTION you are facing.

then basically you want to give your camera a nudge in that direction. the easiest way to do that is say How many units to i want to move in that direction. that''s your speed. lets say you want the speed to be 5 units

so, you know your position (p.x, p.y, p.z). and you know your view vector (v.x - p.x, v.y - p.y, v.z - p.z). and you know your speed b/c we just defined it = 5.

so 2 steps:

1) make a velocity vector. which will also be an x,y,z number. it says move me x units on the x axis, y units on the z axis and z units on the z axis. to get that:

a. normalize your view vector. basically make the length of the bitch = 1. take each of the x,y,z coordinated and divided them by the number sqrt(x^2 + y^2 + z^2) where x,y,z in that equation are equal to each of the calculations (v.x - p.x, v.y - p.y, v.z - p.z)

b. multiply your "normalized" viewVector by your speed. to do that you multiply each term of the vector by the speed. the result will be your velocity vector. (velocity is a physics word for speed that means speed in a certain direction)


2) add your velocity vector to your current position vector. to add 2 vectors you add each of the terms seperately
Vector 1 = (1,2,3)
Vector 2 = (4,5,6)

Vector 1 + Vector 2 = (1 + 4, 2 + 5, 3 + 6)

the answer of your position plus the velocity vector is your new camera position translated speed units in the direction that you were facing.


an example:
view coords: (4,4,4)
position coords (5,5,5)
speed = 6

calculate the viewVector:
viewVector = (4-5, 4-5, 4-5) = (-1, -1, -1)

normalize the viewVector:
length of viewVector = sqrt(1^2 + 1^2 + 1^2) = sqrt(3)
viewVector = (-2/sqrt(3), -2/sqrt(3), -2/sqrt(3))

multiply viewVector times the speed:
viewVector = (6 * -2/sqrt(3), 6 * -2/sqrt(3), 6 * -2/sqrt(3))

add your position to the velocity:
newPosition = (5 + 6 * -2/sqrt(3), 5 + 6 * -2/sqrt(3), 5 + 6 * -2/sqrt(3))

make your camera position = newPosition.

you are done.

if you''re using gluLookAt you''ll have to move your view coords the same way. to do that, when you get to the add your position to the velocity make another calculation to add the velocity to your view coords to get the new view coods.

-me
Jason2Jason
Jason2Jason
Correct me if I''m wrong, but isn''t a vector defined as 2 sets of £D coord, one is a point, the other indicates a direction. I''m not using glulookat() function. I''m currently making a vector class which I''ve just started because if all this. Would u recomend any other functions to put in it, or just the stuff u said just now?

thx,

-J
Palidine
Palidine
well, not entirely sure of technical definitions, but if you''re using a 4 member vector the w parameter indicates if it''s a point or a direction. w = 0 for one 1 for the other (i always forget which).

.normalize() is a good function (dividing by the vector length).

i''d look up "3d math tutorial" on google for some basic 3D math stuff. and as LockePick posted above take ALL those camera tuts. it''ll give you a much better practical understanding of what''s going on and how to implement it.

also search around in articles & resources section of this site for more math tuts you can take.

-me
Jason2Jason
Jason2Jason
thx. those camera tutorial are wot got me into this mess! I would of used them if the input system wasn''t different. I''ll go look for some £D math stuff, and come back with more problems l8r!

-J
uNiQue0815
uNiQue0815
well... you SHOULD use gluLookAt... !!

first of all you should see your camera as an object, floating around in your 3d-space. you can do this by giving it :

1) position
2) ''direction''

these two can all be put in one matrix, and everything will be really easy...

a matrix in opengl is an array of 16 floats/doubles
for better understanding i also created a class ''nxMatrix'' :


class nxMatrix
{
public:
GLfloat X[4];
GLfloat Y[4];
GLfloat Z[4];
GLfloat P[4];
};

at the beginning it should be initialized with :

X[0] = 1.0f; X[1] = 0.0f; X[2] = 0.0f; X[3] = 0.0f;
Y[0] = 0.0f; Y[1] = 1.0f; Y[2] = 0.0f; Y[3] = 0.0f;
Z[0] = 0.0f; Z[1] = 0.0f; Z[2] = 1.0f; Z[3] = 0.0f;
P[0] = 0.0f; P[1] = 0.0f; P[2] = 0.0f; P[3] = 1.0f;
this is the identity of a 4x4 matrix.

when you use these values for your gluLookAt()

[
gluLookAt (
Matrix->P[0], Matrix->P[1], Matrix->P[2],
Matrix->P[0]-Matrix->Z[0], Matrix->P[1]-Matrix->Z[1], Matrix->P[2]-Matrix->Z[2],
Matrix->Y[0], Matrix->Y[1], Matrix->Y[2]);
]

you should have the exact same result, as if you had called glLoadIdentity() and rendered from this position...

you can now move your camera by adding your ''step''-value to
X: P[0]
Y: P[1]
Z: P[2]

rotation is done by multiplication of the camera-matrix with a rotation matrix (search the internet for ''rotation matrix'' & ''matrix multiplication'')

your camera-matrix now is always at your (player''s) position and a call to gluLookAt(see parameters above) will setup opengl for the right camera-position.

one last hint : since gluLookAt() only multiplicates its matrix with the current matrix, you should call glLoadIdentity() right before your call to gluLookAt().

the advantage of doing it this way, instead of using glRotate() and glTranslate() with an angle for all axis, is that you get rid of the bad, bad gimble-lock , which means, that you can move freely thru space & always rotate around the own axis.

hope, this helps you...
uNiQue0815
uNiQue0815
oh... i almost forgot...
the code to move along your axis...

(a copy from my code...)

void nxCamera::MoveX (GLfloat step)
{
GLfloat x, y, z;

x = Matrix->X[0] * step;
y = Matrix->X[1] * step;
z = Matrix->X[2] * step;

Matrix->P[0] += x;
Matrix->P[1] += y;
Matrix->P[2] += z;
}

void nxCamera::MoveY (GLfloat step)
{
GLfloat x, y, z;

x = Matrix->Y[0] * step;
y = Matrix->Y[1] * step;
z = Matrix->Y[2] * step;

Matrix->P[0] += x;
Matrix->P[1] += y;
Matrix->P[2] += z;
}

void nxCamera::MoveZ (GLfloat step)
{
GLfloat x, y, z;

x = Matrix->Z[0] * step;
y = Matrix->Z[1] * step;
z = Matrix->Z[2] * step;

Matrix->P[0] += x;
Matrix->P[1] += y;
Matrix->P[2] += z;
}

it''s quite simple to understand...
Matrix->X[0..2] holds the x, y, z values for the X-axis
Matrix->Y[0..2] holds the x, y, z values for the Y-axis
Matrix->Z[0..2] holds the x, y, z values for the Z-axis
Matrix->P[0..2] holds the x, y, z values for the Position

for movement in x-direction, you just multiply x, y, z of the X-axis with your step-length and add them to x, y, z of your position.
the same thing for Y & Z - axis... that''s easy, isn''t it ?

hope, you can use this for your code...
oeginc
oeginc
quote:
Original post by uNiQue0815
it''s quite simple to understand...

for movement in x-direction, you just multiply x, y, z of the X-axis with your step-length and add them to x, y, z of your position. the same thing for Y & Z - axis... that''s easy, isn''t it ?

hope, you can use this for your code...


OMG. I just wrote a camera class, and I *THOUGHT* I knew what the heck I was doing, but you just totally thru me for a loop... Looks like it''s back to the books, I like your idea of storing the matrix internally... I am currently using the translate/rotate method you described and haven''t run into a "gimble lock" problem yet (that I know of), I can walk, turn, rotate, etc all over the place and don''t seem to have any problems, but it''s in a small test-bed world at the moment...

Thanks for your post, I hope once I understand what your saying it will be very informative!
zedzeek
zedzeek
quite a few camera questions (why do questions seem to go in waves ie one week its fog next week its billboards etc)
for quake style movement (no roll) u can get away with storing the direction in 2 eular angles. note i find its physically easier to control the camera this way (also theres nothing stopping u from letting the camera leave the groundf also with this method)
if u want to have heading,pitch + roll u cant use eular angles (u will get gimbal lock) u are forced to store the rotation in either matrice or quaternion

to do a quake style camera (not 100% certain here, im on linux + all my programming stuff is on my windows hd)
use
dir.x = sin(heading)*cos(pitch)
dir.y = sin(pitch)
dir.z = cos(heading)*sin(pitch)

something like that anyways

http://uk.geocities.com/sloppyturds/gotterdammerung.html
uNiQue0815
uNiQue0815
yes... that''s right... IF you don''t want to move freely & rotate around all axis, then you can just store an angle-float for your axis and use glRotate(). (quake-style) but if you want to do it like in a space-simulation, you gotta go my way
i''m gonna put a gimble-lock-emulator into my camera-class for movement á la quake... this won''t be too hard... so i can use both methods in just one class
Jason2Jason
Jason2Jason
quote:
Original post by uNiQue0815
well... you SHOULD use gluLookAt... !!



Why am i being forced to use gluLookAt(), when (as far as i know) is 3 glrotatef()''s and a glTranslatef() function calls! Isn''t it? I''m trying not to use too many function from glu libary.

I''ll just add this quick note about my camera class I''m trying to make. I''m making it so it can be used in any open gl program, from a flite sim, to a quake-like game, to even a movie (but i prob wont make a movie tho). Basicly I''m making it with the option of free movment in all directions. I dont want to use glu functions if posible. I''ll post the main function and the definition of my class so far (its not working yet still)


  

class CCamera
{
public:
void RollTurn(float factor);
void PitchTurn(float factor);
void MoveHeight(float factor);
void Turn(float factor);
void Move(float factor);
void SideStep(float factor);
void Reset();
void Aim(float roll, float heading, float pitch);
void Place(float x, float y, float z);
void Update();
CCamera();
virtual ~CCamera();

private:
float Roll;
float Heading;
float Pitch;
float Posit[3];
float speed;
};


void CCamera::Place(float x, float y, float z)
{
Posit[0] = x;
Posit[1] = y;
Posit[2] = z;

glTranslatef(x,y,z);
}

void CCamera::Aim(float roll, float heading, float pitch)
{
Roll = roll; Heading = heading; Pitch = pitch;

glRotatef(roll,0.0,0.0,1.0);
glRotatef(heading,0.0,1.0,0.0);
glRotatef(pitch,1.0,0.0,0.0);
}

void CCamera::Update()
{
glRotatef(Roll, 0.0,0.0,1.0);

glRotatef(Pitch, 1.0,0.0,0.0);

glRotatef(Heading, 0.0,1.0,0.0);

glTranslatef(-Posit[0], -Posit[1], -Posit[2]);

}


/*
An here''s one of the functions used to change the rotation
*/


void CCamera::Turn(float factor)
{
Heading += factor;
}

// and to move


void CCamera::Move(float factor)
{
Posit[2] += factor;
}



As you can see its all very basic stuff. But if i keep it as basic code as posible, as long as it does the job i want it to, thats fine. I''ll be sifting through all the code here to try and get something to happen, but if anyone has any other sugestions, there welcome. Just remember i haven''t even finished basic secondary skool maths yet (one year to go).

thx,

-J
uNiQue0815
uNiQue0815
well... i can''t really imagine a way of moving on your axis, when you do your rotations by x, y, z - floats & glRotate()s.

since you have to do your rotations in some sequence (x, y, z / x, z, y / or whatever), every following rotation will be influenced by the one or two, that you made before. this will lead you straight into your own, personal gimble-lock *g*. and you won''t be able to figure out a vector that shows into your viewing-direction.

well...
you could set a vector to (0.0f, 0.0f, 1.0f) - that''s your viewing direction after glLoadIdentity() and rotate it around the axis, just as you glRotate() your view. when your rotation sequence is over, the vector points just into your viewing direction (maybe negative rotation angle... don''t wanna think too much, now, just check it out... )
this will not be too exact, but i can''t think of another way to do it (with my VERY limited brainpower...)

you should really think about using a matrix & gluLookAt()

i also didn''t want to use any glu-function, but i couldn''t figure out, how to setup your camera right, depending on a camera-matrix. (i already told you ''bout my limited brainpower )
so i''m using gluLookAt() until a miracle happens, and i suddenly have an idea of how gluLookAt() works (maybe someone got it''s code & can send me... would really appreciate...).
zedzeek
zedzeek
all vectors are assumed to be normalized

glulookat works by
taking a viewing direction then crossproducting this with the up direction
now u have 3 vectors up, forward + right which is just a 3x3 matrix ie it stores a rotation, set the current matrice to that eg glLoadMatrix(..) (u shouldnt need to orthonormalize the matrice first) then do a - translate to where the camera is,
the problem with glulookat is with certain inputs u will get bogus results to find out find take a bit of paper + do some crossproduct calculations

http://uk.geocities.com/sloppyturds/gotterdammerung.html
uNiQue0815
uNiQue0815
that''s the same thing, as if i loaded my camera-matrix, isn''t it ?

but this seems not to be the right way... this will bring me - what u call : bogus-results - ...

and how to do it EXACTLY the right way is just what i couldn''t figure out... so i''m still using gluLookAt()...
TonyFish
TonyFish
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble centerz,
GLdouble upx, GLdouble upy, GLdouble upz)
{
GLdouble m[16];
GLdouble x[3], y[3], z[3];
GLdouble mag;

/* Make rotation matrix */

/* Z vector */
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
if (mag) { /* mpichler, 19950515 */
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}

/* Y vector */
y[0] = upx;
y[1] = upy;
y[2] = upz;

/* X vector = Y cross Z */
x[0] = y[1] * z[2] - y[2] * z[1];
x[1] = -y[0] * z[2] + y[2] * z[0];
x[2] = y[0] * z[1] - y[1] * z[0];

/* Recompute Y = Z cross X */
y[0] = z[1] * x[2] - z[2] * x[1];
y[1] = -z[0] * x[2] + z[2] * x[0];
y[2] = z[0] * x[1] - z[1] * x[0];

/* mpichler, 19950515 */
/* cross product gives area of parallelogram, which is < 1.0 for
* non-perpendicular unit-length vectors; so normalize x, y here
*/

mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}

mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}

#define M(row,col) m[col*4+row]
M(0, 0) = x[0];
M(0, 1) = x[1];
M(0, 2) = x[2];
M(0, 3) = 0.0;
M(1, 0) = y[0];
M(1, 1) = y[1];
M(1, 2) = y[2];
M(1, 3) = 0.0;
M(2, 0) = z[0];
M(2, 1) = z[1];
M(2, 2) = z[2];
M(2, 3) = 0.0;
M(3, 0) = 0.0;
M(3, 1) = 0.0;
M(3, 2) = 0.0;
M(3, 3) = 1.0;
#undef M
glMultMatrixd(m);

/* Translate Eye to Origin */
glTranslated(-eyex, -eyey, -eyez);

}

<Fish>{
<Fish>{

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.