如何在GLSL片段着色器纹理中访问自动mipmap级别?

Chr*_*uns 11 opengl textures glsl mipmaps fragment-shader

在GLSL片段着色器中对纹理进行采样时,如何确定使用的mipmap级别?

我知道我可以使用以下textureLod(...)方法手动采样纹理的特定mipmap级别:

uniform sampler2D myTexture;

void main()
{
    float mipmapLevel = 1;
    vec2 textureCoord = vec2(0.5, 0.5);
    gl_FragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
Run Code Online (Sandbox Code Playgroud)

或者我可以允许使用texture(...)like 自动选择mipmap级别

uniform sampler2D myTexture;

void main()
{
    vec2 textureCoord = vec2(0.5, 0.5);
    gl_FragColor = texture(myTexture, textureCoord);
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢后者,因为我相信司机对合适的mipmap级别的判断比我自己的更多.

但我想知道在自动采样过程中使用了什么mipmap级别,以帮助我合理地对附近的像素进行采样.GLSL中是否有一种方法可以访问有关自动纹理样本使用的mipmap级别的信息?

Chr*_*uns 23

以下是此问题的三种不同方法,具体取决于您可以使用的OpenGL功能:

  1. 正如Andon M. Coleman在评论中指出的那样,OpenGL 4.00及以上版本的解决方案很简单; 只需使用该textureQueryLod功能:

    #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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在早期版本的OpenGL(2.0+?)中,您可以加载扩展,以达到类似的效果.这种方法适用于我的情况.注意:方法调用在扩展中与内置(queryTextureLodvs 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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果加载扩展程序不起作用,您可以使用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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

在任何情况下,对于我的特定应用程序,我最终只是计算主机端的mipmap级别,并将其传递给着色器,因为自动细节级别不是我所需要的.


gen*_*ult 10

从这里:

看一下OpenGL 4.2规范章节3.9.11公式3.21.基于导数向量的长度计算mip贴图级别:

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,如果我们突然讨论GL 4.x,那么[`textureQueryLod(...)`](https://www.opengl.org/sdk/docs/man/html/textureQueryLod.xhtml)就是精确创建的这个原因.像大多数隐式LOD纹理函数一样,它只能在片段着色器中工作,因为它需要一个屏幕空间渐变(偏导数)来计算相应的mipmap LOD. (2认同)