Moving camera in 3D
Hi,
I am building a flight simulator. When the user presses the left key the camera shoudl rotate left. I don't have a problem to get that to work. When they press UP they should continiously move forward, until back is pressed.
I know how to move the camera continiously along an axis. My problem is how do I continiously move forward in the rotated direction?
For example: If they havent pressed left (and not rotated at all), I move forward by calling glTranslate(0,1,0);. But after I rotate with glRotate(4,x,y,z) and then call glTranslate(0,1,0) I basically "strafe". I want to move in the direction that the camera is pointing. I am assuming this is a linear algebra problem (which I haven't taken).
Thanks
I think I found a partial solution. This solution rotates around the Y axis. How can I change it to rotate around the Z axis?
Link: http://www.lighthouse3d.com/opengl/glut/index.php?6
Link: http://www.lighthouse3d.com/opengl/glut/index.php?6
In your simulator, you'll be expecting full 6DOF, so start-off with quaternions and avoid gluLookAt. The jet can be flying (pointing) directly upwards, after all.
Some pseudo-code:
I could have mistaken some +/- sign somewhere, as I'm still inexperienced to 3D maths.
Some pseudo-code:
Vec3 jet_position = Vec3(0,0,0); // calculated in the code belowQuat jet_orientation; //modified by other codefloat speed=0; // modified by other codevoid Render(){ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslate(-jet_position); Mat3x3 rotation = jet_orientation.ToMatrix(); Mat4x4 rotation4x4 = Mat4x4_identity; rotation4x4.setRotation(rotation); // this simply copies a 3x3 matrix to 4x4 glMultMatrix(rotation4x4); .. now render}void UpdateJetPosition(){ Mat3x3 rotation = jet_orientation.ToMatrix(); Vec3 speed3 = Vec3(0,0,speed); // as if the aircraft flies only forward to Z Vec3 speed3_rotated = rotation * speed3; // this rotated the above direction jet_position += speed3_rotated;}
I could have mistaken some +/- sign somewhere, as I'm still inexperienced to 3D maths.
Hi mbanghart,
hi think the problem you are experiencing is caused by the order of the transformations. When you are not sure about the order of a translation and a rotation, try to exchange them; a lot of times the difference in the result will give you an idea of what's going on.
Second, you may find useful the function gluLookAt():
http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
That basically can do the job for you. The problem of simulation and rendering can be split in two parts. For instance, if your camera is in the point (x, 0.0f, z) and is looking to the point (cx, 0.0f, cz), you can call gluLookAt() in the following way:
gluLookAt(x, 0.0f, z, cx, 0.0f, cz, 0.0f, 1.0f, 0.0f);
Assuming hence no roll:
http://en.wikipedia.org/wiki/Flight_dynamics
Having an algebraic background helps, however what really is fundamental is the concept of transformation, and it's pretty supported by the OpenGL matrix functions. Once you fix a homogeneous reference system, spatial transformations (translation, scale and rotation) and 4x4 matrices are equivalent. Scale and rotation can be done with 3x3 matrixes in a conventional reference system, but not the translation; hence the need of using 4x4 matrixes and homogeneous reference. But as I told you, you don't really need this.
OpenGL stores the current transformation in an inner state variable; all the matrix functions operate on that transformation, and save the result in the same variable. There are three of this transformations, used in different stage of the rendering: the current one can be set calling the function glMatrixMode().
http://www.opengl.org/sdk/docs/man/xhtml/glMatrixMode.xml
Transformations operate on points; when you call glVertex3f(x, y, z), the vertex v=[x, y, z] is first transformed using the GL_WORLDVIEW transformation, and then sent to the screen in a position obtained transforming again with the transformation GL_PROJECTION. When a vertex v is transformed by a transformation A you can express the result as:
A(v)
Which means, A applied to v. Probably you need to set GL_PROJECTION just once, at the beginning of the program. Moving the camera is a matter of setting GL_WORLDVIEW.
The composition of two transformations A and B can be expressed with:
A(B(v))
In which v is transformed with B, and then the result is transformed again with A.
The function glIdentity() puts an identical transformation in the current transformation; the identical transformation doesn't do anything. You should call glIdentity() in order to initialize the variable on which you will work.
All the subsequent calls to matrix functions combine the current transformation with the transformation specified by the particular function you call. MORE RECENT CALLS ARE APPLIED FIRST! This means that the following code:
glMatrixMode(GL_WORLDVIEW);
glIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
Will FIRST perform a rotation R and THEN a translation T; it corresponds to:
T(R(v))
While the following code:
glMatrixMode(GL_WORLDVIEW);
glIdentity();
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -1.0f);
Will FIRST perform a translation T and THEN a rotation R; it corresponds to:
R(T(v))
The visual difference between this two snippets is that in the first one you first rotate the camera and then you step forward, while in the second is the opposite.
Hope I helped you a little bit! Bye!
hi think the problem you are experiencing is caused by the order of the transformations. When you are not sure about the order of a translation and a rotation, try to exchange them; a lot of times the difference in the result will give you an idea of what's going on.
Second, you may find useful the function gluLookAt():
http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
That basically can do the job for you. The problem of simulation and rendering can be split in two parts. For instance, if your camera is in the point (x, 0.0f, z) and is looking to the point (cx, 0.0f, cz), you can call gluLookAt() in the following way:
gluLookAt(x, 0.0f, z, cx, 0.0f, cz, 0.0f, 1.0f, 0.0f);
Assuming hence no roll:
http://en.wikipedia.org/wiki/Flight_dynamics
Having an algebraic background helps, however what really is fundamental is the concept of transformation, and it's pretty supported by the OpenGL matrix functions. Once you fix a homogeneous reference system, spatial transformations (translation, scale and rotation) and 4x4 matrices are equivalent. Scale and rotation can be done with 3x3 matrixes in a conventional reference system, but not the translation; hence the need of using 4x4 matrixes and homogeneous reference. But as I told you, you don't really need this.
OpenGL stores the current transformation in an inner state variable; all the matrix functions operate on that transformation, and save the result in the same variable. There are three of this transformations, used in different stage of the rendering: the current one can be set calling the function glMatrixMode().
http://www.opengl.org/sdk/docs/man/xhtml/glMatrixMode.xml
Transformations operate on points; when you call glVertex3f(x, y, z), the vertex v=[x, y, z] is first transformed using the GL_WORLDVIEW transformation, and then sent to the screen in a position obtained transforming again with the transformation GL_PROJECTION. When a vertex v is transformed by a transformation A you can express the result as:
A(v)
Which means, A applied to v. Probably you need to set GL_PROJECTION just once, at the beginning of the program. Moving the camera is a matter of setting GL_WORLDVIEW.
The composition of two transformations A and B can be expressed with:
A(B(v))
In which v is transformed with B, and then the result is transformed again with A.
The function glIdentity() puts an identical transformation in the current transformation; the identical transformation doesn't do anything. You should call glIdentity() in order to initialize the variable on which you will work.
All the subsequent calls to matrix functions combine the current transformation with the transformation specified by the particular function you call. MORE RECENT CALLS ARE APPLIED FIRST! This means that the following code:
glMatrixMode(GL_WORLDVIEW);
glIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
Will FIRST perform a rotation R and THEN a translation T; it corresponds to:
T(R(v))
While the following code:
glMatrixMode(GL_WORLDVIEW);
glIdentity();
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -1.0f);
Will FIRST perform a translation T and THEN a rotation R; it corresponds to:
R(T(v))
The visual difference between this two snippets is that in the first one you first rotate the camera and then you step forward, while in the second is the opposite.
Hope I helped you a little bit! Bye!
damix911, airplanes can fly upside-down for a while - so the "up" vector in gluLookAt will ruin things. Also, if you make the camera look at a place right above it, rotation around the "up" vector cannot be known. I think I've seen that cause random rotations thanks to tiny precision errors getting multiplied by large numbers while being normalized. Thus, I think gluLookAt is useless in flight-simulators.
Hi idinev, yes actually I was only thinking to a very simple solution to turn left and right (no pitch and roll), for this reason I have choosen the vector [0, 1, 0]. You are right when you say there is a problem with gluLookAt() and up vector for flight simulators; I wrote two simple (ugly) flight simulators in DirectX, and I remember I had a hard time to make them work properly; but I used the equivalent function D3DXMatrixLookAtLH() exactly because it was quite comfortable for the six degrees of freedom. The state of the plane was described by a position P, a direction D and a up vector U. I actually had to update the up vector U in order to be orthogonal with the direction, and this is actually the annoying part. But after this, you have a local reference system in wich D is a z-axis (negative z in OpenGL), U is a y-axis, and a x-axis can be obtained by doing the cross product D x U. At that point you can map those axis to buttons on they joypad and you have three of the six degrees almost for free. And this vectors are also good for the function D3DXMatrixLookAtLH/gluLookAt because the first three arguments are in P, the second three arguments are in P + D, and the last three arguments are in U.
Thanks for the help. Right now I am not trying to create a 6DOF simulator. Just a basic one that ignores pitch and roll. I ended up having it work without using glLookAt. Just glRotate and glTranslate. Still having some rotation problems since I don't my position at any given point (so I have rotate around the origin).
Will probably have to add some variable to keep track of all translations.
Will probably have to add some variable to keep track of all translations.
Hi mbanghart, you can try with something like this.
Your state in the game can be represented by position on a 2D map, something like:
float x, z; // position
and an angle, representing the direction of looking:
float alpha; // direction of looking
The two problems of updating the state and rendering the scene can be solved separately.
=== Updating the state ===
Let's suppose that the time elapsed from your last updating is t. The new position is hence:
x = x + (t * speed) * cos(alpha);
z = z + (t * speed) * sin(alpha);
If you don't want to take in account time, and you simply want to step forward or backward when buttons are pressed, you can substitute the term (t * speed) with whatever you like, for instance 0.1f, 1.2f, aValueOfYourChoice.
In addition, then the user presses the right button, your program should do:
alpha -= 1.0f;
instead, when the user presses the left button, your program should do:
alpha += 1.0f;
=== Rendering the scene ===
You have to translate the plane position in the origin, and then you must rotate the world to simulate the rotation of the camera; remember that the LATEST you call a transformation, the EARLIEST it is applied.
glMatrixMode(GL_MODELVIEW);
glIdentity();
glRotatef(-angle, 0.0f, 1.0f, 0.0f);
glTranslatef(-x, 0.0f, -z);
The minus is used because you are actually moving the world, not the camera; so directions and angles must be inverted.
Your state in the game can be represented by position on a 2D map, something like:
float x, z; // position
and an angle, representing the direction of looking:
float alpha; // direction of looking
The two problems of updating the state and rendering the scene can be solved separately.
=== Updating the state ===
Let's suppose that the time elapsed from your last updating is t. The new position is hence:
x = x + (t * speed) * cos(alpha);
z = z + (t * speed) * sin(alpha);
If you don't want to take in account time, and you simply want to step forward or backward when buttons are pressed, you can substitute the term (t * speed) with whatever you like, for instance 0.1f, 1.2f, aValueOfYourChoice.
In addition, then the user presses the right button, your program should do:
alpha -= 1.0f;
instead, when the user presses the left button, your program should do:
alpha += 1.0f;
=== Rendering the scene ===
You have to translate the plane position in the origin, and then you must rotate the world to simulate the rotation of the camera; remember that the LATEST you call a transformation, the EARLIEST it is applied.
glMatrixMode(GL_MODELVIEW);
glIdentity();
glRotatef(-angle, 0.0f, 1.0f, 0.0f);
glTranslatef(-x, 0.0f, -z);
The minus is used because you are actually moving the world, not the camera; so directions and angles must be inverted.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement