Texturas de hoja de Sprite recogiendo bordes de textura adyacente

10

Tengo una rutina de sprites personalizada (openGL 2.0) que usa una hoja de sprites simple (mis texturas están dispuestas horizontalmente una al lado de la otra).

Entonces, por ejemplo, aquí hay una hoja de prueba de sprite con 2 texturas simples:

ingrese la descripción de la imagen aquí

Ahora, lo que hago al crear mi objeto sprite openGL es especificar el número total de fotogramas en su atlas y al dibujar, especificar qué fotograma quiero dibujar.

Luego determina de dónde agarrar la textura:

Dividiendo el número de cuadro requerido por el número total de cuadros (para obtener la coordenada izquierda)

Y luego bucear 1 por el número total de fotogramas y agregar el resultado a la coordenada de la izquierda calculada anteriormente.

Esto parece funcionar, pero a veces tengo problemas. Digamos, por ejemplo, que quiero dibujar la X a continuación y obtengo ...........

ingrese la descripción de la imagen aquí

He oído hablar de poner un 'relleno' de 1 px entre cada textura, pero ¿alguien podría explicar exactamente cómo funciona? Quiero decir que si hago esto, seguramente arrojará los cálculos para obtener la textura.

Si simplemente incluyo el relleno en la textura recogida (para que el sprite se dibuje con un borde en blanco), ¿entonces seguramente esto causará problemas con la detección de colisiones? (es decir, los sprites pueden parecer colisionar cuando se usan cuadros delimitadores cuando las partes transparentes chocan).

Agradecería si alguien pudiera explicarlo.

BungleBonce
fuente
¿Estás usando GL_NEARESTo GL_LINEARpara renderizar la textura?
MichaelHouse
Estoy usando GL_Linear @ Byte56
BungleBonce

Respuestas:

15

El problema con el uso de atlas de textura y fugas de texels adyacentes tiene que ver con la forma en que funciona el filtrado de textura lineal.

Para cualquier punto de la textura que no se muestrea exactamente en el centro de un texel, el muestreo lineal muestreará 4 texels adyacentes y calculará el valor en la ubicación que solicitó como el promedio ponderado (basado en la distancia desde el punto de muestra) de los 4 muestras

Aquí hay una buena visualización del problema:

  

Dado que no puede usar algo como GL_CLAMP_TO_EDGEen un atlas de texturas, debe crear elementos de borde alrededor del borde de cada textura. Estos texels de borde evitarán que las muestras vecinas de texturas completamente diferentes en el atlas alteren la imagen a través de la interpolación ponderada explicada anteriormente.

Tenga en cuenta que cuando utiliza el filtro anisotrópico, es posible que deba aumentar el ancho del borde. Esto se debe a que el filtrado anisotrópico aumentará el tamaño de la vecindad de la muestra en ángulos extremos.


Para ilustrar lo que quiero decir al usar un borde alrededor del borde de cada textura, considere los diversos modos de ajuste disponibles en OpenGL. Presta especial atención a CLAMP TO EDGE.

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

A pesar de que existe un modo llamado "Clamp to Border", en realidad no es lo que nos interesa. Ese modo le permite definir un solo color para usarlo como borde alrededor de su textura para cualquier coordenada de textura que quede fuera de la normalizada [0.0 -1.0] rango.

Lo que queremos es replicar el comportamiento de CLAMP_TO_EDGE, donde cualquier coordenada de textura fuera del rango apropiado para la (sub) textura recibe el valor del último centro de texel en la dirección en la que estaba fuera de los límites. Dado que tiene un control casi completo sobre las coordenadas de textura en un sistema de atlas, el único escenario en el que las coordenadas de textura (efectivas) pueden referirse a una ubicación fuera de su textura es durante el paso promedio ponderado del filtrado de textura.

Sabemos que GL_LINEARtomará muestras de los 4 vecinos más cercanos como se ve en el diagrama anterior, por lo que solo necesitamos un borde de 1 texel. Es posible que necesite un borde de texel más ancho si usa un filtro anisotrópico, ya que aumenta el tamaño del vecindario de la muestra bajo ciertas condiciones.

Aquí hay un ejemplo de una textura que ilustra el borde más claramente, aunque para sus propósitos puede hacer que el borde tenga 1 texel o 2 texels de ancho.

  

(NOTA: El borde al que me refiero no es el negro alrededor de los cuatro bordes de la imagen, sino el área donde el patrón de tablero de ajedrez deja de repetirse regularmente)

En caso de que te lo estés preguntando, aquí es por qué sigo sacando el filtro anisotrópico. Cambia la forma de la vecindad de la muestra según el ángulo y puede hacer que se usen más de 4 texels para el filtrado:

  http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg

Cuanto mayor sea el grado de anisotropía que use, más probabilidades tendrá de lidiar con vecindarios de muestra que contengan más de 4 texels. Un borde de 2 texel debe ser adecuado para la mayoría de las situaciones de filtrado anisotrópico.


Por último, pero no menos importante, así es como se construiría un atlas de textura empaquetado que replicaría el GL_CLAMP_TO_EDGEcomportamiento en presencia de un GL_LINEARfiltro de textura:

( Reste 1 de X e Y en las coordenadas negras, no revisé la imagen antes de publicar ) .   

Debido al almacenamiento de bordes, el almacenamiento de 4 texturas de 256x256 en este atlas requiere una textura con dimensiones de 516x516. Los bordes están codificados por colores en función de cómo los llenaría con datos de texel durante la creación del atlas:

  • Rojo = Reemplazar con texel directamente debajo
  • Amarillo = Reemplazar con texel directamente arriba
  • Verde = Reemplazar con texel directamente a la izquierda
  • Azul = Reemplazar con texel directamente a la derecha

Efectivamente en este ejemplo empaquetado, cada textura en el atlas usa una región de 258x258 del atlas, pero generará coordenadas de textura que se correlacionan con la región visible de 256x256. Los texels limítrofes solo se usan cuando el filtrado de texturas se realiza en los bordes de las texturas en el atlas, y la forma en que están diseñados imita el GL_CLAMP_TO_EDGEcomportamiento.

En caso de que se lo esté preguntando, puede implementar otros tipos de modos de ajuste utilizando un enfoque similar: GL_REPEATpuede implementarse intercambiando los texels de borde izquierdo / derecho y superior / inferior en el atlas de textura y un poco de matemática de coordenadas de textura inteligente en un sombreador Eso es un poco más complicado, así que no te preocupes por eso por ahora. Como solo se trata de hojas de sprites, limítese a GL_CLAMP_TO_EDGE:)

Andon M. Coleman
fuente
Gracias @AndonMColeman, ¿podría mostrar el borde en un diagrama ya que todavía no estoy seguro de entender cómo funciona esto? ¿Significará nuevamente que cuando se aplique la textura a mi objeto, incluirá el borde? Quiero que la textura real vaya directamente a los bordes de mi quad - lo siento si no lo entiendo correctamente - agradecería algunos detalles más - gracias
BungleBonce
@ user22241 Ciertamente, la forma en que funciona este borde es duplicando el texel en el borde de la textura.
Andon M. Coleman
@ user22241: No, este borde no será visible en circunstancias normales. Tratará sus texturas empaquetadas como si tuvieran las mismas dimensiones para el cálculo de coordenadas de textura, solo aplicará un desplazamiento a ellas para saltar más allá del borde. El objetivo principal del borde es evitar que el muestreo de textura lineal se extienda demasiado y muestree los texel que pertenecen a imágenes separadas en su hoja de sprite. Si usa el muestreo del vecino más cercano, nada de esto es necesario, pero luego obtiene sprites con alias desagradables.
Andon M. Coleman
Respuesta detalladamente brillante: ¡gracias! Solo una última cosa si pudiera. ¿Cómo calcularía el 'desplazamiento' para agregar a mis coordenadas de textura? ¿Estoy en lo cierto al decir que sería simplemente 1 / widthOfTexture?
BungleBonce
@ user22241: Sí, el inicio de la imagen de textura sería + 1 / widthOfTexture en la dirección X y + 1 / heightOfTexture en la dirección Y. Tendrá un borde que recorre todo el contorno de cada textura. Para el momento en que desee calcular las coordenadas de textura para la tercera textura horizontal, la ubicación empaquetada para esta textura es en realidad +5 texels (+2 texels para el borde de la primera textura, +2 para el borde de la segunda textura y +1 para el inicio de esta textura) además del ancho de las otras 2 texturas. Parece complicado solo escribirlo; Puedo dibujar un diagrama si es necesario :)
Andon M. Coleman