web-dev-qa-db-ja.com

GLSLフラグメントシェーダーテクスチャで自動ミップマップレベルにアクセスするにはどうすればよいですか?

GLSLフラグメントシェーダーでテクスチャをサンプリングするときに使用されたミップマップレベルを確認するにはどうすればよいですか?

textureLod(...)メソッドを使用して、テクスチャの特定のミップマップレベルを手動でサンプリングできることを理解しています。

_uniform sampler2D myTexture;

void main()
{
    float mipmapLevel = 1;
    vec2 textureCoord = vec2(0.5, 0.5);
    gl_FragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
_

または、texture(...)を使用してミップマップレベルを自動的に選択できるようにすることもできます。

_uniform sampler2D myTexture;

void main()
{
    vec2 textureCoord = vec2(0.5, 0.5);
    gl_FragColor = texture(myTexture, textureCoord);
}
_

私は後者の方が好きです。なぜなら、私は自分よりも適切なミップマップレベルに関するドライバーの判断を信頼しているからです。

しかし、近くのピクセルを合理的にサンプリングするために、自動サンプリングプロセスで使用されたミップマップレベルを知りたいのですが。自動テクスチャサンプルに使用されたミップマップレベルに関する情報にアクセスする方法はGLSLにありますか?

11

以下は、利用可能なOpenGL機能に応じて、この問題に対する3つの異なるアプローチです。

  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);
    }
    
  2. OpenGLの以前のバージョン(2.0以降?)では、同様の効果で拡張機能をロードできる場合があります。このアプローチは私の場合にはうまくいきました。 [〜#〜] note [〜#〜]:メソッド呼び出しは、拡張機能と組み込み(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);
    }
    
  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);
    }
    

いずれにせよ、私の特定のアプリケーションでは、ホスト側でミップマップレベルを計算し、それをシェーダーに渡すだけでした。自動詳細レベルが正確に必要なものではないことが判明したためです。

23

から ここ

OpenGL 4.2仕様 第3.9.11章の式3.21を見てください。ミップマップレベルは、微分ベクトルの長さに基づいて計算されます。

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);
}
10
genpfault