2012-10-05 25 views
5

A continuación se muestra un sombreador de fragmento GLSL que genera un mensaje de texto si la coordinada de textura dada está dentro de un cuadro; de lo contrario, se genera un color . Esto simplemente se siente tonto y el debe ser una forma de hacer esto sin ramificar?Prueba de cuadro dentro del cuadro GLSL

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; 
} 

A continuación, se muestra una versión sin ramificar, pero todavía se siente torpe. ¿Cuál es la mejor práctica para "sujetar coordenadas de textura"?

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

Estoy sujeción texels a la región con la etiqueta es - la textura s & t coordenadas será de entre 0 y 1 en este caso. De lo contrario, uso un color marrón donde la etiqueta no es.

Tenga en cuenta que también podría construir una versión de bifurcación del código que no realizar una búsqueda de textura cuando no es necesario. ¿Sería esto más rápido que una versión no ramificada que siempre realizó una búsqueda de textura? Tal vez para algunas pruebas ...

+0

Siempre me interesan los resultados de la evaluación comparativa para cosas como esta. Creo que en este caso es posible que tengas que construir un escenario en el que muchas pruebas point-in-box se conviertan en un cuello de botella. – jozxyqk

Respuesta

10

Uso step función para evitar la ramificación y obtener el mejor rendimiento:

// 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

Gracias Andy Shiue por su corrección – damphat

+0

"insideBox()" es una función muy inteligente! – Tara

+0

¿Hay una versión en 3D? – jjxtra

3

Sobre la base de la respuesta de damphat, he implementado una función para una transición suave entre el interior y el exterior el rectángulo:

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

Utilice el parámetro "transition_area" para ajustar el tamaño de la zona de transición entre el interior y fuera del rectángulo. La transición se desvaneció dentro de el rectángulo, no fuera de él. También asegúrese de que el parámetro "transition_area" sea más pequeño que la distancia entre "bottom_left" y "top_right" (en cada dimensión).
Estoy utilizando con éxito esta función para atenuar las sombras en mi motor (usando las coordenadas del mapa de sombra).

Demostración:
inside_rectangle_smooth(v_texture_coordinate, vec2(0.0), vec2(1.0), 0.1)
La imagen de arriba es producida por llamar:
inside_rectangle_smooth(v_texture_coordinate, vec2(0.0), vec2(1.0), 0.1)

Cuestiones relacionadas