opengl 2d

Dibujo 2D en OpenGL: filtrado lineal con precisión de píxel en tamaño nativo



(1)

Es difícil saber exactamente qué es lo "correcto" que estás buscando. Si tienes un sprite de 64x64, y quieres escalarlo a 65x65 o a 63x63, ninguna cantidad de filtrado hará que se vea bien. Cuando agregue antialias a la mezcla, recuerde que el multisampling no es supersampling, por lo que sus texturas no se volverán mágicamente interiores más suaves.

Dicho esto, se supone que el filtrado que no es el más cercano funciona bien fuera de la caja con el multisampling. Creo que su enfoque GL_LINEAR está en el camino correcto, pero creo que puede tener problemas de implementación.

En particular, se supone que el filtrado lineal se filtra cuando se encuentra a lo largo de los límites de texel. Esto puede suceder, por ejemplo, si tiene dos triángulos contiguos. De hecho, debería esperar un filtrado lineal a lo largo de los bordes del sprite, y este filtrado es lo correcto.

No debe intentar corregir esto ajustando las coordenadas de la textura (y, por lo tanto, los vértices), ya que esto escalará incorrectamente la coordenada de la textura a través de la textura. En su lugar, recomiendo fijar las coordenadas de textura al rango deseado más / menos 0.5 / texture_res en su sombreador.

Descubrirá que esto resuelve el problema para obtener resultados perfectos en píxeles a escala nativa y también aumentos de buena calidad. La reducción se verá bien, pero recomendaría el filtrado trilineal (mipmap) para obtener mejores resultados.

Version corta:

¿Existe un enfoque general en OpenGL que permita el dibujo 2D de texturas de píxeles perfectos desde un atlas cuando se dibuja en tamaño nativo (incluidos los píxeles de borde), y una escala de buena calidad cuando se filtra a tamaño no nativo?

Más detalles sobre el problema:

Supongamos que está escribiendo algún tipo de sistema para dibujar sprites desde un atlas de textura, de modo que el usuario pueda especificar el sprite, y el tamaño y la ubicación en la que se va a dibujar. Además, es posible que solo quieran dibujar un sub-rectángulo del sprite.

Por ejemplo, aquí hay un tablero de ajedrez de 64x64:

... y solo en su textura atlas:

Nota: asumiremos que la ventana gráfica está configurada para asignar 1: 1 a los píxeles del dispositivo.

Enfoques

Edite para mayor claridad: tenga en cuenta que los primeros 2 enfoques a continuación no dan el resultado deseado, y están específicamente para delinear lo que no funciona.

1. Para dibujar el sprite en tamaño nativo, simplemente use GL_NEAREST

  • configura OpenGL para usar GL_NEAREST min / mag filtering
  • para dibujar en la posición (x, y), coloca los vértices de (x, y) a (x + 64, y + 64)
  • usar coordenadas de textura (0,0) -> (64 / atlas_size, 64 / atlas_size)

Esto está bien para dibujar en tamaño nativo, pero el filtro MÁS CERCANO da malos resultados cuando el usuario dibuja el objeto en un tamaño diferente a 64x64. También obliga a los texels a alinearse con la cuadrícula de píxeles, dando malos resultados cuando el objeto se dibuja en ubicaciones de píxeles no enteros:

2. Habilitar GL_LINEAR

  • Con el filtrado lineal, necesitamos cambiar nuestras cuerdas UV al centro de los texels: (0.5/atlas_size,0.5/atlas_size) a (63.5/atlas_size,63.5/atlas_size) . De lo contrario, para los píxeles más externos, el filtrado lineal muestreará los vecinos del sprite en el atlas.
  • También necesitamos modificar nuestros vértices, ya que continuar usando vértices de (0,0) a (64,64) estirará la textura en 1px en ambas direcciones, de esta manera:
  • por lo tanto, necesitamos usar vértices de (0.5,0.5) a (63.5,63.5). Generalmente, cuando la textura se dibuja en una proporción de su tamaño nativo (a, b) necesitaremos cambiar nuestros vértices "hacia adentro", creo, (a / 2, b / 2). El da el siguiente resultado (sobre un fondo morado):

Tenga en cuenta que obtenemos un dibujo de píxeles precisos, excepto los píxeles del borde, que se mezclan con el fondo, ya que el límite del vértice se encuentra a medio camino entre los píxeles.

Editar: también tenga en cuenta que este comportamiento también depende de si está habilitado el antialiasing. Si no es así, el enfoque anterior de hecho da una representación perfecta de píxeles, pero no proporciona una buena transición cuando el sprite se mueve desde una posición de píxel alineado a una posición de subpíxel. Además de antialiasing es una necesidad en muchos casos.

3. Pad sprites en el atlas de textura.

Las dos soluciones obvias al problema del píxel del borde involucran rellenar el borde del sprite con un borde de 1px en el atlas de textura. Usted podría:

  • rellene con 1 capa de píxeles transparentes y expanda los vértices en (0.5a, 0.5b) en lugar de contraerlos
  • rellene con una segunda copia de los píxeles más externos del sprite, y vuelva a muestrear la textura de (0,0) a (64 / atlas_size, 64 / atlas_size)

Básicamente, esto nos da un dibujo de píxeles precisos con escala lineal. Sin embargo, si luego permitimos que el usuario dibuje solo un sub-rect de un sprite, cualquiera de estos enfoques falla porque el sub-rect obviamente no tiene el relleno requerido.

¿Me he perdido algo? ¿Hay una solución general a este problema?