# What is causing these texture edge artifacts on some video cards?

I have a 2d heightfield converted into a very simple mesh and textured with tiles from a texture atlas. The tiles texture is drawn with:

glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);


On my integrated Intel card, it draws as I intend (top picture). On a friend's ATI card, it has very visible edges (bottom picture).

What causes this, and how can I avoid it?

Extra info:

• glColor4f(1,1,1,1) has been called before drawing the mesh
• the texture atlas is a simple vertical strip, so the right-side of each tile has x=1.0f
• the vertices are being shared so there isn't really a 'hole' between my rows
• the resolution on both systems is the same
• the vertices and texture coordinates are all passed as GL_FLOAT
• the tiles atlas is mipmapped
• Looks like a problem with your UV's, could it be a prescision problem on your friend's graphics card? Have your tried outputting your UV's to the fragment colour? – Jonathan Connell Aug 22 '11 at 10:11
• Interesting that edges are seen only in 1 direction. Maybe it can give you a clue? – Kromster Aug 22 '11 at 12:05

At a guess you should be using GL_CLAMP_TO_EDGE instead of GL_CLAMP. I don't have an Intel to verify on but I suspect that the ATI is actually the one doing the right thing (OpenGL on Intel can suck badly - their drivers are notorious).

Try using GL_CLAMP_TO_EDGE. The GL spec says, that GL_CLAMP clamps to [0,1], so you get problems at the edge where the border color gets in, whereas GL_CLAMP_TO_EDGE clamps to [0.5/size, 1-0.5/size], which is what you want, as GL returns exact texel values at the texel center.

I think the ATI is right, as it uses the border color for values out of the valid texture range. which would either dim the edge region (when filtering linear) or make one side completely black (the default border color) when using nearest neighbour filtering. Or maybe on the Intel you just don't get exact 1.0, so in nearest filtering you still get the last valid texel. In either case, you are on the safe side with using GL_CLAMP_TO_EDGE.