¿Qué es un buen algoritmo de empaque de textura? Técnicamente, el embalaje del contenedor es NP-duro , por lo que una heurística es lo que realmente busco.
52
¿Qué es un buen algoritmo de empaque de textura? Técnicamente, el embalaje del contenedor es NP-duro , por lo que una heurística es lo que realmente busco.
Respuestas:
Pasé unos meses en un trabajo con un mejor algoritmo de empaque de texturas.
El algoritmo con el que comenzamos fue simple. Recoge todos los elementos de entrada. Ordénelos por píxeles totales consumidos, de grande a pequeño. Extiéndalos en su textura en el orden de la línea de exploración, solo probando cosas desde el píxel superior al píxel vertical, moviéndose hacia abajo en una línea y repitiendo, restableciendo el píxel superior después de cada colocación exitosa.
Usted necesita codificar un ancho o crear otra heurística para esto. En un intento por preservar la cuadratura, nuestro algoritmo comenzaría en 128, luego aumentaría en 128s hasta que se obtuviera un resultado que no fuera más profundo que ancho.
Entonces, teníamos ese algoritmo y decidí mejorarlo. Probé un montón de heurísticas extrañas, tratando de encontrar objetos que encajaran, ponderando sobre un conjunto de propiedades deseadas de empaquetamiento espacial, girando y volteando. Después de todo mi trabajo, literalmente tres meses de trabajo, terminé ahorrando un 3% de espacio.
Sí. 3%
Y después de ejecutar nuestra rutina de compresión, en realidad terminó siendo más grande (lo que todavía no puedo explicar), así que descartamos todo y volvimos al antiguo algoritmo.
Ordenar elementos, atascar en textura en el orden de la línea de escaneo. Ahí está tu algoritmo. Es fácil de codificar, rápido de ejecutar y no mejorará mucho sin una increíble cantidad de trabajo. Ese trabajo simplemente no vale la pena a menos que su empresa tenga al menos 50 personas y probablemente más.
Y como nota al margen, acabo de implementar este algoritmo (ancho fijo de 512 píxeles) para, literalmente, exactamente la misma aplicación que estás haciendo (sin complicaciones, pero con glifos de tipo libre renderizados por opengl). Aquí está el resultado. Parece borroso porque el mío está utilizando el algoritmo de representación de texto basado en el campo de distancia de Valve , que también representa el espacio adicional entre los glifos. Obviamente, no queda mucho espacio vacío, y hace un buen trabajo al agrupar las cosas en espacios abiertos.
Todo el código para esto tiene licencia BSD y está disponible en github .
fuente
La tesis doctoral de Andrea Lodi se titula Algoritmos para problemas de asignación y empaque bidimensional de contenedores .
La tesis analiza algunas de las formas más difíciles de estos problemas. Afortunadamente, el embalaje de texturas es la versión más fácil. El mejor algoritmo que encontró se llamaba Touching Perimeter .
Para citar de la página 52:
También de interés, el documento describe un algoritmo para determinar el tamaño de un mapa de textura óptimamente empaquetado. Sería útil determinar si es posible ajustar todas las texturas en un atlas de 1024x1024.
fuente
Si alguien todavía está interesado, he reescrito completamente la biblioteca rectpack2D para que sea mucho más eficiente.
Funciona manteniendo un
std::vector
espacio vacío en el atlas, comenzando con un tamaño máximo inicial (típicamente, el tamaño de textura máximo permitido en una GPU particular), dividiendo el primer espacio vacío viable y guardando las divisiones de nuevo en el vector.El avance en el rendimiento vino con solo usar un vector, en lugar de mantener un árbol completo, como se hizo anteriormente.
El procedimiento se describe en detalle en el archivo README .
La biblioteca está bajo MIT, así que me alegro por ti si te resulta útil.
Resultados de ejemplo:
Las pruebas se realizaron en una CPU Intel (R) Core (TM) i7-4770K a 3.50GHz. El binario fue construido con clang 6.0.0, usando un interruptor -03.
Sprites arbitrarios del juego + glifos japoneses: 3264 sujetos en total.
Tiempo de ejecución: 4 milisegundos
Píxeles desperdiciados: 15538 (0.31% - equivalente a un cuadrado de 125 x 125)
Salida (2116 x 2382):
En color:
(el negro es espacio desperdiciado)
Glifos japoneses + algunos sprites GUI: 3122 sujetos.
Tiempo de ejecución: 3.5 - 7 ms
Píxeles desperdiciados: 9288 (1.23% - equivalente a un cuadrado de 96 x 96)
Salida (866 x 871):
En color:
(el negro es espacio desperdiciado)
fuente
Un buen algoritmo heurístico se puede encontrar aquí . Cuando estaba probando algo similar recientemente, encontré esto como el punto de partida básico para la mayoría de las implementaciones que vi.
Funciona particularmente bien con muchos elementos de formas regulares y de tamaño similar, o con una buena combinación de imágenes pequeñas y menos grandes. El mejor consejo para lograr buenos resultados es recordar clasificar su entrada en términos de tamaño de imagen, luego empaquetar de mayor a menor, ya que las imágenes más pequeñas se empaquetarán en el espacio alrededor de las imágenes más grandes. La forma en que haces esto, dependiendo de tus objetivos. Usé el perímetro en lugar del área como una aproximación de primer orden, ya que tomé la vista de que las imágenes altas + delgadas / cortas + anchas (que tendrían un área más baja) en realidad son muy difíciles de colocar más adelante en un paquete, por lo que al usar el perímetro empujas estas formas extrañas hacia el frente de la orden.
Aquí hay una muestra de visualización de la salida para mi empacador en un conjunto aleatorio de imágenes del directorio de volcado de imágenes de mi sitio web :).
Los números en los cuadrados son las identificaciones de los bloques que contienen en el árbol, así que le dará una idea del orden de las inserciones. El primero es el ID "3" porque es el primer nodo de hoja (solo las hojas contienen imágenes) y, en consecuencia, tiene 2 padres).
fuente
Personalmente, solo uso un codicioso primer bloque más grande que encaja. No es óptimo, pero funciona bien.
Tenga en cuenta que, si tiene una cantidad razonable de bloques de textura, puede buscar exhaustivamente el mejor orden incluso si el problema en sí es NP.
fuente
Algo que he usado, que funciona bien incluso para mapas UV irregulares, es convertir el parche UV en una máscara de mapa de bits y mantener una máscara para la textura misma, buscando la primera posición en la que se ajustará el parche UV. Ordeno los bloques de acuerdo con algunas heurísticas simples (altura, ancho, tamaño, lo que sea), y permito que las rotaciones de los bloques minimicen o maximicen la heurística elegida. Eso proporciona un espacio de búsqueda manejable para la fuerza bruta.
Si puede repetir eso probando varias heurísticas, y / o aplicar un factor aleatorio al elegir el orden e iterar hasta que se agote el límite de tiempo.
Con este esquema, obtendrá pequeñas islas UV empaquetadas en los huecos hechos por las grandes, e incluso en los agujeros que quedan dentro de los mismos parches UV.
fuente
Recientemente lanzamos un script de Python que empaquetará texturas en múltiples archivos de imagen de un tamaño determinado.
Citado de nuestro blog:
"Si bien hay numerosos empacadores que se pueden encontrar en línea, nuestra dificultad fue encontrar cualquiera que pudiera manejar grandes cantidades de imágenes en múltiples directorios. ¡Así nació nuestro propio atlas packer!
Tal como está, nuestro pequeño script comenzará en el directorio base y cargará todos los .PNG en un atlas. Si ese atlas está lleno, crea uno nuevo. Luego, intentará ajustar el resto de las imágenes en todos los atlas anteriores antes de encontrar un lugar en el nuevo. De esa manera, cada atlas está empaquetado lo más ajustado posible. Los atlas se nombran según la carpeta de la que provienen sus imágenes.
Puede cambiar el tamaño del atlas (línea 65), el formato de las imágenes que desea empaquetar (línea 67), el directorio de carga (línea 10) y el directorio de guardar (línea 13) con bastante facilidad sin experiencia en Python. Como un pequeño descargo de responsabilidad, esto se combinó en unos días para trabajar específicamente con nuestro motor. Le recomiendo que solicite funciones, comente con sus propias variaciones e informe cualquier error, pero cualquier cambio en el script ocurrirá en mi tiempo libre ".
No dude en consultar el código fuente completo aquí: http://www.retroaffect.com/blog/159/Image_Atlas_Packer/#b
fuente
Es bastante fácil empaquetar fuentes porque todas (o la gran mayoría) de las texturas de glifos son casi del mismo tamaño. Haz lo más simple que se te ocurra y estará muy cerca de lo óptimo.
La inteligencia se vuelve más importante cuando empaca imágenes de tamaños muy diferentes. Entonces desea poder empacar en huecos, etc. Aun así, sin embargo, un algoritmo simple como la búsqueda de orden de exploración analizada anteriormente producirá resultados muy razonables.
Ninguno de los algos avanzados es mágico. No serán un 50% más eficientes que un simpel algo, y no obtendrá beneficios consistentes de ellos a menos que tenga una asombrosa cantidad de hojas de textura. Esto se debe a que las pequeñas mejoras que hacen los mejores algoritmos solo se verán en conjunto.
Vaya simple y avance a algo donde sus esfuerzos serán mejor recompensados
fuente
Si es específicamente para texturas de fuente, entonces probablemente haga algo no óptimo pero agradable y simple:
Ordenar los caracteres por altura, los más altos primero
Comience en 0,0 Coloque el primer carácter en las coordenadas actuales, avance X, coloque el siguiente, repita hasta que no quepamos con otro
Restablezca X a 0, avance Y hacia abajo por la altura del carácter más alto de la fila y llene otra fila
Repita hasta que nos quedemos sin caracteres o no podamos encajar en otra fila.
fuente