Mipmap are generated with glComputeMipmap(). Mipmap value are right (I have checked their values with texelFetch).
WRAP_S and WRAP_T are set with CLAMP with “fract(texCoord)” in shader. I have done some test with CLAMP_TO_EDGE and CLAMP_TO_BORDER but results are the same.
I have no idea where I’ve done a mistake. Any ideas ?
These coordinate are interpolated just before fragment shader. So when you are in fragment shader, your texture coordinate are in interval [0.0,1.0]. Aren’t they?
That’s why I don’t understand why you say texture coordinates processed with fract (transformed in [0.0,1.0[) cross the border.
What is this interval : [texelsize/2,1-texelsize/2] ?
Inclusive or exclusive does not mean a lot with floats.
It is just that fract() returns only the fractional part, 0.0 inclusive, 1.0 exclusive. Whatever.
Read a bit about the different clamp modes : texcoord 0.0 is in fact between the edge texel E (the first one you define) and the border texel B (either defined explicitely with border=1 or indirectly with border color). By default border color is black. So for a pure white texture, naive GL_CLAMP with let some 50% grey at texcoord 0.0 and 1.0. GL_CLAMP_TO_EDGE clamps texcoord earlier (half a texel) to prevent this color bleeding. GL_REPEAT does not have this problem, as the B texel is in fact the E texel from the opposite side of the texture.
You need exactly a combination of GL_REPEAT with GL_CLAMP_TO_EDGE.
Using fract leads to the artefacts you see because it messes up the texcoord derivatives. The texture unit uses these to determine the texture level of detail that should be used.
When you use fract, the relatively small step between e.g. 0.99 and 1.01 (+0.02) becomes a step from 0.99 to 0.01, i.e. -0.98. If this happens between two neighbouring fragments, the GL implementation will believe that you want to map almost the entire texture in between those two fragments. In order to avoid aliasing it will then select the lowest resolution mipmap level. That’s what causes those grey pixels.
There are a number of things you could do, however before I suggest one it would be good if you could explain what the coefficients represent, why you can’t interpolate them across texture edges, and how you intend to deal with the discontinuity edge that will inevitably arise from repeating the texture without filtering across edges.
If you absolutely need to use fract(), then what you’ll have to do is to compute the mipmap level yourself, then sample the texture manually for that level. Here’s an example that should set you on the right track:
/// This function evaluates the mipmap LOD level for a 2D texture using the given texture coordinates
/// and texture size (in pixels)
float mipmapLevel(vec2 uv, vec2 textureSize)
{
vec2 dx = dFdx(uv * textureSize.x);
vec2 dy = dFdy(uv * textureSize.y);
float d = max(dot(dx, dx), dot(dy, dy));
return 0.5 * log2(d);
}
...
float lod = mipmapLevel(uv, 1024.0);
vec4 col = texture2DLod(tex, fract(uv), lod);
There are a number of things you could do, however before I suggest one it would be good if you could explain what the coefficients represent, why you can’t interpolate them across texture edges, and how you intend to deal with the discontinuity edge that will inevitably arise from repeating the texture without filtering across edges.
I store some spherical harmonics (SH) in texture. I have two kinds of texture :
[li]Spatial SH textures : Store SH coefficients per position (actually texel position : s,t) on quad. []Angular SH textures : Store SH coefficients per spherical coordinates (theta[0,PI/2],phi[0,2PI]) (for half vector).
For these textures, I would like trilinear interpolation inside textures but not on border.
Pictures above show artifact on spatial textures. I haven’t mentionned it before, but I have same artifacts with angular textures when phi is around 2*PI.