2014-06-24 35 views
6

Come determinare quale livello di mipmap è stato utilizzato durante il campionamento di una trama in uno shader di frammenti GLSL?Come accedere al livello mipmap automatico nella trama dello shader del frammento GLSL?

ho capito che posso provare manualmente un particolare livello mipmap di una texture con il metodo textureLod(...):

uniform sampler2D myTexture; 

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

Oppure potrei permettere il livello di mipmap da selezionare automaticamente utilizzando texture(...) come

uniform sampler2D myTexture; 

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

Preferisco quest'ultimo, perché mi fido del giudizio del guidatore sul livello appropriato di mipmap più di quanto non faccia mio.

Ma mi piacerebbe sapere quale livello di mipmap è stato utilizzato nel processo di campionamento automatico, per aiutarmi a campionare razionalmente i pixel vicini. C'è un modo in GLSL per accedere alle informazioni su quale livello di mipmap è stato utilizzato per un campione di texture automatico?

+6

Quale versione di GLSL stai prendendo di mira? GLSL 4.00 supporta ['textureQueryLod (...)'] (https://www.opengl.org/sdk/docs/man/html/textureQueryLod.xhtml), che fa esattamente quello che vuoi. –

risposta

17

Qui di seguito sono tre approcci distinti a questo problema, a seconda che sono disponibili funzioni OpenGL per voi:

  1. Come sottolineato da Andon M. Coleman nei commenti, la soluzione in OpenGL versione 4.00 e successive è semplice; basta usare la funzione 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. Nelle versioni precedenti di OpenGL (? 2.0+), si potrebbe essere in grado di caricare l'estensione, in senso analogo. Questo approccio ha funzionato per il mio caso. NOTA: la chiamata al metodo è maiuscola in modo diverso nell'estensione, rispetto a quella incorporata (queryTextureLod rispetto a 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. Se si carica l'estensione non funziona, si potrebbe stima il livello automatico di dettagli utilizzando l'approccio contributo di 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 ogni caso, per il mio particolare applicazione, ho finito per calcolare il livello mipmap sul lato host e passarlo allo shader, perché il livello automatico di dettaglio non era esattamente quello di cui avevo bisogno.

+0

Alcune domande se posso: Questo potrebbe essere fatto usando i valori dFdx e dFdy dalle sole coordinate UV normalizzate? Perché sono necessari i risultati per dFdx e dFdy per essere 2 variabili di dimensione? (Se tutto ciò di cui ho bisogno è la derivata/modifica lungo la coordinata U o V - un float regolare non è sufficiente?) Che tipo di valori (Codomain) ottengo da dFdx e dFdy quando si applicano queste funzioni alla trama UV normalizzata coordinate? - Sarebbero qualcosa come 0, 1, 1/2, 1/4, 1/8 ...... 1/4096? – Nims

+0

@Nims Le coordinate UV normalizzate sono inadeguate perché mancano le informazioni su come viene campionata finemente la trama; informazioni fondamentali per la selezione del livello mipmap ottimale. dFdx e dFdy sono bidimensionali perché la coordinata della trama è bidimensionale. Come hai detto tu, tutto ciò che ti serve è la derivata lungo la coordinata "U OR V". Quindi ti dà entrambi. Questo risponde a una qualsiasi delle tue domande? –

+0

Grazie per la risposta, ma ancora non capisco perché le derivate sono 2 dimensioni, diciamo per esempio che ddx sta solo misurando la modifica lungo la coordinata U, non ci sarebbe alcun cambiamento lungo la coordinata V, quindi per dx_vtc - il secondo valore sarebbe zero. Altrimenti qual è il motivo per avere sia ddx che ddy? – Nims

7

Da here:

un'occhiata al OpenGL 4.2 spec capitolo 3.9.11 equazione 3.21. Il livello di mip mappa è calcolato sulla base delle lunghezze dei vettori derivati:

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

Grazie per aver trovato questo. Ho guardato le specifiche e purtroppo sembra lasciare un po 'di margine di manovra nell'implementazione reale, quindi questo metodo potrebbe non essere esattamente quello che viene utilizzato. Inoltre, non tiene conto delle impostazioni GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD. Nota che texture_coordinate nel tuo snippet dovrebbe essere non normalizzata, cioè in pixel, non solo (0,1).Questo è un buon inizio per me per specificare manualmente LOD me stesso. Ma vorrei avere un modo per accedere al valore LOD automatizzato interno. –

+0

@ChristopherBruns: potresti fare qualcosa * veramente * scadente: popola una trama fittizia con diversi colori/valori solidi per ogni livello di mip, campionala e riconvertisci il colore/valore al livello mip :) – genpfault

+2

In realtà, se siamo parlando di GL 4.x improvvisamente, ['textureQueryLod (...)'] (https://www.opengl.org/sdk/docs/man/html/textureQueryLod.xhtml) è stato creato proprio per questo motivo. Come la maggior parte delle funzioni di texture LOD implicite, funziona solo nello shader dei frammenti perché ha bisogno di un gradiente dello spazio dello schermo (derivata parziale) per calcolare il LOD mipmap appropriato. –