# Texture coordinate discontinuity with mipmaps creates seams

I just started learning openGL and I am getting this artifact when texturing a sphere with mipmaps. Basically when the fragment samples the edge of my texture, it detects the discontinuity (say from 1 to 0) and picks the smallest mipmap, which creates this ugly seam:

//fragVert is the original vertex from the vertex shader
vec2 ll = vec2((atan(fragVert.y, fragVert.x) / 3.1415926 + 1.0) * 0.5, (asin(fragVert.z) / 3.1415926 + 0.5));
vec2 ll2 = ll;
if (ll.x < 0.01 || ll.x > 0.99)
ll2.x = .5;
vec4 surfaceColor = textureGrad(material.tex, ll, dFdx(ll2), dFdy(ll2));


Now I get two seams instead of one. How can I get rid of them? And why does the code above generate 2 seams?

2 eams http://cdn.imghack.se/images/44a38ef13cc2cdd801967c9223fdd2d3.png

You can't tell from the two images but the 2 seams are on either side of the original seam.

• Is your sphere a mesh, or are you raytracing the sphere analytically in the shader or suchlike? If it's a mesh, people usually solve this by duplicating the vertices along the seam so that the verts on one side can have u = 0 and the other side have u = 1. Commented May 31, 2013 at 23:30
• As for why your code generates two seams, I expect it's because it's creating two discontinuities - one where u jumps from 0.01 to 0.5, and one where u jumps from 0.99 to 0.5. It's the same problem as when u jumps from 0 to 1 - not as large of a jump but still a big jump. Commented May 31, 2013 at 23:32
• I have a mesh for the sphere. It's a decahedron so the vertices don't line up to the seam. The funny thing about the two seams is the original seam is gone. Also, I get the same 2 seams even if I clamp it to .01 or .99. Commented Jun 1, 2013 at 0:26
• Can you post a screenshot of the two-seams case? And, how are you generating the UVs (can you post the relevant part of your code)? I presume you are generating them procedurally in the shader, not just interpolating them from the vertices, else your dodecahedron mesh wouldn't work at all. Commented Jun 1, 2013 at 0:31
• I updated the question with a picture of the 2 seams, they're either side of the original seam, but the original seam isn't there . I think the the UV are interpolated from the vertices, not sure. The code is in the question now. Commented Jun 1, 2013 at 2:57

Based on the shader code you posted, you're not interpolating the UVs from the vertices - rather it appears you're interpolating the 3D position (fragVert), then calculating the UVs by transforming to spherical coordinates.
A relatively simple approach to fix the problem would be to decide which mip level to use yourself and call textureLod to sample it directly. If the planet is always going to be fairly close to the camera, you could just hard-code the mip level to 0 (or, for that matter, just not include mip levels in the texture at all). Otherwise, it could be based on the log2 of the point's distance from the camera, scaled by some suitable factors. Note that this will effectively disable anisotropic filtering.
A more "correct" approach would be to calculate some higher-quality derivatives. Instead of using dFdx and dFdy on the UVs, which have discontinuities due to the atan2, you could apply dFdx and dFdy to fragVert (which will be continuous all the way around the sphere), then use some calculus (chain rule) to find the formula to get the UV derivatives from the position derivatives. This will be more complicated and slower, but has the advantage that anisotropic filtering should work.