Concerning graphical glitch in 2d tile rendering [SOLVED]

Started by W0x, January 26, 2012, 23:13:11

Previous topic - Next topic

W0x

Hi everyone,

I'm programming a simple game using the LWJGL. The game uses a tile-based map.

I implemented an Atlas for my tile textures and wrote some code to generate the proper texture coordinates.

Now, this all seems to be working perfectly fine. The right textures are loaded every time and no bleeding occurs.
When I scroll the map, however, (I do this by translating the scene over a PAN_X and PAN_Y variable), some strange graphical glitches occurr every now and then. I have attached a screenshot of the problem. (the screenshot is of low quality, just a compression result, you will clearly see the graphical glitch I refer to, though.)

Does this look familiar to anyone? What could cause this phenomenon?

I call the general rendering routine as follows:

GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		
		GL11.glPushMatrix();
		
		Texture texture = TextureUtils.ATLAS;
		texture.bind();
		
		world.renderTiles();
		
		GL11.glPopMatrix();


The tiles are then rendered as such:

GL11.glPushMatrix();
		
		GL11.glTranslatef(PAN_X, PAN_Y, 0f);
		GL11.glScalef(World.ZOOM, World.ZOOM, 0f);
		
		for (int y = tileY0; y < tileY1; y++)
		{
			for (int x = tileX0; x < tileX1; x++)
			{
				if ((x > MAP_SIZE-1) || (y > MAP_SIZE-1) || (x < 0) || (y < 0))
				{
					// Do not render
				}
				else
				{
					GraphicsUtils.renderTileGraphic(tiles[x][y]);
				}
			}
		}
		
		GL11.glPopMatrix();


I use the following basic rendering code for the tiles:

public static void renderTileGraphic(IRenderable renderObject)
	{
		int x = renderObject.getLocation().x;
		int y = renderObject.getLocation().y;
		
		Point coordinates = TextureUtils.getTileTextureCoordinates(renderObject.getTexture());
		
		double tx0 = coordinates.x*TextureUtils.TEXTURE_STEP_TILE;
		double tx1 = (coordinates.x+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		double ty0 = coordinates.y *TextureUtils.TEXTURE_STEP_TILE;
		double ty1 = (coordinates.y+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		GL11.glPushMatrix();
		
		GL11.glTranslatef(x, y, 0);
		GL11.glRotatef(renderObject.getRotation(), 0f, 0f, 1f);
		GL11.glTranslatef(-x, -y, 0);
		
		GL11.glBegin(GL11.GL_QUADS);
		    GL11.glTexCoord2d(tx0,ty0);
			GL11.glVertex2d(x - (renderObject.getWidth()/2), y - (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx0,ty1);
			GL11.glVertex2d(x - (renderObject.getWidth()/2), y + (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty1);
			GL11.glVertex2d(x + (renderObject.getWidth()/2), y + (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty0);
			GL11.glVertex2d(x + (renderObject.getWidth()/2), y - (renderObject.getHeight()/2));
		GL11.glEnd();
		
		GL11.glPopMatrix();	
	}

Fool Running

That artifact is typically caused by some vertexes of your polygon not being in the correct place (i.e. they got calculated to be off the screen somewhere).
This code looks suspicious:
GL11.glTranslatef(x, y, 0);
		GL11.glRotatef(renderObject.getRotation(), 0f, 0f, 1f);
		GL11.glTranslatef(-x, -y, 0);

Is there a reason you translate to the location of the tile before rotating it?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

W0x

Quote
That artifact is typically caused by some vertexes of your polygon not being in the correct place (i.e. they got calculated to be off the screen somewhere).
This code looks suspicious:
GL11.glTranslatef(x, y, 0);
		GL11.glRotatef(renderObject.getRotation(), 0f, 0f, 1f);
		GL11.glTranslatef(-x, -y, 0);


Is there a reason you translate to the location of the tile before rotating it?

Thanks for your reply.

Perhaps this is the result of my own in-experience. The way I understood it I need to translate the matrix to the position of the rendering object before rotating to ensure it rotates around its own axis, and not around some arbitrary other point (pivoting).

Is this assumption incorrect?

CodeBunny

Actually, why do you rotate at all? It looks like your tiles don't need to rotate; you're wasting a call on something you don't use.

W0x

Very true, I should remove that part for tile rendering (the code was meant to be as generic as possible, hence the interface as an argument to the method). Did I go about the rotation wrong, though? Could this cause the glitches I'm seeing?

CodeBunny

I'm not sure.

No offense, but your render method is very ugly and slow. That's understandable, I assume you're starting out with LWJGL programming - we've all been there. I would look up general tutorials and tips on how to draw a large tilemap.

Fool Running

Quote from: W0x on January 27, 2012, 14:49:30
Thanks for your reply.

Perhaps this is the result of my own in-experience. The way I understood it I need to translate the matrix to the position of the rendering object before rotating to ensure it rotates around its own axis, and not around some arbitrary other point (pivoting).

Is this assumption incorrect?
Yes, normally you want to translate before rotating, but you are not using the translation (you are un-translating right after the rotation). In essence you are translating after the rotation because you are doing the un-translating. I think this might be causing your problem. A quick way to check if this is, indeed, your problem is to comment out those 3 lines and see if the glitches go away.

EDIT: To get more of what you are probably looking for, you probably need to do something like:
public static void renderTileGraphic(IRenderable renderObject)
	{
		int x = renderObject.getLocation().x;
		int y = renderObject.getLocation().y;
		
		Point coordinates = TextureUtils.getTileTextureCoordinates(renderObject.getTexture());
		
		double tx0 = coordinates.x*TextureUtils.TEXTURE_STEP_TILE;
		double tx1 = (coordinates.x+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		double ty0 = coordinates.y *TextureUtils.TEXTURE_STEP_TILE;
		double ty1 = (coordinates.y+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		GL11.glPushMatrix();
		
		GL11.glTranslatef(x, y, 0);
		GL11.glRotatef(renderObject.getRotation(), 0f, 0f, 1f);
		
		GL11.glBegin(GL11.GL_QUADS);
		    GL11.glTexCoord2d(tx0,ty0);
			GL11.glVertex2d(-(renderObject.getWidth()/2), -(renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx0,ty1);
			GL11.glVertex2d(-(renderObject.getWidth()/2), (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty1);
			GL11.glVertex2d((renderObject.getWidth()/2), (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty0);
			GL11.glVertex2d((renderObject.getWidth()/2), -(renderObject.getHeight()/2));
		GL11.glEnd();
		
		GL11.glPopMatrix();	
	}
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

W0x

Quote from: CodeBunny on January 27, 2012, 17:13:16
I'm not sure.

No offense, but your render method is very ugly and slow. That's understandable, I assume you're starting out with LWJGL programming - we've all been there. I would look up general tutorials and tips on how to draw a large tilemap.

You do indeed assume correctly. I do not feel that it is appropriate to post this type of response, though.
Constructive critisism only, please.

W0x

Quote from: Fool Running on January 27, 2012, 17:13:48
Quote from: W0x on January 27, 2012, 14:49:30
Thanks for your reply.

Perhaps this is the result of my own in-experience. The way I understood it I need to translate the matrix to the position of the rendering object before rotating to ensure it rotates around its own axis, and not around some arbitrary other point (pivoting).

Is this assumption incorrect?
Yes, normally you want to translate before rotating, but you are not using the translation (you are un-translating right after the rotation). In essence you are translating after the rotation because you are doing the un-translating. I think this might be causing your problem. A quick way to check if this is, indeed, your problem is to comment out those 3 lines and see if the glitches go away.

EDIT: To get more of what you are probably looking for, you probably need to do something like:
public static void renderTileGraphic(IRenderable renderObject)
	{
		int x = renderObject.getLocation().x;
		int y = renderObject.getLocation().y;
		
		Point coordinates = TextureUtils.getTileTextureCoordinates(renderObject.getTexture());
		
		double tx0 = coordinates.x*TextureUtils.TEXTURE_STEP_TILE;
		double tx1 = (coordinates.x+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		double ty0 = coordinates.y *TextureUtils.TEXTURE_STEP_TILE;
		double ty1 = (coordinates.y+1)*TextureUtils.TEXTURE_STEP_TILE;
		
		GL11.glPushMatrix();
		
		GL11.glTranslatef(x, y, 0);
		GL11.glRotatef(renderObject.getRotation(), 0f, 0f, 1f);
		
		GL11.glBegin(GL11.GL_QUADS);
		    GL11.glTexCoord2d(tx0,ty0);
			GL11.glVertex2d(-(renderObject.getWidth()/2), -(renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx0,ty1);
			GL11.glVertex2d(-(renderObject.getWidth()/2), (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty1);
			GL11.glVertex2d((renderObject.getWidth()/2), (renderObject.getHeight()/2));
			
			GL11.glTexCoord2d(tx1,ty0);
			GL11.glVertex2d((renderObject.getWidth()/2), -(renderObject.getHeight()/2));
		GL11.glEnd();
		
		GL11.glPopMatrix();	
	}


Thanks, I was at work earlier and did not have the change to try it. I'll mess around with it for a bit more and hopefully fix my problems. :)

W0x

My problem was fixed when I loaded the map into video-card memory using Display Lists. The framerate has obviously increased, but as a friendly side-effect the graphical glitching is gone. :)