Reputation: 932
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):
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):
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.
Upvotes: 7
Views: 7306
Reputation: 9079
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.
Upvotes: 2
Reputation: 130
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);
Upvotes: 0
Reputation: 7488
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.
Upvotes: 6
Reputation: 52155
You could always switch your GL_TEXTURE_MIN/MAG_FILTER
to GL_NEAREST
:)
Upvotes: 0