6
votes

I'm trying to draw a basic 2d ground mesh made up of smaller tiles from a texture atlas (note the 1 pixel transparent border):

enter image description here

I render the tiles as texture quads using the following code:

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(2, GL_SHORT, 0, &m_coords[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &m_uvs[0]);

glDrawArrays(GL_TRIANGLES, 0, m_coords.size() / 2);

glBindTexture(GL_TEXTURE_2D, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);

The positions are obviously integer coordinates. The UV coordinates for the corners are calculated like this:

u0 = float(x) / float(texWidth);
v0 = float(y) / float(texHeight);
u1 = float(x+w) / float(texWidth);
v1 = float(y+h) / float(texHeight);

Where w and h is the size of the tile without the padding.

It looks great when the modelview transform is snapped to an integer position (right), but when it starts to move I get black thingies between the tiles (left):

enter image description here

From what I understand I should offset the UV coordinates with a half texel to make it work, but if I change the UV calculations to:

u0 = float(x+0.5f) / float(texWidth);
v0 = float(y+0.5f) / float(texHeight);
u1 = float(x+w-0.5f) / float(texWidth);
v1 = float(y+h-0.5f) / float(texHeight);

It still doesn't work. Is this the correct way to do it? Do I need blending for this to work? If I offset the tiles to make sure they're snapped to the pixel grid it works, but that makes it snap when moving slowly. How do people usually solve this?

EDIT

I should ofc have said that it's on the iphone.

5
Fixed-function or programmable pipeline?genpfault
Obvious questions first, are you taking those borders into account when generating the UVs? Seems like they'd be good to get rid of, just duplicate the tile's edge pixels out.ssube
@genpfault It's fixed function on the iphone.user408952
@peachykeen yes, the first 64x64 tile is positioned at 1,1 so the UVs will go from (1/1024,1/1024) to ((1+64)/1024, (1+64)/1024), if the whole texture is 1024. Do you think that duplicating the border pixels instead of adding transparency will work better?user408952
My guess is it's related to filtering, pixel->voxel mapping, or something along those lines. If so, duplicating them will hide the issue, if no other fix is available. Before you resort to that, though, try to make sure your uv coords and filtering line up properly.ssube

5 Answers

6
votes

Your border shouldn't be transparent, but rather the pixels from the opposing side of each subtexture. For example the border on the right hand side of each sub-texture should be a copy of the left-most line of pixels, i.e. the pixels that it would wrap around to.

That is how you "cheat" wrapping for the texture sampler on the borders.

2
votes

I had a similar issue with a texture atlas. I fixed it by insetting the image by 1.0/TEXTURE_ATLAS_PIXELS_PER_SIDE * 1/128.0. The 128 number you need to figure out by experimentation. The upside for me is no one is going to perceive 128th of a pixel being missing. I made this modification to the texture coordinates being sent to the graphics card and not in a shader. I have not tried doing this with texels in the shader, like you have. I've read different information on how to handle texture bleeding but for a texture atlas this was the easiest solution for me. Adding borders to my textures which are tightly packed and follow the power of two rule would cause me to have a lot of whitespace.

This is what worked for me on the iphone.

0
votes

You could always switch your GL_TEXTURE_MIN/MAG_FILTER to GL_NEAREST :)

0
votes

Try using GL_NEAREST for GL_TEXURE_MIN/MAX_FILTER and translate by 0.375f before drawing:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375f, 0.375f, 0.0f);
-2
votes

I had this exact same problem. I fixed it with this.

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);