I’m making a 2D game seen from above, and thought “hey it would be nice to be able to zoom in on the players, so that not everything on the map is showing”.
Now, what I’d love to do is to set a camera to follow a player’s X/Y coordinates, and then just set the range of view this camera should have. Question is how this is done in a good way. I’ve heard GLU should fit this need perfectly, but I’ve tried and tried and can’t get it to work like I want it to (nothing is being shown when I play around with GLU).
Maybe GLU is best for 3D, but as I said this is a 2D game. Feel free to give code examples instead of just saying “you should do X” because code says more than a 1000 words. Err. Well, if the code is short and clean at least.
This is not really a JOGL question, but a fundamental 3d application one
Your game’s bird-view Ortho coordinate may want to reflect the players x/y coordinates?
Hint: So it’s the center of things?
However … let’s use a more general forum for such discussions.
Someone pointed me to gamedev.net for these thing …
I didn’t check the gl reference, so my edges might need to be swapped around. GLU wouldn’t help to much with this; it provides a useful gluLookAt() function for 3D environments, and a gluOrtho2D(), but Ortho2D doesn’t add much to glOrtho.
That’s funny though, I tried changing glOrtho before and it ended up showing nothing at all. Hm. If I change glOrtho on each frame could that mean that it somehow changes the previous changed image before and keeps zooming in or something?
I’ll try a bit more, thankful for all further thoughts still though.
If I uncomment the second glOrtho (above “iiii++;”) a black square is drawn on white background. What I hoped to achieve with the second glOrtho is to shrink the square to about half size (since the area set by glOrtho is doubled). What happened however was that nothing at all was drawn, only the white background.
So how can I get the effect I desire (shrink the square)? In the game I would want to zoom in instead of zoom out, but I figure it’ll be easy to zoom in once I know how to zoom out.
It was glLoadIdentity that did the trick. I don’t really know why since I’m new to the whole OpenGL thing, so if someone that knows would explain that would be great. Also I’m not sure what’s so good about using glMatrixMode to change between GL_PROJECTION and GL_MODELVIEW all the time, but apparently that is a good thing? From what I found online people keep saying that changing glMatrixMode is important but I don’t know why since not doing so doesn’t effect the results one bit visually.
EDIT: originally I posted and missed your solution, which looks good. I’m glad you figured it out.
OpenGL has multiple different transforms that are applied when rendering. The two most important ones are the modelview (camera, positions, etc.) and the projection matrix (how to go from 3d to 2d). Which matrix is updated depends on the current matrix mode (the default is the modelview).
So in your code, you’re calling glOrtho but that modifies the modelview matrix. In some scenarios, especially with lighting, this causes problems. Also, the call glOrtho() computes a new matrix and multiplies it with the current one, it doesn’t set the matrix to the computed matrix.
I also realized that my original suggestion to compute a recentered glOrtho() based on position is a little heavy-handed. It would be better to set up a glOrtho of the size you want, centered around the origin and leave it alone after that. Then in your display() method, you should do something like:
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the camera
gl.glTranslatef(-playerX, -playerY, 0); // re-center everything
You can then use the push/pop mechanism to set the world transforms of your rendered objects:
// for each thing to draw
gl.glPushMatrix();
... set transform
... render somehow
gl.glPopMatrix(); // restore matrix
So I modified my post, it add some stuff for your 2d application. As far as glLoadIdentity() is concerned, it’s not necessary to call it everytime the matrix mode changes. When changing the projection matrix, we didn’t want to concatenate projections, so we had to clean the slate with glLoadIdentity(). When setting the modelview, it’s useful to load identity at the beginning of the frame so we have known transform state to start with.
One example where you wouldn’t call glLoadIdentity() would be when changing the texture coordinate matrix (transforms texcoords before they access textures). You would switch to that mode, configure it, and then switch back to the modelview matrix. However, it could be that your modelview is configured already to render everythinng correctly so wouldn’t want to load identity. It really depends on how you modify your transform state.
Ah so glLoadIdentity clears everything previously set in that glMatrixMode. Does that mean that if you call glLoadIdentity when glMatrixMode is set to GL_MODELVIEW it will remove settings you have changed in that mode (like if you had called “gl.glEnable(GL.GL_POINT_SMOOTH);” previously in GL_MODELVIEW.
I’ve looked at your new suggested solution, I’ve seen it alot when looking around the net. But i don’t like too much to have all coordinates relative to the player, I like it better to change what section is being viewed. That way I can visualize a big canvas where I paint all my things, then I cut out a part of it and show to the user. With your solution it’ll be more like painting what I want to show in front of where the user is standing looking at the canvas.
Changing the glOrtho on every frame shouldn’t have that much of an impact on performance, right?
CyanPrime: Well because I don’t understand it. Thread title mentions “GLU”, I was playing around with lookAt and tried it but it never worked. I just assumed that it was more meant for 3D and thought it would be explained to me in this thread if it was something I could make use of. It still hasn’t been explained to me how it can be used in a 2D context, and if it’s better than the current solution I’ve found. You know, just saying “why not use X” in a thread such as this (where I specifically asked people not to just shout out a method name in the first post) isn’t very helpful. But thanks any for the effort nonetheless.
The matrix mode only applies to the matrix (and it’s stack, but that’s more advanced). So all glLoadIdentity() does is set the matrix to the identity matrix. It has no affect on any other opengl state. Also, if you do use matrix stacks, it does not reset the stack, it only modifies the matrix at the top.
No offense, but I think you’ve misunderstood what my example is doing. In my example, I set up a glTranslatef() matrix that shifts everything by (-playerX, -playerY, 0). You can think of this as the camera, because if you were to then render something at (playerX, playerY, 0), it ends up being rendered at (0, 0, 0). So you get to think and render everything from the world perspective (e.g. don’t care who’s looking), and then it gets shifted over.
This might be a little complicated, and I think a good place for you to learn more is to try reading into matrix math. OpenGL operates very heavily on matrix math and its concepts are very important in understanding how to correctly position the camera, etc.
I’m just going to throw this at you, and see if it clicks:
For simplicity, I’m only going to consider translations/positions and not rotations, but it basically works the same.
When setting up the modelview matrix, it is useful to think of it in two parts: the view/camera and then world position of what’s being drawn. When drawing your entire scene, the view will stay the same, but each object gets its own model transform.
OpenGL stores the model and view in one matrix, they’re multiplied together: [V] x [M]. Note that [V] is on the left because matrix multiplication proceeds from right to left. When opengl processes vertices, they’re first modified by [M], and then that result is modified by [V]. The end result are vertices as seen from where the camera is located. (And really [V] = [C]^-1, or the opposite of the camera’s position in the world).
With this way of doing things, you want your geometry to be relative/local. This makes it very easy to draw the same geometry data in multiple places in a scene. So if you had a square, its 4 points would be centered around (0, 0, 0). If you wanted the square centered somewhere else, you’d change its model position, or [M] to a different location.
Example:
gl.glMatrixMode(GL.GL_MODELVIEW); // we want to modify the modelview
gl.glLoadIdentity(); // beginning of the frame, so reset the modelview matrix
// the camera is located at (camX, camY, camZ)
gl.glTranslatef(-camX, -camY, -camZ); // transform opposite of that, so we're looking from the correct position
// loop over each shape to draw
gl.glPushMatrix(); // save the current matrix (which ATM is just a translation) onto the modelview stack
// shape is centered at (x, y, z)
gl.glTranslatef(x, y, z);
gl.glBegin(...);
... render relative vertices
gl.glEnd();
// restore saved matrix from before rendering, so that it's
// just (-camX, -camY, -camZ). This lets us go to the next shape
// without having to recompute the camera position.
gl.glPopMatrix();
// done rendering
Now if you don’t want to use the push/pop functions, do this:
gl.glMatrixMode(GL.GL_MODELVIEW);
// for each shape do this
gl.glLoadIdentity();
gl.glTranslatef(-camX, -camY, -camZ); // inverse of camera's location
gl.glTranslatef(x, y, z); // location of shape
gl.glBegin(..);
// render relative vertices as above
gl.glEnd();
// done rendering
No, but my 2nd suggestion is generally the preferred way of doing it.
Funny thing is that I sort of knew about world position and local position already, I must have been out of my mind before. I have already implemented a Camera class using the changing-glOrtho-solution, but I’m going to change that now. Ran into problems with drawing crosshairs and interface stuff… Glad I didn’t work THAT much on it last night.
I tried moving my camera before with glTranslatef and glScalef, but I did it all wrong. I had positive X/Y in glScalef and I scaled after I had translated… all wrong as said. Then I locked my brain into thinking I couldn’t use glTranslatef for this without having to change a lot of my existing code.
Now I just do it like this:
@Override
public void display(GLAutoDrawable drawable) {
Player player = getPlayer();
gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glPushMatrix();
if (player!=null) {
gl.glScalef(2, 2, 0); //zoom in x2
gl.glTranslatef(-player.getX(), -player.getY(), 0);
}
drawWorld(gl);
gl.glPopMatrix();
drawInterface(gl);
}
About a thousand times better than before. Thank you very much lhkbob, you da man!
I have a new unsolved question up right now over at the “Tools”-section and thought I’d link to it from here since the “Jogl”-section have a lot more readers. Maybe one of you can help me out but wouldn’t have seen the thread if it wasn’t for this link?
It’s about ProGuard, please have a look if you have used ProGuard. Also be sure not to reply to that question in this thread by mistake. Thanks a lot!