How do I determine what mipmap level was used when sampling a texture in a GLSL fragment shader?
I understand that I can manually sample a particular mipmap level of a texture using the textureLod(...)
method:
uniform sampler2D myTexture;
void main()
{
float mipmapLevel = 1;
vec2 textureCoord = vec2(0.5, 0.5);
gl_FragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
Or I could allow the mipmap level to be selected automatically using texture(...)
like
uniform sampler2D myTexture;
void main()
{
vec2 textureCoord = vec2(0.5, 0.5);
gl_FragColor = texture(myTexture, textureCoord);
}
I prefer the latter, because I trust the driver's judgment about appropriate mipmap level more than I do my own.
But I'd like to know what mipmap level was used in the automatic sampling process, to help me rationally sample nearby pixels. Is there a way in GLSL to access the information about what mipmap level was used for an automatic texture sample?
If the sampler is not using anisotropic filtering, the mipmap level is chosen by considering the gradient vector with the highest magnitude and finding a mipmap level where the texel size best fits that vector.
A mipmap is a sequence of textures, each of which is a progressively lower resolution representation of the same image. The height and width of each image, or level, in the mipmap is a power of two smaller than the previous level.
in display() function : GLuint texture; texture = LoadTexture("bubble. png"); glBindTexture(GL_TEXTURE_2D, texture);
Make sure that you use mipmapping. This is because mipmapping improves both performance and quality. Mipmapping improves the performance of the GPU. This is because the GPU does not need to render the full resolution texture on an object that is far away from the camera.
Below are three distinct approaches to this problem, depending on which OpenGL features are available to you:
As pointed out by Andon M. Coleman in the comments, the solution in OpenGL version 4.00 and above is simple; just use the textureQueryLod
function:
#version 400
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
void main()
{
float mipmapLevel = textureQueryLod(myTexture, textureCoord).x;
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
In earlier versions of OpenGL (2.0+?), you might be able to load an extension, to similar effect. This approach worked for my case. NOTE: the method call is capitalized differently in the extension, vs. the built-in (queryTextureLod
vs queryTextureLOD
).
#version 330
#extension GL_ARB_texture_query_lod : enable
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
void main()
{
float mipmapLevel = 3; // default in case extension is unavailable...
#ifdef GL_ARB_texture_query_lod
mipmapLevel = textureQueryLOD(myTexture, textureCoord).x; // NOTE CAPITALIZATION
#endif
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
If loading the extension does not work, you could estimate the automatic level of detail using the approach contributed by genpfault:
#version 330
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
// Does not take into account GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD/GL_TEXTURE_LOD_BIAS,
// nor implementation-specific flexibility allowed by OpenGL spec
float mip_map_level(in vec2 texture_coordinate) // in texel units
{
vec2 dx_vtc = dFdx(texture_coordinate);
vec2 dy_vtc = dFdy(texture_coordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
float mml = 0.5 * log2(delta_max_sqr);
return max( 0, mml ); // Thanks @Nims
}
void main()
{
// convert normalized texture coordinates to texel units before calling mip_map_level
float mipmapLevel = mip_map_level(textureCoord * textureSize(myTexture, 0));
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
In any case, for my particular application, I ended up just computing the mipmap level on the host side, and passing it to the shader, because the automatic level-of-detail turned out to be not exactly what I needed.
From here:
take a look at the OpenGL 4.2 spec chapter 3.9.11 equation 3.21. The mip map level is calculated based on the lengths of the derivative vectors:
float mip_map_level(in vec2 texture_coordinate) { vec2 dx_vtc = dFdx(texture_coordinate); vec2 dy_vtc = dFdy(texture_coordinate); float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); return 0.5 * log2(delta_max_sqr); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With