2014-06-24 9 views
6

Wie kann ich feststellen, welche Mipmap-Ebene beim Abtasten einer Textur in einem GLSL-Fragment-Shader verwendet wurde?Zugriff auf automatische Mipmap-Ebene in der GLSL-Fragment-Shader-Textur?

Ich verstehe, dass ich manuell einen bestimmten Mipmapstufe einer Textur mit der textureLod(...) Methode probieren können:

uniform sampler2D myTexture; 

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

Oder ich könnte die Mipmapstufe erlauben werden ausgewählte texture(...) wie

automatisch
uniform sampler2D myTexture; 

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

Ich ziehe das letztere vor, weil ich dem Urteil des Fahrers über den richtigen Mipmap-Level mehr vertraue als meinem eigenen.

Aber ich würde gerne wissen, welche Mipmap-Ebene in der automatischen Sampling-Prozess verwendet wurde, um mir rational Probe in der Nähe von Pixeln zu helfen. Gibt es einen Weg in GLSL, um auf Informationen darüber zuzugreifen, welche Mipmap-Ebene für ein automatisches Texturmuster verwendet wurde?

+6

Auf welche Version von GLSL zielen Sie? GLSL 4.00 unterstützt ['textureQueryLod (...)'] (https://www.opengl.org/sdk/docs/man/html/textureQueryLod.xhtml), was genau das tut, was Sie wollen. –

Antwort

17

Im Folgenden drei verschiedene Ansätze für dieses Problem sind, je nachdem, welche OpenGL-Funktionen zur Verfügung stehen:

  1. Wie in den Kommentaren von Andon M. Coleman gezeigt, ist die Lösung in OpenGL Version 4.00 und höher einfach; benutzen Sie einfach die textureQueryLod Funktion: eine Erweiterung zu laden, um eine ähnliche Wirkung

    #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. In früheren Versionen von OpenGL (? 2.0+), könnten Sie in der Lage sein. Dieser Ansatz hat für meinen Fall funktioniert. HINWEIS: Der Methodenaufruf wird in der Erweiterung anders als im integrierten Format (queryTextureLod vs queryTextureLOD) unterschiedlich groß geschrieben.

    #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. die Verlängerung Wenn das Laden nicht funktioniert, könnten Sie Schätzung die automatische Detailgrad der Ansatz mit Beiträgen 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); 
    } 
    

Auf jeden Fall für meine besondere Anwendung, ich am Ende nur die Mipmap-Ebene auf der Host-Seite zu berechnen, und übergab es an den Shader, weil die automatische Detaillierung erwies sich als nicht genau das, was ich brauchte.

+0

Ein paar Fragen, wenn ich darf: Könnte dies mit dFdx und dFdy-Werten aus den normalisierten UV-Texturkoordinaten allein gemacht werden? Warum brauche ich die Ergebnisse für dFdx und dFdy als 2-dimensionale Variablen? (Wenn alles, was ich brauche, die Ableitung/Änderung entlang der U- oder V-Koordinate ist - würde kein regulärer Gleitkomma ausreichen?) Welche Werte (Codomain) bekomme ich von dFdx und dFdy, wenn ich diese Funktionen auf die normalisierte UV-Textur anwende Koordinaten? - Würden das etwa 0, 1, 1/2, 1/4, 1/8 ...... 1/4096 sein? – Nims

+0

@Nims Die normalisierten UV-Koordinaten sind unzureichend, da die fehlende Information darüber, wie fein die Textur ist, ist; Informationen entscheidend für die Auswahl der optimalen Mipmap-Ebene. dFdx und dFdy sind zweidimensional, da die Texturkoordinate zweidimensional ist. Wie Sie sagten, brauchen Sie nur die Ableitung entlang der Koordinate "U OR V". So gibt es euch beide. Beantwortet das eine Ihrer Fragen? –

+0

Danke für die Antwort, aber ich verstehe immer noch nicht, warum die Ableitungen 2 Dimensionen sind, sagen wir zum Beispiel ddx misst nur die Änderung entlang der U-Koordinate, es würde keine Änderung entlang der V-Koordinate geben, also für dx_vtc - der zweite Wert wäre Null. Sonst was ist der Punkt in beiden ddx und ddy? – Nims

7

Von here:

werfen Sie einen Blick auf die OpenGL 4.2 spec Kapitel 3.9.11 Gleichung 3.21. Die MIP-Map-Ebene basiert auf der Länge der Ableitung Vektoren berechnet:

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); 
} 
+0

Danke, dass Sie das gefunden haben. Ich schaute auf die Spezifikation, und leider scheint es ein wenig Spielraum in der tatsächlichen Implementierung zu verlassen, so dass diese Methode nicht genau das ist, was verwendet wird. Außerdem berücksichtigt es nicht die Einstellungen von GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD. Beachten Sie, dass die texture_coordinate in Ihrem Snippet nicht normalisiert sein sollte, d. H. In Pixel, nicht nur (0,1).Dies ist ein guter Anfang für mich, LOD manuell zu spezifizieren. Aber ich wünschte, ich hätte eine Möglichkeit, auf den internen automatischen LOD-Wert zuzugreifen. –

+0

@ChristopherBruns: Sie könnten etwas tun * wirklich * kitschig: füllen Sie eine Dummy-Textur mit verschiedenen Volltonfarben/Werte für jede Mip-Ebene, probieren Sie es aus und konvertieren Sie die Farbe/Wert wieder auf die Mip-Ebene :) – genpfault

+2

Eigentlich, wenn wir es sind Wenn man plötzlich über GL 4.x spricht, wurde ['textureQueryLod (...)'] (https://www.opengl.org/sdk/docs/man/html/textureQueryLod.xhtml) genau aus diesem Grund erstellt. Wie die meisten impliziten LOD-Texturfunktionen funktioniert es nur im Fragment-Shader, da es einen Bildschirm-Raum-Gradienten (partielle Ableitung) benötigt, um die entsprechende Mipmap-LOD zu berechnen. –

Verwandte Themen