2014-04-16 5 views
6

Qual è il modo migliore per assaggiare le texture a schermo intero in uno shader frammento, così per esempio la g-buffer in un renderer differita, o la trama scena all'interno di uno shader post elaborazione?Il modo migliore per gustare una texture fullscreen

Al momento io uso due modi seguenti:

  • passare la dimensione dello schermo allo shader come uniforme e calcolare (u, v) da gl_FragCoord:

    vec2 texCoord = gl_FragCoord.xy/vScreenSize; 
    vec3 c = texture(tex, texCoord).rgb; 
    

    non sembra essere l'ideale dato che è necessaria una divisione e fornire lo shader con le dimensioni dello schermo è ingombrante.

  • Converti gl_FragCoord.xy in un ivec e utilizzare texelFetch:

    vec3 c = texelFetch(tex, ivec2(gl_FragCoord.xy), 0).rgb; 
    

    Inoltre non è l'ideale, perché è necessaria la conversione da float a int.

Quindi c'è un modo migliore? Voglio solo campionare un buffer nel punto esatto in cui il mio pixel shader sta disegnando.


// EDIT:


Ok, i consigli di interpolati tessitura coordinate che provengono dal vertex sono riuscito a capire il codice seguente:

Vertex Shader:

#version 150 

uniform mat4 im_ModelViewProjectionMatrix; 

in vec3 iv_Vertex; 
noperspective out vec2 vVertCoord; 

void main(void) 
{ 
    gl_Position = im_ModelViewProjectionMatrix * vec4(iv_Vertex, 1.0); 
    vVertCoord = (gl_Position.xy/gl_Position.w) * (0.5) + vec2(0.5); 
} 

io fondamentalmente calcolare le coordinate del dispositivo normalizzate (NDC) dal fermaglio spac e posiziona con la divisione prospettiva e poi mappa i NDC (che vanno da [-1,1]) all'intervallo [0,1]. Funziona perfettamente per quad a schermo intero (anche senza la divisione prospettiva perché le coordinate sono così semplici). La geometria arbitraria che ho bisogno di disegnare come geometria della luce nel mio renderer differito ha però alcuni problemi. In uscita I vertex shader vVertCoord come colore per il rosso = x e verde = y:

#version 150 

noperspective in vec2 vVertCoord; 
out vec4 colorOut; 

void main(void) 
{ 
    colorOut = vec4(vVertCoord.x, vVertCoord.y, 0, 1); 
} 

Questo è il risultato quando sono all'interno di un punto-luce-sfera, tutto osserva benissimo (le linee nere sono resi di proposito):

All fine

Tuttavia, se mi avvicino alla luce geometria questo è il risultato:

Not ok

Che cosa sta facendo quella patch rossa nell'angolo in alto a sinistra? Non vuoi vedere i risultati in colore reale con i colori di debug disabilitati perché assomigliano a un lsd-trip, tutto si muove attorno quando muovi la telecamera. Questa precisione è correlata? Nota che tutto va bene quando uso gl_FragCoord nel pixel shader.

+0

C'è qualche ragione particolare per cui le coordinate della trama sono basate su gl_FragCoord e non un normale attributo interpolato? Nel primo esempio si eliminerebbe già la necessità della divisione. post scriptum invece di vScreenSize puoi avere il reciproco delle dimensioni dello schermo (trasformando la divisione in una moltiplicazione) –

+0

Probabilmente non vuoi il secondo, che eliminerà la possibilità di fare qualsiasi filtro di trama. Mentre si potrebbe pensare che non ci si preoccupi veramente di questo, in un motore di shading differito può essere utile eseguire la generazione e l'ombreggiatura di G-Buffer a risoluzioni diverse (in particolare su hardware di fascia bassa che di solito è piuttosto limitato al tasso di riempimento). –

risposta

2

Non dovete fare qualsiasi matematica speciale se si passa in un vertice interpolato coordinata dal vertex shader.

Ad esempio, se si stesse disegnando un semplice quadrato unitario che copriva lo schermo, si può solo e sarebbe quindi ricevere la consistenza schermo intero, si può solo fare qualcosa di simile:

vertex shader pseudocode: 
layout(position = 0) in vec3 in_vertex; 
out vec3 out_vertex; 
void main() 
{ 
    //Do your matrix multiplications to your in_vertex to get its final position... 
    out_vertex = in_vertex; 
} 

vostro vertex Shader quindi interpolerà correttamente l'in_vertex per essere nell'intervallo x: 0 ... 1, y: 0 ... 1 (finché si disegna un quadrato di unità) e lo passa al frammento shader. Il tuo frammento di shader sarà quindi utilizzarlo in questo modo:

fragment shader pseudocode: 
in vec3 out_vertex; 
uniform sampler2D tex; 
void main() 
{ 
    gl_fragcolor = texture(tex,vec2(out_vertex.x,out_vertex.y)); 
} 

Non è necessaria alcuna altra matematica, a patto che si prende cura che l'out_vertex sarà sempre e solo essere nel range di 0 ... 1. Per estendere questo esempio un po ', immaginare ecco il nostro quadrato:

(0,1)+-----------+(1,1) | | | | | | | | | | (0,0)+-----------+(0,1)

e abbiamo voluto assaggiare questo punto nel centro esatto:

(0,1)+-----------+(1,1) | | | | | * | | | | | (0,0)+-----------+(0,1)

nostro vertex shader interpolerà automaticamente che posizione dalle altre 4 posizioni e passare la seguente vec3 allo shader del frammento:

out_vertex = vec3(0.5,0.5,0); 

Quale può essere quindi utilizzato per campionare correttamente la trama

+0

Credo che tu abbia ancora bisogno di impostare 'gl_Position' nel tuo vertex shader. Se si disegna un quadrato unitario, come suggerito da @redsoxfantom, si può usare qualcosa come 'gl_Position = vec4 (2.0 * out_vertex, 0.0) - 1.0;'. Non hai bisogno di moltiplicazioni di matrice. Fammi sapere se hai bisogno di ulteriori spiegazioni e dettagli. È piuttosto difficile coprirlo in un commento, ma posso postarlo come risposta. –

+0

Buona risposta, anche se ho finito con un codice diverso perché non disegnavo sempre quad a schermo intero ma anche geometria leggera, nel qual caso le coordinate del vertice non sono molto utili. – Marius