Texturas

Sigue estas prácticas recomendadas para optimizar la apariencia y el rendimiento de las texturas en el juego de Android.

Las texturas son uno de los componentes centrales del arte 3D. Los juegos en 3D que se ejecutan bien en la mayoría de los dispositivos comienzan con arte 3D diseñado para aprovechar al máximo los procesadores de gráficos. En esta guía, se destacan optimizaciones y prácticas recomendadas para texturas en dispositivos móviles a fin de mejorar el rendimiento del juego y minimizar el consumo de energía, a la vez que mantienes una alta calidad visual.

Partes de este artículo se basan en el trabajo aportado y protegido por derechos de autor de Arm Limited.

Crea un atlas de texturas

Un atlas de texturas es una textura que se diseñó para contener los datos de imagen de varios objetos gráficos, como objetos 2D o mallas 3D. En lugar de que cada objeto tenga su propia textura, se usa un atlas de ellas para combinar las imágenes de cada objeto.

Mallas que comparten un atlas de texturas
Figura 1: Lo que se destaca en color amarillo en la escena renderizada (izquierda) delinea las mallas que comparten el atlas de texturas (derecha).

Es importante minimizar la cantidad de llamadas de dibujo de un fotograma de juego para lograr un rendimiento óptimo durante la renderización. Puedes usar la misma textura para diferentes objetos como un factor a fin de combinarlas en una sola llamada de dibujo. Es importante reducir las llamadas de dibujo, en especial para los juegos que se vinculan a la CPU, ya que cada llamada genera una sobrecarga de la CPU mientras el controlador gráfico la procesa. Los atlas de texturas también reducen la cantidad de archivos de elementos de textura en los datos de tiempo de ejecución del juego. Se pueden consolidar cientos o incluso miles de texturas en una cantidad mucho menor de archivos de atlas de texturas.

Cuando creas mallas 3D, debes planificar el diseño del atlas de texturas. Si se crea el atlas antes de crear el recurso de malla, este debe separarse con UV después del atlas de texturas. Si se crea el atlas después de crear el elemento de malla, mediante herramientas de creación de atlas o de combinación en el software de pintura, la isla UV deberá volver a organizarse según la textura.

Agrupa en lotes las llamadas de dibujo específicas del motor

El motor de juego de Unity tiene una función de agrupación en lotes de llamadas de dibujo que puede combinar objetos automáticamente. Para hacerlo, estos deben compartir un material en común, incluidas las texturas, y deben estar marcados como estáticos.

Unreal Engine 4 requiere una configuración manual para agrupar en lotes. Puedes combinar objetos en software 3D antes de importarlos a Unreal. Unreal también incluye la herramienta UE4 Actor Merging, que puede combinar mallas y crear archivos de atlas de texturas.

Genera mipmaps

Los mipmaps son versiones de una textura con menor resolución. Una colección de mipmaps para una textura determinada se denomina cadena de mipmap. En una cadena, cada nivel posterior de ellos tiene menor resolución que el nivel anterior. Los mipmaps se usan para implementar el nivel de detalle (del inglés LOD) de texturas durante la renderización. Cuando una textura con mipmap se vincula a una etapa de textura, el hardware gráfico utiliza el espacio de textura que ocupa un fragmento para elegir un nivel de la cadena de mipmap. Cuando se renderiza una escena en 3D, el objeto alejado de la cámara usará un mapa MIP con menor resolución que el que se encuentre más cerca de la cámara.

Una textura con mipmap consume más memoria comparada con una sin ellos. Los niveles adicionales de mipmap aumentan un 33% el consumo de memoria de una textura. Si se dibuja una textura a una distancia fija de la cámara, la generación de mipmap representa un uso innecesario de la memoria.

Una cadena de mipmap de una resolución de textura base de 512 x 512 píxeles
Figura 2: Una cadena de mipmap de una resolución de textura base de 512 × 512 píxeles.

El uso correcto de mipmaps mejora el rendimiento de la GPU. La disponibilidad de los niveles de mipmap con menor resolución reduce el uso del ancho de banda de la memoria y mejora la residencia de texturas en caché.

La generación de mipmaps también puede mejorar la calidad visual mediante la reducción de superposición de texturas. La superposición de texturas se puede observar como un efecto parpadeante en áreas más alejadas de la cámara.

Un ejemplo de superposición de texturas
Figura 3: Un ejemplo de superposición de texturas. Una imagen se renderiza sin mipmaps (izquierda), y la otra imagen con ellos (derecha). La superposición de texturas se puede observar dentro del rectángulo rojo en la imagen de la izquierda.

Detalles de mipmaps específicos del motor

Para usar mipmaps, Unreal Engine 4 requiere dimensiones de textura que sean múltiplos de dos (p. ej., 512 x 1024, 128 x 128). Si una o ambas de las dimensiones de textura no son múltiplos de dos, no se generarán las cadenas de mipmaps.

Para crear mipmaps, el motor de Unity escalará automáticamente las texturas con dimensiones que no sean potencia de dos. Asegúrate de que las dimensiones de los archivos de textura de origen sean múltiplos de dos para evitar este escalamiento.

Selecciona los modos correctos para el filtrado de texturas

El filtrado de texturas es una función de renderización de hardware que afecta la apariencia visual de un triángulo renderizado. El uso correcto del filtrado de texturas puede mejorar la calidad visual de una escena. Existen varios modos para el filtrado de texturas, cada uno con un balance diferente entre la mejora de renderización y el costo. El costo incluye el tiempo de procesamiento y el ancho de banda de memoria. Los tres modos más frecuentes para el filtrado de texturas disponibles son el modo (o punto) más cercano, el filtrado bilineal y el filtrado trilineal. El filtrado anisotrópico es un método adicional para texturas que se puede combinar con el filtrado bilineal o trilineal.

Modo más cercano

El modo más cercano es el método de filtrado de texturas más simple y menos costoso. Este modo realiza muestras de un solo téxel usando coordenadas especificadas en la textura de origen. Los triángulos renderizados con el modo más cercano tendrán un aspecto pixelado o en forma de bloques, en especial cuando se renderizan cerca de la cámara.

Filtrado bilineal

El filtrado bilineal realiza muestras de los cuatro téxeles que rodean las coordenadas especificadas en la textura de origen. Estos cuatro téxeles se promedian a fin de determinar el color de textura para el fragmento. El filtrado bilineal produce un gradiente más suave entre los píxeles, lo que evita la apariencia en forma de bloques del filtrado más cercano. Los triángulos renderizados que se encuentran más cerca la cámara se verán borrosos en lugar de pixelados. Esta clase de filtrado cuesta más que el más cercano debido a las muestras de téxel y el cálculo del promedio adicionales.

Comparación entre el filtrado más cercano y el bilineal
Figura 4: Una comparación entre el filtrado de texturas más cercano (izquierda) y el bilineal (derecha).

Filtrado trilineal

Cuando renderizas una malla en la que varía la distancia de los vértices de la cámara, se pueden seleccionar varios niveles de mipmaps durante la renderización. Los cambios entre dos niveles de mipmaps pueden generar un corte nítido y notable en el punto de transición. Para suavizar estas transiciones, el filtrado trilineal realiza uno bilineal en dos niveles de mipmaps diferentes y, luego, interpola los resultados. Debido al uso de varios niveles de mipmaps y la interpolación, el filtrado trilineal es más costoso en términos de procesamiento si se lo compara con el bilineal.

Una comparación entre el filtrado de texturas bilineal y el trilineal
Figura 5: Una comparación entre el filtrado de texturas bilineal (izquierda) y el trilineal (derecha). La región ampliada contrasta la diferencia de renderización en las transiciones de mipmaps.

Filtrado anisotrópico

El filtrado anisotrópico aumenta la calidad visual de las mallas con texturas que se renderizan en un ángulo extremo en relación con la cámara. Un ejemplo frecuente de esta clase de malla son los planos del terreno. Para funcionar, el filtrado anisotrópico requiere texturas con mipmaps. Durante la renderización, se puede configurar la proporción o el nivel del filtrado anisotrópico que se aplica. El costo del filtrado anisotrópico aumenta a medida que lo hace el nivel.

Una comparación entre un filtrado anisotrópico de nivel 1 y uno de nivel 2
Figura 6: Una comparación entre el filtrado bilineal y el filtrado anisotrópico de nivel 1 (izquierda) y el filtrado bilineal y el filtrado anisotrópico de nivel 2 (derecha).

Estrategia para seleccionar el modo

Por lo general, el filtrado bilineal es el mejor equilibrio entre el rendimiento y la calidad visual. El filtrado trilineal requiere un ancho de banda de la memoria significativamente mayor y debe usarse de manera selectiva. En muchos casos, el filtrado bilineal combinado con el filtrado anisotrópico de nivel 2 se verá mejor y tendrá un mejor rendimiento que el filtrado trilineal con filtrado anisotrópico de nivel 1. El aumento de los niveles anisotrópicos para que superen el nivel 2 es demasiado costoso, y debe hacerse de manera muy selectiva para elementos esenciales del juego.

El filtrado de texturas podría representar hasta la mitad del consumo total de energía de la GPU. Una excelente manera de reducir las demandas de energía del juego es elegir filtros de texturas más simples siempre que sea posible.

Optimiza los tamaños de las texturas

Asegúrate de que las dimensiones de las texturas sean lo más pequeñas posible teniendo en cuenta la calidad de la imagen que deseas. Revisa los elementos de textura para comprobar si, por error, se crearon texturas grandes. Este principio aplica a las texturas discretas y las de atlas. Si el juego admite muchos dispositivos que abarcan una gran variedad de capacidades de resolución y rendimiento, considera crear versiones con baja y alta resolución de los elementos de textura para la clase correcta de dispositivos.

Cuando renderices una malla que usa varias texturas en su material, considera reducir la resolución de algunas texturas de manera selectiva. Por ejemplo, cuando se usa una textura difusa de 1024 x 1024, es posible reducir la aspereza o la textura metálica del mapeo de textura a 512 x 512 con solo un impacto mínimo en la calidad de la imagen. Verifica el impacto de todos estos experimentos en el cambio de tamaño para asegurarte de que no afecten el nivel de calidad que deseas.

Usa el espacio de color correcto

Muchos paquetes de software que se usan para crear texturas operan en el espacio de color sRGB y exportan con este. Es posible que las texturas difusas, que se procesan como color, usen el espacio de color sRGB. Las texturas que no se procesan como color, como los mapas de texturas metálicas, de aspereza o normales, no se deben exportar al espacio de color sRGB.

La configuración de texturas de los motores de juego incluye un parámetro para determinar si una textura usa el espacio de color sRGB.

Parámetros de configuración de texturas sRGB en Unity y Unreal Engine 4
Figura 7: Parámetros de configuración de texturas sRGB en Unity (izquierda) y Unreal Engine 4 (derecha).

Como los datos de píxeles de estas texturas no se utilizan como datos de color, el uso del espacio de color sRGB producirá imágenes incorrectas.

Una renderización de un mapa de textura metálica y de aspereza en el filtrado lineal en comparación con el espacio de color sRGB
Figura 8: Un mapa de textura metálica y de aspereza lineal que no usa sRGB (izquierda) y un mapa de textura metálica y de aspereza que usa sRGB (derecha). Los reflejos de la derecha parecen incorrectos.

Usa la compresión de texturas

La compresión de texturas es un algoritmo de compresión de imágenes que se aplica a datos de píxeles sin comprimir y que genera una textura que el hardware de gráficos puede descomprimir con rapidez durante la renderización. El uso efectivo de la compresión de texturas puede reducir el uso de memoria y aumentar el rendimiento con un impacto mínimo en la calidad visual. En Android, los tres algoritmos más frecuentes para la compresión de texturas son ETC1, ETC2 y ASTC. En el caso de los juegos modernos, ASTC suele ser la primera mejor opción, y ETC2 es una opción de resguardo por si el juego se orienta a dispositivos que no admiten ASTC.

ETC1

ETC1 es compatible con todos los dispositivos Android. ETC1 solo admite un único modo de cuatro bits por píxel de datos de color RGB. ETC1 no admite canales alfa. Muchos motores de juego que admiten ETC1 permiten designar una segunda textura ETC1 para que represente los datos de los canales alfa.

ETC2

ETC2 es compatible con más del 90% de los dispositivos Android activos. Los dispositivos muy antiguos que no son compatibles con la API de OpenGL ES 3.0 no pueden usar ETC2. En comparación con ETC1, ETC2 agrega lo siguiente:

  • Compatibilidad con canales alfa, tanto "perforación" de ocho bits como de un bit
  • Versiones sRGB de texturas RGB y RGBA
  • Texturas de uno y dos canales, R11 y RG11

ASTC

ASTC es compatible con más del 75% de los dispositivos Android activos. ASTC tiene tamaños de bloques de compresión configurables, lo que brinda un control detallado y equilibra la proporción de compresión con la calidad de la imagen para una textura determinada. Con frecuencia, ASTC logra una calidad superior con el mismo tamaño de memoria que ETC2, o bien puede alcanzar una cantidad similar con una memoria más pequeña que ETC2.

Una comparación visual de los formatos de compresión de texturas con la misma imagen de origen
Figura 9: Una comparación entre imágenes sin comprimir (izquierda, con un tamaño de 17 MB), comprimidas con ETC1 (centro, con un tamaño de 3 MB) y comprimidas con ASTC (derecha, con un tamaño de 2.5 MB).

Velocidad de la compresión de texturas

La compresión de texturas puede demorar mucho tiempo si el juego tiene demasiadas. Tanto en ETC como ASTC, se pueden seleccionar parámetros de configuración para la calidad de compresión. Los parámetros de mayor calidad requieren más tiempo para comprimir. Durante el desarrollo, te recomendamos que disminuyas el nivel de calidad para reducir el tiempo de compresión y aumentar el nivel de calidad antes de crear compilaciones importantes.

Compresión de texturas en motores de juego

Si usas un motor de juego, es posible que debas elegir el formato de compresión de texturas (ETC o ASTC) a nivel del proyecto. Para brindar la máxima compatibilidad, podría necesitarse trabajo adicional admitir varios formatos de compresión. La función de orientación de formato de compresión de texturas de Google Play Asset Delivery puede ayudarte a incluir varios formatos en el juego y entregar únicamente el formato más óptimo para un dispositivo individual en el momento de la instalación.

Extiende las islas UV

Mantén la isla UV lo más recta posible, ya que ayuda a la textura de las siguientes maneras:

  • El empaquetado de las islas UV es más sencillo, lo que genera menos desperdicio de espacio.
  • Las islas UV rectas reducen el "efecto escalera" en las texturas.
  • El empaquetado correcto de las islas UV garantiza que la textura brinde una resolución óptima.
  • Se obtienen texturas de mejor calidad, incluso si las islas UV están ligeramente distorsionadas por enderezarlas.
Una isla UV no optimizada frente a una isla UV optimizada
Figura 10: Una isla UV no optimizada (izquierda) y una isla UV enderezada y extendida (derecha).

En un modelo, las uniones visibles de las texturas no lucen bien. Ubica las uniones UV en lugares en los que sean menos visibles. A fin de crear mapas normales de mejor calidad, divide la isla UV en donde los bordes sean nítidos y deja espacio alrededor de la isla.

Evita detalles imperceptibles

Cuando creas elementos artísticos, no agregues detalles que no se verán, en especial en los juegos diseñados para dispositivos con pantallas más pequeñas. Crear una textura de 4096 x 4096 con detalles complejos es un desperdicio para un modelo de silla pequeña que apenas se puede ver en la esquina de una habitación. En algunos casos, es posible que debas exagerar los bordes (agregar elementos destacados adicionales) y el sombreado para mejorar la percepción de la forma.

Uso de una textura pequeña en un modelo que se renderiza a distancia
Figura 11: En un modelo de un soldado renderizado a distancia, se usa una textura pequeña de 256 × 256 sin demasiados detalles.

Integra los detalles

Los dispositivos móviles tienen pantallas más pequeñas y hardware gráficos con menor potencia si se los compara con las computadoras personales o las consolas de juegos. En lugar de calcular efectos, como la oclusión del ambiente o el destacado especular en el tiempo de ejecución, considera integrarlos en la textura difusa cuando sea posible, ya que ayuda al rendimiento y garantiza la visibilidad de los detalles.

Integración de elementos destacados y oclusión del ambiente en una textura difusa
Figura 12: Los elementos destacados y la oclusión del ambiente integrados en la textura difusa (izquierda) y renderizados en el juego (derecha).

Ajusta el tono de color

Si tienes la capacidad de crear sombreadores personalizados y cuentas con mallas que tienen un esquema de colores similar o uniforme, considera ajustar el tono de color en las mallas que correspondan. Con el ajuste del tono de color, se usa una textura en escala de grises, que requiere menos memoria de textura que una textura RGB. El sombreador aplica los datos de color por vértice para colorear la malla. Como método alternativo para ajustar el tono, puedes usar una máscara RGB y aplicar la textura según el rango de colores de la máscara.

Una textura en escala de grises cuyo tono se ajustó en el tiempo de ejecución
Figura 13: Textura en escala de grises (izquierda) cuyo tono se ajustó en el tiempo de ejecución para el modelo de columna (derecha).

Empaqueta los canales de texturas

Cuando renderices materiales con varias texturas, considera la posibilidad de combinar las texturas que solo usen un canal de color en una sola textura que utilice los tres canales de color. De esta manera, se reduce el uso de memoria y, además, se disminuye la cantidad de operaciones de muestras de texturas que realiza el sombreador de fragmentos.

Tres texturas de un solo canal combinadas en una textura multicanal
Figura 14: Tres texturas de un solo canal (izquierda) que se combinan en una textura multicanal (derecha). Los datos de la oclusión del ambiente se asignan al canal rojo, el mapa de aspereza y suavidad al verde, y el mapa de textura metálica al azul.

Cuando realices el empaquetado, asigna los datos con más detalles al canal verde. Como el ojo humano es más sensible al verde, por lo general, el hardware de gráficos asigna más bits al canal de este color. Por ejemplo, con frecuencia, un mapa de aspereza y suavidad tendrá más detalles que un mapa de textura metálica y es una mejor opción para asignar al canal verde.

En el caso de los materiales que usan un canal alfa, si solo usas dos canales en la textura empaquetada, considera colocar los datos del canal alfa en la textura empaquetada en lugar de hacerlo en la textura difusa. Según el formato de la textura difusa, esto puede ayudarte a reducir su tamaño o aumentar la calidad visual si omites los datos del canal alfa.

Un canal alfa empaquetado en otra textura
Figura 15: Un mapa de opacidad de un canal alfa empaquetado en una textura junto con un mapa de aspereza y suavidad, y uno de textura metálica.

Asegúrate de que las texturas empaquetadas estén configuradas en un espacio de color RGB lineal y no en uno sRGB.

Crea mapas normales

El mapeo normal es una técnica que le brinda a un modelo 3D la apariencia de los detalles sin usar geometría adicional. Las características, como arrugas o pernos que podrían requerir muchos triángulos para modelar, se pueden simular con un mapa normal. Es posible que el mapeo normal sea adecuado o no, según el estilo artístico y la dirección del juego.

Modelo renderizado con y sin un mapa normal
Figura 16: Un modelo renderizado sin un mapa normal (izquierda), el mismo modelo renderizado con un mapa normal (centro) y el mapeo de textura normal (derecha).

Los mapas normales generan cierto costo de rendimiento y deberían usarse con moderación en dispositivos de gama baja. El mapa normal requiere una textura adicional, lo que produce una muestra de texturas y cálculos del sombreador de fragmentos adicionales.

Prácticas recomendadas para mapas normales

A continuación, se mencionan algunas prácticas recomendadas para crear mapas normales:

Usa un contenedor

Un contenedor es una versión más grande, o extendida, del modelo con pocos polígonos. Necesita incluir el modelo con gran cantidad de polígonos para que funcione bien durante la integración normal del mapa. El contenedor se usa para limitar la distancia de la proyección de rayos durante la integración normal del mapa y ayuda a evitar problemas con las uniones normales divididas en el mapa normal.

Contenedor que rodea la malla con pocos polígonos.
Figura 17: Un contenedor que rodea la malla de pocos polígonos.
Un modelo renderizado mediante un mapa normal con y sin un contenedor
Figura 18: Un modelo renderizado a través de un mapa normal generado con un contenedor (izquierda) en comparación con un modelo renderizado mediante un mapa normal generado sin un contenedor (derecha).

Realiza la integración por coincidencia con el nombre de la malla

Si el software de integración lo admite, realiza la integración por coincidencia con el nombre de la malla. Esta función mitiga el problema de proyectar, de manera incorrecta, un mapa normal. Cuando los objetos están demasiado cerca entre sí, pueden proyectar, de manera inesperada, su mapa normal en la superficie incorrecta. La coincidencia con el nombre de la malla garantiza que la integración solo se lleve a cabo en la superficie correcta. Para obtener más información sobre esta función de Substance Painter, consulta esta página. Para obtener más información sobre esta función en Marmoset Toolbag, consulta esta página.

Expande la malla

Considera expandir la malla si no puedes lograr que coincida con el nombre de la malla durante la integración. Si la expandes, se separarán las partes entre sí, de modo que el mapa normal no se proyectará en la superficie incorrecta. Si también realizas la integración para la oclusión del ambiente, es posible que debas llevar a cabo la integración por separado sin expandir la malla.

Una malla expandida para integrar el mapa normal
Figura 19: Una malla expandida para integrar el mapa normal.

Minimiza las uniones

Las islas UV continuas en los bordes rígidos causarán uniones visibles; divide las UV en estos bordes para minimizar ese efecto. Cuando configuras grupos de suavizado, como regla general, mantén el ángulo inferior a 90 grados. Las uniones UV deben tener un grupo de suavizado diferente en los triángulos.