I was under the impression that gl.glTranslatef() effectively moved a sprite by the values passed in to the method (ie if I wanted a sprite to move by 2 pixels I would call gl.glTranslate(2.0f,0.0f,0.0f);
However If I do this then the sprite remains static. However If I pass in an absolute position (ie call gl.glTranslatef(52.0f,0.0f,0.0f)) my sprite moves as expected. However its starting position is out by the initial position coordinates (ie If I specify the sprite to start at 30,30 then the first draw loop draws the sprite at 62,30, once the first frame is done the sprite moves as I expect.
What is going on?
here is the draw code for my sprite.
//Reset the modelview matrix
gl.glLoadIdentity();
//drawing
//bind the previously generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D,this._texture);
//point to our buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//set the face rotation
gl.glFrontFace(GL10.GL_CW);
gl.glPushMatrix();
gl.glTranslatef(_position.x,_position.y,0.0f);//need to work out fraction of 1 that the position of the sprite represents
//point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, _textureBuffer);
//draw the vertices as a triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, _vertices.length / 3);
gl.glPopMatrix();
//disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
Note that this passes in the absolute position and not the small extra movement.
To simplify the above.
If I specify static inputs for gltranslatef
gl.glTranslatef(2.0f,2.0f,0.0f);
I would expect the matrix to move diagonally by 2 units each frame, however if I do this the matrix and hence my sprite stays at position 2,2
If I add 2 to the input parameters on each frame (ie 2, then 4 then 6 etc) my sprite moves diagonally but this is not how I thought translatef worked.
culprits for the given behaviour in your case are glPushMatrix() and glPopmatrix(). These two calls restore the original state(matrix stack) every frame. So every time your origin remain same and when you specify (2.0, 0.0,0.0) each fram with respect to world origin your sprite remains at world origin. Remove these two calls and see the magic !
Related
What I'd like to achieve is a blend where I draw two quads over eachother, both transparent, and the quad drawn last will cancel the colour of the previous quad completely, as if it was never there. However, it may not affect anything behind it besides that single other quad. Because I'm horrible at explaining, I made the following image:
I'm using very basic openGL immediate mode functions.
Currently I have something along the lines of:
glEnable(GL_BLEND)
glColor4f(0,0,1,0.3f);
glBegin(GL_QUADS);
{
glVertex2d(100, -100);
glVertex2d(-100, -100);
glVertex2d(-100, 100);
glVertex2d(100, 100);
}
glEnd();
glColor4f(0,1,0,0.3f);
glBegin(GL_QUADS);
{
glVertex2d(150, -50);
glVertex2d(-50, -50);
glVertex2d(-50, 150);
glVertex2d(150, 150);
}
glEnd();
This isn't really a blending problem per se.
One way to solve this would be to change the depth buffer comparison function.
Use GL_LESS for the green square, while drawing the blue square first.
This way the pixels of the green square overlapping the blue square, simply wouldn't be drawn at all to begin with.
glDepthFunc(GL_LEQUAL);
// Draw the blue square
glDepthFunc(GL_LESS);
// Draw the green square
If you want to have elements visible under both the blue and green square. You could draw the first and then clear the depth buffer and then it's the same.
glDepthFunc(GL_LEQUAL);
// Draw the red squares
glClear(GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LEQUAL);
// Draw the blue square
glDepthFunc(GL_LESS);
// Draw the green square
Whether there's a simpler way to do it, depends on what the overall goal is.
I have a 2D tile map in java (using libgdx no Tiled Map Editor) formed with squares and I want the tiles to gradually become darker until they won't be visible. So basically I don't want round light. The only option I know is to use alpha channel and make every tile from the source which is the player become less visible. I want to know how can I implement this using a shader. I want to render my map normally with a spritebacth and then apply the shader to my spritebacth, so I can render the light effect. Each tile should have it's own visibility. An example of a game which uses the kind of lightning I want is: http://www.desura.com/games/fragile-soul
Render each tile itself via SpriteBatch and use spriteBatch.setColor(r, g, b, a) with different "grey" values.
The tile where your player is standing on will start with white, so spriteBatch.setColor(1, 1, 1, 1) before rendering that one. And then linearly decrease the brightness for the other ones in a radius around.
For example all tiles one next to the player might get spriteBatch.setColor(0.8f, 0.8f, 0.8f, 1f) resulting in a slightly darker tile. You do this until you reach black via spriteBatch.setColor(0, 0, 0, 1). All those tiles will be completely black.
I was trying to follow example codes to simply display a rectangle on a black background, but it didn't seem to be displaying. What I did was
private static void initGL(){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,Display.getWidth(),0,Display.getHeight(),-1,1);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST); //2D mode
glColor3f(0.5f, 0.0f, 1.0f);
glBegin(GL_QUADS);
glVertex2f(-0.75, 0.75);
glVertex2f(-0.75, -0.75);
glVertex2f(0.75, -0.75);
glVertex2f(0.75, 0.75);
glEnd();
}
It doesn't display anything on the screen except for a black background. Does anyone know what I might have done wrong? I'm using lwjgl in eclipse.
First things first: You only have to run the whole
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,Display.getWidth(),0,Display.getHeight(),-1,1);
glMatrixMode(GL_MODELVIEW);
thing once during your program, probably shortly after you run Display.create().
Also, you're tessellating using the wrong vertices. You wrote
glVertex2f(-0.75, 0.75);
glVertex2f(-0.75, -0.75);
glVertex2f(0.75, -0.75);
glVertex2f(0.75, 0.75);
which means draw a rectangle from (-0.75, -0.75) pixels to (0.75, 0.75) pixels. This is too small to be noticed. My guess is you assumed glVertex2f deals with fractions of the display width. It does not. glVertex2f deals with actual coordinates, it just allows fractional pixels, unlike glVertex2i (this is useful believe it or not, it helps with smoother animations). Something like
glVertex2f(100F, 100F);
places a vertex at (100, 100), and is effectively equivalent to
glVertex2i(100, 100);
Also, remember that negative pixels will be rendered off the screen, because OpenGL's origin of the coordinate system, (0, 0), is in the lower left and behaves like the first quadrant from the coordinate system in math class, not like the traditional computer coordinate system with (0, 0) in the upper left.
As for the the black background, LWJGL's Display has a black background by default, so it's recommended to draw a quad with your background color that covers the entire display width and height. One quad won't really affect your performance.
glVertex2f uses same size units as your glOrtho so unless your display width and height are in units of ones, like 10 or less, you may not see anything!
I've been working on a very simple game, and I've decided to include some basic textures. I was experimenting with the code, and for some reason, I have no idea why, I cannot get the textures to map correctly. Right now, I am simply trying to map a green rectangle (512 x 64 .png file) to the bottom of a screen of size 640 x 480. This green rectangle is supposed to represent the ground. Here is an image of my failed attempt:
Here is the relevent code:
In the Boot class I have created I call this function:
public void initGL() {
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, gameWidth, gameHeight, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
In the ground class I have created, I call a draw function. The texture is loaded in the Boot class, and set as a protected variable which I bind and use in the ground.draw() function.
public void draw() {
this.texture.bind();
GL11.glLoadIdentity();
GL11.glTranslatef(0, 0, 0);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 480 - height);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(640, 480 - height);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(640, 480);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(0, 480);
GL11.glEnd();
}
Also, if you'll note above I have a GL11.glTranslatef call. I can get my ground texture in the right position if I simply make the 2nd argument for this function large enough to displace it further in the y direction, however I don't wish to do it this way. I really don't know how the texture ended up in this location in the first place, and I would like to figure out why.
I think there is a problem with your matrices :
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, gameWidth, gameHeight, 0, 1, -1);
I never really used OpenGL fixed pipeline but what I see or actually DON"T SEE is where you multiply your matrices. You must multiply the model matrix of your quad with projection matrix which is glOrtho(). ( glPushMatrix/glPopMatrix )
So in your scenario you should :
Push Ortho matrix.
Push camera(view) matrix (if exists).
Push Model Matrix.
Pop Model Matrix.
Pop camera (view) matrix (if exists).
Pop Ortho matrix.
If the Ortho never changes I think you need to push it only once.
Also make sure you take into account ortho coordinates changes because depending on glOrtho() setup the world center going to be different from the center of the screen.Usually top left or bottom left corner.
The bottom line is : while I don't recommend you using the old and deprecated OpenGL at all, you should take a look how the transformations are done the right way in the numerous online tutorials.Also here
Im currently making a sidescroller game which uses randomly generated terrain that scrolls in the background. The terrain is basically an instance of the GeneralPath class. When the terrain generates, the corners (0, 0) and (width, 0) are included in the path since the height of the viewing canvas isnt known yet. To make the terrain appear right-side-up, i added the following lines of code:
g.translate(0, getHeight());
g.scale(0, -1);
This should flip the coordinate system into Cartesian format with the bottom left being 0, 0.
For some reason, the terrain isnt drawing. When i comment-out these lines, it works, but is upside-down. If i only comment out the scale command and change the amount translated by to a smaller number, it also draws successfully (upside-down and translated a small amount).
Thanks in advance!
As you noticed, you need to scale the x axis as well - g.scale(1, -1);