I've read through several over-complicated articles on rendering a 3D scene with OpenGL, and haven't really found something that helps me to visualize the basic concepts of scene navigation with respect to glRotate and glTranslate calls.
From experimenting with the examples provided by LWJGL (my particular OpenGL library), I understand very basically what effect comes of their use. I can use glTranslate to move to a point, glRotate to rotate about that point, and glLoadIdentity to snap back to the origin or glPopMatrix to go back to the last glPushMatrix, which are essentially snapshots of a location and rotation. Finally, the scene will render to screen with respect to the origin.
So basically, to put a cube at point A with rotation B:
glTranslate(A.x,A.y,A.z) [now focused on point A]
glRotate(B.,,*,*) for pitch, yaw, and roll; [now rotated to rotation B]
glBegin(GL_QUADS) and glVertex3f()x4 for each 'side'(quad) relative to object's origin
glEnd()
glLoadIdentity() [reset to origin for other objects, not needed if only drawing the cube]
As for the "camera", since openGL's "eye" is fixed, the scene has to move inversely from the camera in order to simulate moving the eye with the camera. This is my understanding so far, and if this is wrong, please put me on the right path.
Now for my specific situation and question:
My 'scene' consists of terrain and a player (some arbitrary shape, located at a terrain-relevant location and a 'camera' head). The view should rotate with respect to the player, and the player move with respect to the terrain. I want the final rendering to essentially "look through" the player's head, or camera. My confusion is with the order of translate/rotate calls for rendering each part, and the direction of translation. Is the following the proper way to render the terrain and player with respect to the player's "camera"?
translate away from the player by the player's distance from origin (move the scene)
rotate away from the player's rotation (player looks 40 degrees right, so rotate scene 40 left)
render terrain
reset via glLoadIdentity
render player's head (if needed)
translate to body/hands/whatever position
rotate away from the player's rotation (step 2 again)
render body/hands/whatever
Also, does rotating have an effect on translation? Aka, does OpenGL translate with respect to the rotation, or does rotation have no bearing on translation?
I can use glTranslate to move to a point, glRotate to rotate about that point, and glLoadIdentity to snap back to the origin or glPopMatrix to go back to the last glPushMatrix, which are essentially snapshots of a location and rotation.
No not quite. Those functions have now idea of what a scene is. All they do is manipulating matrices. Here's an excellent article about it:
http://www.opengl.org/wiki/Viewing_and_Transformations
One important thing to keep in mind when working with OpenGL is, that it is not a scene graph. All it does is rendering flat points, lines and triangles to the framebuffer. There's no such thing like a scene you navigate.
So basically, to put a cube at point A with rotation B:
(...)
Yes, you got that one right.
As for the "camera", since openGL's "eye" is fixed
Well, OpenGL got no camera. It's only pushing vertices through the modelview matrix, does lighting calculations on them, then passes them through the projection and maps them to the viewport.
Related
I'm making a skybox in my game. The game has a solar system with some things in it (to start, the sun and the earth, with stars in the background). The player is on one planet in this solar system. The solar system is represented to the player using a skybox, with 2D sprites projected onto the skybox in the corresponding positions. The Skybox is rendered with OpenGL (actually, Java's LWJGL) [1]
First things first, all of the bodies are being tracked in 3D space. I can obtain their coordinates, relative directions, etc. All orbits are defined independently (aka, occur on arbitrary planes). In addition, planets have Quaternion rotations. Rendering the system in full 3D, there are no problems.
Projecting the system to the skybox is another matter entirely. In theory, I figure that I should be able to do it like this;
1. Calculate direction vector of where the player is looking (full rotations are not relevant - the vector just has to point in the right direction).
2. Multiply this direction vector with their planet's orientation (Quaternion) to calculate the "view direction"
3. Calculate direction vector from the planet to the object being viewed
4. Find the rotation between the vectors, and rotate the skybox accordingly.
However, when I feed OpenGL my angles, Gimbal Locking occurs and orbits that should be straight: go all bendy (although rotations around one single axis work fine). In what ways can I attempt to prevent this from happening? I'm at a loss.
[1]: My terrain is actually a flat square voxel grid, and I scale the player's coordinates onto it, then pretend that it is a 3D planet.
I want to mix a perspective and orthographic view, but I can't get it to work.
I want X and Y coordinates to be orthographic and Z perspective. For clarification I added a sketch of the desired transformation from OpenGL coordinates to screen display:
(I started from a tutorial, but couldn't find how to get values top, bottom, etc.)
What you've drawn is simply perspective, not a mix. You just have to make sure that the viewing direction is parallel to the z axis to make the front and back faces of the box stay rectangular.
You could probably use glFrustum to achieve this.
If you use a standard perspective matrix and the camera faces the box front on, X/Y will be uniform, however movement away from the camera will move the X/Y coordinates towards the centre, shrinking them for a standard parallax effect. What you've drawn is movement towards the top of the window. All you need to do is crop the perspective projection to below its standard centre. That's where glFrustum comes in - move the normally symmetrical top/bottom arguments down, align the camera/view matrix along the axis you want and you should have the desired projection.
Any rotation of the camera/view will destroy the uniform projection in the X/Y plane. For camera movement you're then limited to panning and moving the glFrustum bounds.
EDIT Come to think of it, you could probably just throw in a glTranslatef(shearX, shearY, 0) before the call to gluPerspective and achieve the same thing.
I would like to create a snowman in OpenGL 2.0. I would like to rotate the entire shape, but every time I run the program it doesn't work.
glPushMatrix();
//bottom sphere
glTranslated(tranX,tranY-2,tranZ);
glRotated(rotX,1,0,0);
glRotated(rotY,0,1,0);
glRotated(rotZ,0,0,1);
glScaled(scaX,scaY,scaZ);
glColor3f(1.1,.7,.99);
glutSolidSphere(1.5,30,30);
//middle sphere
glTranslated(tranX,tranY+2.3,tranZ+8);
glRotated(rotX,1,0,0);
glRotated(rotY,0,1,0);
glRotated(rotZ,0,0,1);
glScaled(scaX,scaY,scaZ);
glColor3f(1.1,.7,.99);
glutSolidSphere(1.3,30,30);
//top sphere
glTranslated(tranX,tranY+2,tranZ+10);
glRotated(rotX,1,0,0);
glRotated(rotY,0,1,0);
glRotated(rotZ,0,0,1);
glScaled(scaX,scaY,scaZ);
glColor3f(1.1,.7,.99);
glutSolidSphere(1,30,30);
glPopMatrix();
The thing to know about OpenGL transformations is that they modify the current coordinate system, and not individual objects. For example, when you call glRotated, it rotates the coordinate system the provided angle around the axis supplied, and affects every bit of geometry you render after calling it, until you change or replace the matrix (by calling glPopMatrix, glLoadMatrix, etc.).
In your example, you rotate each sphere of the snowman, but don't have an overarching rotation that affects all of the objects in the scene. Try placing the rotation(s) that you want to affect the entire scene immediately after the glPushMatrix call at the top of your routine.
I was trying to understand lesson 9 from NEHEs tutorial, which is about bitmaps being moved in 3d space.
the most interesting thing here is to move 2d bitmap texture on a simple quad through 3d space and keep it facing the screen (viewer) all the time. So the bitmap looks 3d but is 2d facing the viewer all the time no matter where it is in the 3d space.
In lesson 9 a list of stars is generated moving in a circle, which looks really nice. To avoid seeing the star from its side the coder is doing some tricky coding to keep the star facing the viewer all the time.
the code for this is as follows: ( the following code is called for each star in a loop)
glLoadIdentity();
glTranslatef(0.0f,0.0f,zoom);
glRotatef(tilt,1.0f,0.0f,0.0f);
glRotatef(star[loop].angle,0.0f,1.0f,0.0f);
glTranslatef(star[loop].dist,0.0f,0.0f);
glRotatef(-star[loop].angle,0.0f,1.0f,0.0f);
glRotatef(-tilt,1.0f,0.0f,0.0f);
After the lines above, the drawing of the star begins. If you check the last two lines, you see that the transformations from line 3 and 4 are just cancelled (like undo). These two lines at the end give us the possibility to get the star facing the viewer all the time. But i dont know why this is working.
And i think this comes from my misunderstanding of how OpenGL really does the transformations.
For me the last two lines are just like undoing what is done before, which for me, doesnt make sense. But its working.
So when i call glTranslatef, i know that the current matrix of the view gets multiplied with the translation values provided with glTranslatef.
In other words "glTranslatef(0.0f,0.0f,zoom);" would move the place where im going to draw my stars into the scene if zoom is negative. OK.
but WHAT exactly is moved here? Is the viewer moved "away" or is there some sort of object coordinate system which gets moved into scene with glTranslatef? Whats happening here?
Then glRotatef, what is rotated here? Again a coordinate system, the viewer itself?
In a real world. I would place the star somewhere in the 3d space, then rotate it in the world space around my worlds origin, then do the moving as the star is moving to the origin and starts at the edge again, then i would do a rotate for the star itself so its facing to the viewer. And i guess this is done here. But how do i rotate first around the worlds origin, then around the star itself? for me it looks like opengl is switching between a world coord system and a object coord system which doesnt really happen as you see.
I dont need to add the rest of the code, because its pretty standard. Simple GL initializing for 3d drawings, the rotating stuff, and then the simple drawing of QUADS with the star texture using blending. Thats it.
Could somebody explain what im misunderstanding here?
Another way of thinking about the gl matrix stack is to walk up it, backwards, from your draw call. In your case, since your draw is the last line, let's step up the code:
1) First, the star is rotated by -tilt around the X axis, with respect to the origin.
2) The star is rotated by -star[loop].angle around the Y axis, with respect to the origin.
3) The star is moved by star[loop].dist down the X axis.
4) The star is rotated by star[loop].angle around the Y axis, with respect to the origin. Since the star is not at the origin any more due to step 3, this rotation both moves the center of the star, AND rotates it locally.
5) The star is rotated by tilt around the X axis, with respect to the origin. (Same note as 4)
6) The star is moved down the Z axis by zoom units.
The trick here is difficult to type in text, but try and picture the sequence of moves. While steps 2 and 4 may seem like they invert each other, the move in between them changes the nature of the rotation. The key phrase is that the rotations are defined around the Origin. Moving the star changes the effect of the rotation.
This leads to a typical use of stacking matrices when you want to rotate something in-place. First you move it to the origin, then you rotate it, then you move it back. What you have here is pretty much the same concept.
I find that using two hands to visualize matrices is useful. Keep one hand to represent the origin, and the second (usually the right, if you're in a right-handed coordinate system like OpenGL), represents the object. I splay my fingers like the XYZ axes to I can visualize the rotation locally as well as around the origin. Starting like this, the sequence of rotations around the origin, and linear moves, should be easier to picture.
The second question you asked pertains to how the camera matrix behaves in a typical OpenGL setup. First, understand the concept of screen-space coordinates (similarly, device-coordinates). This is the space that is actually displayed. X and Y are the vectors of your screen, and Z is depth. The space is usually in the range -1 to 1. Moving an object down Z effectively moves the object away.
The Camera (or Perspective Matrix) is typically responsible for converting 'World' space into this screen space. This matrix defines the 'viewer', but in the end it is just another matrix. The matrix is always applied 'last', so if you are reading the transforms upward as I described before, the camera is usually at the very top, just as you are seeing. In this case you could think of that last transform (translate by zoom) as a very simple camera matrix, that moves the camera back by zoom units.
Good luck. :)
The glTranslatef in the middle is affected by the rotation : it moves the star along axis x' to distance dist, and axis x' is at that time rotated by ( tilt + angle ) compared to the original x axis.
In opengl you have object coordinates which are multiplied by a (a stack of) projection matrix. So you are moving the objects. If you want to "move a camera" you have to mutiply by the inverse matrix of the camera position and axis :
ProjectedCoords = CameraMatrix^-1 . ObjectMatrix . ObjectCoord
I also found this very confusing but I just played around with some of the NeHe code to get a better understanding of glTranslatef() and glRotatef().
My current understanding is that glRotatef() actually rotates the coordinate system, such that glRotatef(90.0f, 0.0f, 0.0f, 1.0f) will cause the x-axis to be where the y-axis was previously. After this rotation, glTranslatef(1.0f, 0.0f, 0.0f) will move an object upwards on the screen.
Thus, glTranslatef() moves objects in accordance with the current rotation of the coordinate system. Therefore, the order of glTranslatef and glRotatef are important in tutorial 9.
In technical terms my description might not be perfect, but it works for me.
Using OpenGL I'm attempting to draw a primitive map of my campus.
Can anyone explain to me how panning, zooming and rotating is usually implemented?
For example, with panning and zooming, is that simply me adjusting my viewport? So I plot and draw all my lines that compose my map, and then as the user clicks and drags it adjusts my viewport?
For panning, does it shift the x/y values of my viewport and for zooming does it increase/decrease my viewport by some amount? What about for rotation?
For rotation, do I have to do affine transforms for each polyline that represents my campus map? Won't this be expensive to do on the fly on a decent sized map?
Or, is the viewport left the same and panning/zooming/rotation is done in some otherway?
For example, if you go to this link you'll see him describe panning and zooming exactly how I have above, by modifying the viewport.
Is this not correct?
They're achieved by applying a series of glTranslate, glRotate commands (that represent camera position and orientation) before drawing the scene. (technically, you're rotating the whole scene!)
There are utility functions like gluLookAt which sorta abstract some details about this.
To simplyify things, assume you have two vectors representing your camera: position and direction.
gluLookAt takes the position, destination, and up vector.
If you implement a vector class, destinaion = position + direction should give you a destination point.
Again to make things simple, you can assume the up vector to always be (0,1,0)
Then, before rendering anything in your scene, load the identity matrix and call gluLookAt
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( source.x, source.y, source.z, destination.x, destination.y, destination.z, 0, 1, 0 );
Then start drawing your objects
You can let the user span by changing the position slightly to the right or to the left. Rotation is a bit more complicated as you have to rotate the direction vector. Assuming that what you're rotating is the camera, not some object in the scene.
One problem is, if you only have a direction vector "forward" how do you move it? where is the right and left?
My approach in this case is to just take the cross product of "direction" and (0,1,0).
Now you can move the camera to the left and to the right using something like:
position = position + right * amount; //amount < 0 moves to the left
You can move forward using the "direction vector", but IMO it's better to restrict movement to a horizontal plane, so get the forward vector the same way we got the right vector:
forward = cross( up, right )
To be honest, this is somewhat of a hackish approach.
The proper approach is to use a more "sophisticated" data structure to represent the "orientation" of the camera, not just the forward direction. However, since you're just starting out, it's good to take things one step at a time.
All of these "actions" can be achieved using model-view matrix transformation functions. You should read about glTranslatef (panning), glScalef (zoom), glRotatef (rotation). You also should need to read some basic tutorial about OpenGL, you might find this link useful.
Generally there are three steps that are applied whenever you reference any point in 3d space within opengl.
Given a Local point
Local -> World Transform
World -> Camera Transform
Camera -> Screen Transform (usually a projection. depends on if you're using perspective or orthogonal)
Each of these transforms is taking your 3d point, and multiplying by a matrix.
When you are rotating the camera, it is generally changing the world -> camera transform by multiplying the transform matrix by your rotation/pan/zoom affine transformation. Since all of your points are re-rendered each frame, the new matrix gets applied to your points, and it gives the appearance of a rotation.