2012-10-05 14 views
5

Di seguito è riportato uno shader di frammenti GLSL che emette un texel se il coord della texture è all'interno di una finestra, altrimenti viene emesso un colore . Questo sembra semplicemente stupido e il lì deve essere un modo per farlo senza diramazioni?GLSL point box test interno

uniform sampler2D texUnit; 

varying vec4 color; 
varying vec2 texCoord; 

void main() { 
    vec4 texel = texture2D(texUnit, texCoord); 
    if (any(lessThan(texCoord, vec2(0.0, 0.0))) || 
     any(greaterThan(texCoord, vec2(1.0, 1.0)))) 
    gl_FragColor = color; 
    else 
    gl_FragColor = texel; 
} 

Di seguito è una versione senza diramazione, ma si sente ancora maldestro. Qual è la migliore pratica per "texture coord clamping"?

uniform sampler2D texUnit; 

varying vec4 color; 
varying vec4 labelColor; 
varying vec2 texCoord; 

void main() { 
    vec4 texel = texture2D(texUnit, texCoord); 
    bool outside = any(lessThan(texCoord, vec2(0.0, 0.0))) || 
       any(greaterThan(texCoord, vec2(1.0, 1.0))); 
    gl_FragColor = mix(texel*labelColor, color, 
        vec4(outside,outside,outside,outside)); 
} 

Here is the rendering result

sto bloccaggio texel alla regione con l'etichetta è - la struttura s & t coordinate saranno tra 0 e 1, in questo caso. In caso contrario, io uso un colore marrone dove l'etichetta non è.

Nota che potrei anche creare una versione di ramificazione del codice che non esegua una ricerca di trama quando non è necessario. Sarebbe più veloce di una versione non ramificata che ha sempre eseguito una ricerca della trama? Forse il tempo per alcuni test ...

+0

Sono sempre interessato a vedere i risultati del benchmarking per cose come questa. Penso che in questo caso potrebbe essere necessario costruire uno scenario in cui molti test point-in-box diventano un collo di bottiglia. – jozxyqk

risposta

10

Usa step funzione per evitare ramificazione e ottenere le migliori prestazioni:

// return 1 if v inside the box, return 0 otherwise 
float insideBox(vec2 v, vec2 bottomLeft, vec2 topRight) { 
    vec2 s = step(bottomLeft, v) - step(topRight, v); 
    return s.x * s.y; 
} 

void main() { 
    vec4 texel = texture2D(texUnit, texCoord); 

    float t = insideBox(v_position, vec2(0, 0), vec2(1, 1)); 
    gl_FragColor = t * texel + (1 - t) * color; 
} 
+0

Grazie Andy Shiue per la correzione – damphat

+0

"insideBox()" è una funzione molto intelligente! – Tara

+0

Esiste una versione 3D? – jjxtra

3

in base alla risposta del damphat, ho implementato una funzione per una transizione morbida tra interno ed esterno rettangolo:

float inside_rectangle_smooth(vec2 p, vec2 bottom_left, vec2 top_right, float transition_area) 
{ 
    vec2 s = smoothstep(bottom_left, bottom_left + vec2(transition_area), p) - 
      smoothstep(top_right - vec2(transition_area), top_right, p); 
    return(s.x * s.y); 
} 

Utilizzare il parametro "transition_area" per regolare la dimensione della zona di transizione tra interno ed esterno del rettangolo. La transizione è sbiadita all'interno del del rettangolo, non al di fuori di esso. Assicurati anche che il parametro "transition_area" sia più piccolo della distanza tra "bottom_left" e "top_right" (in ogni dimensione).
Sto usando con successo questa funzione per sfumare le ombre nel mio motore (usando le coordinate della mappa ombra).

Dimostrazione:
inside_rectangle_smooth(v_texture_coordinate, vec2(0.0), vec2(1.0), 0.1)
L'immagine sopra è prodotta chiamando:
inside_rectangle_smooth(v_texture_coordinate, vec2(0.0), vec2(1.0), 0.1)