OPENGL ES 2.0 Knowledge Talk (10) —— OPENGL ES Explicación detallada IV (Optimización de textura)

Revisión de la sección anterior

En la sección anterior, aprendimos cómo obtener la información necesaria para generar una textura a partir de una imagen original, y luego generar una textura en la memoria de la GPU a través de la API de OpenGL ES en base a esta información, y también introdujimos las propiedades de la textura, sabiendo cómo para asignar la textura al búfer de dibujo por coordenadas de textura. Si bien comprendemos la importancia de las texturas, también sabemos que en la aplicación, el tamaño de la textura afecta el tamaño del paquete de la aplicación y también ocupa la mayor parte de la memoria de la aplicación. La optimización es un trabajo muy importante. Entonces, a continuación, debemos optimizar la textura. En esta lección, nos centraremos en el procesamiento de varios formatos de textura comprimida, cómo administrar texturas en la memoria y resumiremos algunas de las mejores formas de usar texturas.

textura comprimida

A través del estudio de la lección anterior, sabemos que la textura es en realidad un búfer. Este búfer almacena la información de múltiples píxeles al multiplicar el ancho de la textura, como una textura con un ancho y alto de 100 * 100. Entonces esto buffer El buffer almacena la información de tantos píxeles, sin embargo, el espacio ocupado por la información de cada píxel está determinado por el formato de la textura, por ejemplo, la textura cuyo formato es GL_RGBA y tipo GL_UNSIGNED_BYTE requiere cada píxel en la CPU. 4 bytes de espacio. Sin embargo, si el formato es GL_RGB y el tipo también es una textura GL_UNSIGNED_BYTE, cada píxel en la CPU necesita ocupar 3 bytes de espacio. De manera similar, la información de estas dos imágenes se pasa a la GPU para generar After la textura, la primera textura ocupará mucho espacio en la GPU. Por lo tanto, el tamaño del espacio ocupado por la textura está relacionado con el tamaño de la textura y el formato de la textura. En el caso de un mismo formato, cuanto mayor sea el tamaño de la textura, mayor será el espacio ocupado. En el caso del mismo tamaño de textura, algunos formatos ocupan mucho espacio y algunos formatos ocupan poco espacio. Por supuesto, las texturas que ocupan mucho espacio pueden expresar más información, por ejemplo, GL_RGBA tiene un canal alfa más que GL_RGB. Pero si ambos formatos pueden expresar suficiente información, intentaremos elegir el formato que ocupe menos espacio para ahorrar espacio en la memoria. Los formatos de textura que mencionamos antes son todos formatos comunes. En esta lección, presentaremos un nuevo formato de textura, que es el formato de textura comprimida. Es concebible que este formato de textura comprima la información de textura. Aunque cierta información de textura se perderá. de acuerdo con la relación de compresión, lo que da como resultado una menor precisión de textura, pero si la precisión de las imágenes de textura no es particularmente alta, el uso de texturas comprimidas puede ahorrar mucho espacio en la memoria.

Las texturas ocupan mucho espacio, lo que tendrá tres efectos: 1. Si hay muchas texturas sin ningún procesamiento, el paquete del juego será relativamente grande y será problemático para los usuarios instalarlo, lo cual no es bueno; 2. Texturas Es relativamente grande, y la textura debe transmitirse desde la CPU del cliente a la GPU, lo que requerirá más ancho de banda, y la transferencia de datos también consume mucha energía. 3. Ocupa la memoria principal cuando está en la CPU, y después de pasar a la GPU, también ocupará la memoria de la GPU. Aunque el desarrollo de teléfonos móviles es relativamente rápido en la actualidad, todavía hay algunos teléfonos móviles con memoria 1-2G en el mercado.Si la memoria es demasiado grande, puede causar una mala experiencia del usuario, como bloqueos del juego.

Por lo tanto, existen varios métodos de optimización para texturas que consumen energía, afectan la experiencia del usuario, ocupan memoria y deben usarse. El primer método de optimización es comprimir texturas. A continuación, presentaremos el concepto, las características y el uso de las texturas comprimidas.

Sabemos que los esquemas de compresión tradicionales, como las imágenes JPG y PNG en sí mismas, son imágenes comprimidas y han sido comprimidas hasta cierto punto, pero las imágenes en estos formatos pueden reducir el tamaño de los recursos y el tamaño del paquete, pero la información al cargar en la GPU , debe descomprimirse y hay una parte de memoria ocupada en la GPU para almacenar texturas, por lo que después de que estas imágenes comprimidas y las imágenes ordinarias se transfieran a la GPU, la memoria de GPU ocupada es la misma. Los pasos específicos son: cuando los datos de un gráfico se transfieren a la memoria de la GPU, deben transferirse a la GPU a través de la API glTexImage2D, y esta API solo reconoce GL_RGBA y otros formatos, por lo que estas imágenes comprimidas deben descomprimirse a GL_RGBA o GL_RGB y otro formato sin comprimir, se puede pasar a la GPU. Por lo tanto, estas imágenes comprimidas no son muy significativas, a lo sumo solo hacen que el paquete del juego sea más pequeño. Y aunque el paquete del juego se hace más pequeño, también agrega un proceso de descompresión, y cuando se transmite a la GPU, todavía se transmite en el formato normal. En 1996, tres profesores de Stanford publicaron un artículo llamado "Renderizado basado en texturas comprimidas", que proponía un método de compresión de texturas basado en GPU, que permite a la GPU muestrear y renderizar directamente desde texturas comprimidas, lo que también permite comprimir texturas. . Este tipo de textura comprimida necesita usar imágenes originales especiales en el lado de la CPU, es decir, imágenes en formato PVR o ETC. Estas imágenes almacenan la información para generar texturas comprimidas. El tamaño de estos archivos es más pequeño que el de JPG, PNG y otras imágenes, y Al transmitir a la GPU, no es necesario usar la API glTexImage2D, pero sí usar la API dedicada glCompressedTexImage2D para texturas comprimidas.A través de esta API, la información de la imagen se puede transmitir directamente a la GPU sin descompresión, y luego la información se puede mantener en un estado comprimido para el almacenamiento.En la GPU, este método no solo puede reducir el tamaño de los recursos, sino también ahorrar el ancho de banda de la transferencia de datos de la CPU a la GPU y reducir el uso de memoria de la GPU . A continuación usaré el formato PVR para ilustrar las texturas comprimidas. El formato PVR es un formato de compresión de texturas definido y autorizado por imagenation. Actualmente es un formato de compresión muy utilizado en el campo del desarrollo de juegos. La GPU generada por imagenation se llama powervr. La GPU es totalmente compatible con el formato pvr y la GPU powervr es la GPU oficial de Apple, por lo que los dispositivos de Apple, como el iPhone, básicamente admiten la textura comprimida de PVR. Las imágenes en formato pvr usan pvr como sufijo. Comprimir texturas tiene las siguientes ventajas:

1) Las imágenes pvr son originalmente más pequeñas que las imágenes jpg y png, por lo que la experiencia del paquete del juego es relativamente pequeña.
2) OpenGL ES API glCompressedTexImage2D reconoce el formato de PVR, por lo que los datos de la imagen pvr se pueden transferir directamente a la GPU sin descompresión, y los datos en el formato PVR original son menos, por lo que los datos que deben transmitirse también son muy poco, ahorrando ancho de banda.
3) Después de pasar a la GPU, no es necesario descomprimirlo, por lo que ahorra memoria.

En comparación con las texturas ordinarias y nuestras técnicas de compresión conocidas, las texturas comprimidas deben tener las siguientes cuatro características:

1) Aunque no hay necesidad de descomprimir cuando se importa por primera vez a la GPU, aún debe descomprimirse cuando se usa. Para no afectar el rendimiento del sistema de renderizado, la textura comprimida debe descomprimirse más rápido, para garantizar que se pueda descomprimir rápidamente al usarlo. La tecnología de compresión que solemos utilizar está diseñada principalmente para almacenamiento o transferencia de archivos, y no tiene una velocidad de descompresión rápida.
2) Admite una lectura precisa. De acuerdo con el contenido de la lección anterior, sabemos que leeremos la información de algunos píxeles en la textura de acuerdo con las coordenadas de la textura, y se puede usar cualquier posición en la textura, por lo que necesitamos Primero, los elementos de textura en cualquier posición de la textura se pueden ubicar de manera rápida y precisa, y luego estos píxeles se pueden descomprimir antes de que se puedan usar. Por lo tanto, la tecnología para comprimir texturas debe poder ubicarse de manera rápida y precisa. Para garantizar la máxima relación de compresión, la tecnología de compresión tradicional generalmente utiliza una relación de compresión variable. De esta manera, si desea leer la información de un determinado píxel, es difícil ubicarlo de manera rápida y precisa, y a menudo necesita para descomprimir una gran parte de los píxeles relevantes. La información puede leer la información de un píxel. La tecnología de textura comprimida generalmente adopta una compresión de relación fija. Siempre que la relación fija conozca el coeficiente de relación de compensación y compresión, al acceder a los texeles, puede ubicar rápidamente un bloque determinado de acuerdo con el bloque de índice y luego obtener la información de texel requerida. Por ejemplo, si los 10 000 datos originales se comprimen en 100 datos, si desea leer el punto medio, su posición cambiará del 5000 al 50, de modo que, de acuerdo con esta proporción, pueda ubicar con precisión el punto de píxel requerido. . Los formatos como PVR se comprimen en una proporción fija, mientras que los formatos como JPG y PNG se comprimen en una proporción no fija. Dado que las características de lectura precisas de las texturas comprimidas están relacionadas con el mecanismo de implementación de las texturas comprimidas, aquí explicamos cómo se implementan las texturas comprimidas. La textura comprimida se comprime según una relación de compresión fija. El algoritmo de compresión primero dividirá la textura en varios bloques de píxeles según esta relación. Por ejemplo, la textura 100*100 que acabamos de mencionar tiene 10 000 puntos, y estos 10 000 puntos serán dividido en bloques, y asumimos que la relación de compresión es 4, es decir, 4 puntos son un bloque, luego la imagen se divide en 2500 bloques, cada bloque contiene la información de estos 4 puntos, y luego el bloque es Unidad para comprimir , comprima la información de estos 4 puntos y almacene la información de cada píxel comprimido en un conjunto de píxeles, de modo que se obtengan 2500 conjuntos de píxeles comprimidos, y luego haga un conjunto de estos 2500 conjuntos de píxeles El mapa de índice de bloque se utiliza para almacenar la posición del índice de cada bloque de píxeles, para que el archivo de bloque correspondiente se pueda encontrar fácilmente. Luego transfiera la textura comprimida a la GPU. Cuando sea el momento de usar, puede determinar a qué punto de la textura ir de acuerdo con las coordenadas de la textura, y luego calcular a qué bloque pertenece este punto y el desplazamiento en este bloque, y luego de acuerdo con el bloque El mapa de índice encuentra este bloque de píxeles y lo descomprime. La descompresión aquí solo necesita descomprimir este bloque pequeño, por lo que no ocupará mucha memoria. , y luego lea el valor de textura que necesitamos del contenido descomprimido de acuerdo con el desplazamiento. De esta manera, se logra una lectura precisa, y este algoritmo de compresión, conocido como algoritmo de compresión basado en bloques, comprime y descomprime en bloques. En la operación real, los datos de un bloque de píxeles también se pueden almacenar en caché de acuerdo con la situación real. Esta descompresión rápida permite que la canalización de procesamiento de gráficos guarde la textura comprimida directamente en la memoria de la GPU en lugar de descomprimir la imagen en la CPU, lo que no solo reduce la ocupación de recursos del disco, sino que también reduce la textura ocupada durante el proceso de transmisión. , y también ahorra en gran medida el uso de la memoria de la GPU. Este algoritmo de compresión basado en bloques es más común en texturas comprimidas.Sin embargo, existen otros formatos de texturas comprimidas, como el formato PVR de primera generación PVRTC, que utiliza diferentes algoritmos de lectura y compresión de texturas, y no continuará expandiéndose aquí. dicho.
3) La mayoría de las técnicas tradicionales de compresión de imágenes tienen que considerar la calidad de la imagen. Para la tecnología de compresión de texturas, cada textura es solo una parte de la escena, y la calidad general de representación de la escena es más importante que una sola imagen. La compresión de texturas no necesita preocuparse demasiado por la calidad de la compresión. Lo primero es garantizar el rendimiento del juego, por lo que las texturas comprimidas suelen utilizar texturas con pérdida.
4) No preste demasiada atención a la velocidad de codificación, ya que el proceso de compresión de texturas se lleva a cabo fuera de la aplicación y fuera de línea, no cuando el usuario está jugando, por lo que no se requiere una alta velocidad de codificación. Imagination proporciona una herramienta llamada PVRTextureTool para que los desarrolladores generen imágenes PVR fuera de línea. De hecho, es lento, pero dado que no afectará la experiencia del usuario, la velocidad de compresión no importa. La principal restricción del uso de texturas comprimidas es la velocidad de descompresión.

El método de compresión de texturas que cumple con las características anteriores no solo puede reducir el tamaño del recurso de imagen original, reducir el ancho de banda del cliente del programa de aplicación para transmitir datos de textura a la GPU, reducir el consumo de energía del dispositivo móvil, sino también reducir en gran medida la ocupación de la memoria GPU Y puede cooperar con GPU para una representación eficiente. Además, en términos de uso, en OpenGL ES, las texturas comprimidas se usan básicamente de la misma manera que otras texturas. También se muestrean a través de coordenadas de textura y admiten texturas multinivel. Excepto por la transferencia de texturas a través de la API especial glCompressedTexImage2D, otras Los aspectos son casi indistinguibles de las texturas normales. Hablando de texturas multinivel, de hecho, las texturas comprimidas son más avanzadas que las texturas ordinarias. También dijimos en la última lección, porque las imágenes ordinarias como las imágenes JPG generalmente no contienen información de textura multinivel, y los formatos de textura comprimida como Las imágenes PVR se pueden pasar directamente a través de PrvTexTool. Dichas herramientas incluyen texturas multinivel en un archivo de imagen, de modo que el multinivel de una textura se puede asignar directamente a través de un archivo, mientras que las imágenes normales pueden requerir múltiples imágenes para asignar multinivel. de una textura. Sin embargo, generar texturas de varios niveles mediante la asignación de valores ocupa más espacio de almacenamiento, pero no es necesario generarlo al usarlos.

Lo anterior es el concepto básico de textura comprimida. Los códigos como la generación de texturas y el establecimiento de propiedades de textura no distinguen entre texturas comprimidas y texturas sin comprimir. La única diferencia es que las texturas comprimidas usan glCompressedTexImage2D, mientras que las texturas no comprimidas usan glTexImage2D. Presentemos glCompressedTexImage2D en detalle.

void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);

La función de glCompressedTexImage2D es la misma que la de glTexImage2D: transfiere los datos preparados del lado de la CPU al lado de la GPU y los guarda en el objeto de textura especificado. La única diferencia es que glTexImage2D transfiere los datos utilizados para generar texturas ordinarias, que se generan en la GPU, mientras que glCompressedTexImage2D transfiere los datos utilizados para generar texturas comprimidas, que se generan en la GPU.

Los parámetros de entrada de esta función no son muy diferentes de los parámetros de entrada de glTexImage2D. El primer parámetro de entrada significa especificar el tipo de objeto de textura, que puede ser GL_TEXTURE_2D, o uno de los lados de la textura del mapa de cubos 6, a través de GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CU BE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE _MAPA_POSITIVO_Z, o GL_TEXTURE_CUBE_MAP_NEGATIVE_Z para especificar, dijimos que la textura del mapa de cubos en realidad se compone de 6 texturas 2D, por lo que esta función se usa para asignar una textura 2D. Si se pasan otros parámetros, se informará un error INVALID_ENUM. El segundo se refiere a la asignación de la primera capa de la textura. Ya hemos mencionado el concepto de textura multinivel en la lección anterior. El nivel aquí es el número de capas asignadas a la textura para la asignación. La capa 0 es el nivel base. Como acabo de decir, una imagen PVR puede contener todos las texturas de texturas multinivel Los datos requeridos, es decir, los datos leídos de una imagen original PVR, se pueden asignar a varios niveles de una textura a través de esta API. Si el nivel es inferior a 0, se producirá un error GL_INVALID_VALUE. Y el nivel no puede ser demasiado grande, si el nivel excede log2 (máximo), habrá un error GL_INVALID_VALUE. El máximo aquí se refiere a GL_MAX_TEXTURE_SIZE cuando el objetivo es GL_TEXTURE_2D y GL_MAX_CUBE_MAP_TEXTURE_SIZE cuando el objetivo es otros casos. El tercer parámetro, internalformat, es para especificar el formato en la GPU después de que los datos originales se transfieran a la GPU. Puede pasar el parámetro GL_NUM_COMPRESSED_TEXTURE_FORMATS a través de glGet API, puede consultar la cantidad de formatos de textura comprimida compatibles con el dispositivo actual, pasar el parámetro GL_COMPRESSED_TEXTURE_FORMATS, puede consultar qué formatos de textura comprimida admite el dispositivo actual, si el formato interno que el dispositivo actual el dispositivo actual no es compatible, aparecerá Error GL_INVALID_ENUM. El cuarto parámetro ancho y el quinto parámetro alto son el ancho y el alto de la imagen original, así como el ancho y el alto de la textura recién generada, porque los dos son iguales. La información de la imagen se transmite de la CPU a la GPU en forma de datos, y el formato y la información contenida en cada píxel pueden cambiar, pero el tamaño de la imagen, es decir, la cantidad de píxeles, cuántos píxeles hay en cada línea, y cuántas líneas en total, esta información no cambia. El ancho y la altura no pueden ser menores a 0, ni pueden exceder GL_MAX_TEXTURE_SIZE cuando el objetivo es GL_TEXTURE_2D, o exceder GL_MAX_CUBE_MAP_TEXTURE_SIZE cuando el objetivo es otros casos, de lo contrario, se producirá un error GL_INVALID_VALUE. El sexto parámetro, borde, representa si la textura tiene borde o no, aquí debe escribirse como 0, es decir, no hay borde, si se escribe como otro valor, se producirá un error GL_INVALID_VALUE. El significado del séptimo parámetro y el último parámetro de entrada es: los datos son una parte de la memoria en la CPU que apunta a los datos reales, y el tamaño de la imagen especifica el tamaño de la información de textura comprimida a partir de la ubicación de los datos en esta memoria, y el la unidad es un byte sin firmar. Si los datos no son nulos, se leerán datos de bytes sin firmar del tamaño de la imagen desde la ubicación de datos en el lado de la CPU, y luego se transferirán desde el lado de la CPU y el formato actualizado se guardará en el objeto de textura en el lado de la GPU. Si el tamaño de la imagen no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia. Si el tamaño no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Cabe señalar aquí que debido a que una imagen pvr puede contener información de texturas de varios niveles en una imagen, cada vez que se genera un nivel de información de textura, esta función debe llamarse una vez, y el segundo nivel de parámetro se llama cada vez. , y los dos últimos parámetros, el tamaño y la ubicación de los datos cambiarán en consecuencia.

Esta función no tiene parámetros de salida, pero hay varias situaciones en las que se producirán errores. Además de los errores de entrada de los parámetros que acabamos de mencionar, y aunque la especificación principal de OpenGL ES no especifica el formato de textura comprimida, OpenGL ES tiene algunas extensiones para estas compresiones. El uso de texturas está restringido. Por ejemplo, algunos formatos de textura comprimida requieren que el ancho y alto de la textura sea un múltiplo de 4 (pvr). Si la combinación de parámetros no está de acuerdo con las regulaciones en la extensión , se producirá un error de GL_INVALID_OPERATION. Y si los datos guardados en data no guardan los datos correctos de acuerdo con la extensión, entonces habrá resultados como no definir, o el programa terminará.

void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid * data);

La función de esta API es similar a glCompressedTexImage2D en este momento.Como sugiere el nombre, la API en este momento es para pasar datos al objeto de textura, y este glCompressedTexSubImage2D es para pasar datos a una parte del objeto de textura. Este comando no cambiará el formato interno, el ancho, la altura, los parámetros y el contenido del objeto de textura que no sea la parte especificada.

Los parámetros de entrada primero y segundo de esta función son los mismos que los de glCompressedTexImage2D, que se utilizan para especificar el tipo de objeto de textura y qué capa de mipmap debe asignarse a la textura. La situación de error es la misma que glCompressedTexImage2D. Si el objetivo pasa un valor no admitido, aparecerá un error de GL_INVALID_ENUM. Si el nivel pasa un número incorrecto, aparecerá un error de GL_INVALID_VALUE. Los parámetros de entrada tercero, cuarto, quinto y sexto significan: comenzando desde el comienzo del objeto de textura, el ancho se compensa con las posiciones de compensación x y la altura se compensa con las posiciones de compensación y. con un ancho de unidades de ancho y un alto de alto utiliza una pieza de datos de memoria en la CPU apuntada por datos. El formato de esta pieza de datos de memoria es el séptimo parámetro, y el tamaño es el octavo parámetro imageSize. Para este espacio cubrir. El formato aquí y el tercer parámetro internalformat de glCompressedTexImage2D tienen el mismo significado.Si se pasa un formato que no es compatible con el dispositivo actual, se producirá un error GL_INVALID_ENUM. Si el tamaño de la imagen no coincide con el formato, el ancho y el alto de la textura comprimida y los datos realmente almacenados en data, se producirá un error GL_INVALID_VALUE. Si uno de xoffset, yoffset, ancho y alto es negativo, o xoffset+width es mayor que el ancho de la textura, o yoffset+height es mayor que el alto de la textura, se producirá un error INVALID_VALUE. No importa si el ancho y el alto son ambos 0, pero este comando no tendrá efecto.

Esta función no tiene parámetros de salida. Además de los errores causados ​​por el problema del parámetro justo ahora, si la textura especificada por el destino no ha sido glCompressedTexImage2D, el espacio se asigna en el formato interno correspondiente al formato de textura comprimida del formato. Aparecerá un error GL_INVALID_OPERATION. Si la combinación de parámetros no está de acuerdo con lo establecido en la extensión correspondiente al formato de textura comprimida, por ejemplo, algunos formatos comprimidos no permiten reemplazar solo una parte del contenido, entonces a través de esta API, solo xoffset=yoffset=0 , y el ancho y el alto son el ancho y el alto reales de la textura; de lo contrario, se producirá un error GL_INVALID_OPERATION. Y si los datos guardados en data no guardan los datos correctos de acuerdo con las regulaciones de la extensión, habrá resultados como no definir o el programa terminará.

Introduzcamos el formato de texturas comprimidas. Acabamos de usar el formato de texturas comprimidas de pvr para hablar de ello. De hecho, todavía hay muchos formatos de texturas comprimidas. Diferentes GPU admiten diferentes formatos de texturas comprimidas. Por ejemplo, varios formatos de PVR y ETC, por lo que antes de usar el formato de textura comprimida, aún debe confirmar si el dispositivo actual lo admite. En OpenGL ES2.0, aunque la API glCompressedTexImage2D está definida para que las aplicaciones carguen texturas comprimidas, OpenGL ES2.0 no define ningún formato de compresión de texturas, por lo que el formato de las texturas comprimidas generalmente lo definen los fabricantes de hardware de gráficos o algunas organizaciones de terceros. . Me di cuenta, y los formatos de compresión admitidos por cada GPU son básicamente diferentes. Por ejemplo, como dije hace un momento, Apple usa GPU powerVR, y el mejor soporte es PVR. Todos los dispositivos iOS admiten texturas comprimidas PVR. . El teléfono móvil Android cumple con el estándar khronos, y la mayoría de los dispositivos Android básicamente admiten el formato ETC. Como hemos presentado antes, khronos es una organización autorizada que formula una serie de especificaciones como OpenGL ES. Estos son los valores predeterminados para todos, pero para otros formatos de compresión, debe consultar la información de soporte de hardware específico, por lo que si desea saber qué formatos de compresión admite la GPU, debe usar la API glGetString para pasar GL_EXTENSIONS, de modo que pueda Puede obtener todas las extensiones compatibles con el dispositivo. Luego consulte las extensiones correspondientes a qué formatos de textura comprimida son compatibles en estas listas de extensiones, para saber qué formatos de textura comprimida admite el dispositivo. Por lo tanto, al usar texturas comprimidas al escribir juegos, es mejor usar estas funciones para confirmar qué formatos de textura comprimida son compatibles. Para decir algo más adelante, de hecho, en OpenGL ES3.0, se proporciona un estándar de textura comprimida, es decir, glCompressedTexImage2D debe admitir ciertos formatos, por lo que al usar texturas comprimidas de estos formatos, no es necesario verificar.

Permítanme presentarles los dos formatos de compresión de PVR y ETC.

El primero es PVR. PVR se divide en dos formatos de compresión, PVRTC y PVRTC2. En comparación con PVRTC2, las actualizaciones realizadas por PVRTC2 son las siguientes: 1. pvrTC2 comenzó a admitir texturas NPOT, 2. Calidad de imagen mejorada, especialmente en algunos de alto contraste , grande 3. Mejor compatibilidad con la premultiplicación alfa. La premultiplicación alfa es un algoritmo de optimización. Presentaremos la premultiplicación alfa en cursos posteriores.

Tanto PVRTC como PVRTC2 admiten dos relaciones de compresión de 2bpp y 4bpp, lo que significa que la información de un píxel se puede comprimir a 2 o 4 bits, sabemos que la información de un píxel sin comprimir puede tener 16 o 32 bits, por lo que la compresión La relación es bastante alta y PVR admite canal alfa. El canal alfa sigue siendo muy útil.Muchos de los formatos de textura que mencionamos en la última lección tienen alfa, como GL_RGBA. Aunque el PVR es compatible con alfa, si no puede usar el canal alfa, intente no usarlo. Por ejemplo, una imagen RGBA32, cada píxel ocupa 32 bits, 4 bytes, comprimidos en pvr 4bpp, y una imagen RGB24, cada píxel ocupa 24 bits, comprimidos en pvr 4bpp. Si el tamaño comprimido es el mismo, entonces la tasa de pérdida de la imagen RGBA32 debe ser mayor que la de la imagen RGB24 para lograr el mismo tamaño después de la compresión, lo que significa que la calidad de la imagen RGB24 es mejor después de la compresión.

Imagination proporciona una herramienta llamada PVRTextureTool para el procesamiento de imágenes en formato PVR. A través de esta herramienta, se pueden crear mapas de cubos, texturas de fuentes y texturas de varios niveles, pero lo más importante es generar texturas comprimidas en formato pvr. Además del formato pvr, PVRTextureTool también admite la conversión de formatos png, etc. Las herramientas de conversión de uso común incluyen el empaquetador de texturas para gráficos y la herramienta de texturas que viene con Xcode en el sistema iOS.

Luego, hablemos de ETC. El formato ETC es un formato de compresión propuesto por Ericsson en 2005. Tanto ETC como PVR son formatos de textura comprimidos con pérdida que admiten una relación de compresión de 4bpp y no admiten canales alfa. Se puede ver desde aquí que ETC todavía no es tan bueno como PVR. Dado que ETC no es compatible con el canal alfa, pero muchas texturas requieren información alfa, existen dos soluciones: 1. Por ejemplo, al crear una imagen que originalmente era una imagen GL_RGBA en ETC, primero, primero convierta la información RGB de tres canales. se comprime en una imagen ETC, y luego la altura de esta imagen ETC se duplica. El ancho y la altura del espacio adicional son los mismos que el ancho y la altura de la imagen original. De esta manera, el valor alfa de la imagen original se comprime en este espacio, para hacer una imagen en escala de grises. El resultado final es obtener una imagen ETC, pero la altura de esta imagen es el doble de la original, la mitad inferior es la información RGB de la imagen original y la mitad superior es la imagen en escala de grises convertida a partir de la información alfa de la imagen original. . De esta forma, la aplicación necesita muestrear la textura una vez más en PS, muestreo RGB de cada punto y muestreo A una vez. Pero esta solución es limitada, porque aumenta el tamaño de la textura, y el tamaño de la textura está limitado en la GPU. El ancho y la altura no pueden exceder GL_MAX_TEXTURE_SIZE, y hay una altura máxima. Generalmente, el límite máximo es 2048. Luego, si la altura de la imagen original excede 1024, entonces duplique el tamaño, excederá 2048, excederá el límite y se informará un error. Entonces, al usar esta solución, la altura de la imagen original debe ser inferior a la mitad de GL_MAX_TEXTURE_SIZE. 2. Por ejemplo, cuando la imagen GL_RGBA original se convierte en ETC, se crean dos imágenes ETC, una se usa para almacenar información RGB y la otra se usa para almacenar información alfa, generando así dos texturas comprimidas, y Estas dos texturas comprimidas use un esquema de textura múltiple, y se envían al mismo sombreador al mismo tiempo, y luego toda la información RGBA de la imagen original se puede usar en este sombreador. La textura múltiple se mencionó en la última lección, por lo que no la explicaré aquí. La herramienta de compresión de textura Mali proporcionada por Arm puede manejar estas dos soluciones muy bien.

ETC2 ahora es compatible con el canal alfa, pero después de comprimir RGBA en ETC2, es 8bpp, cuando RGB se comprime en ETC2, es 4bpp, y cuando RGB se comprime en ETC1, también es 4bpp, por lo que todavía ocupa mucho de espacio, pero la tasa de pérdida de compresión de ETC2 es peor que la de ETC1, aunque todavía no es tan buena como la de PVR. Unity proporciona un formato de compresión llamado etc2 RGB + 1bit alpha 4bpp, es decir, si el alpha es de solo 1bit, se puede comprimir a este formato de 4bpp etc2, para que finalmente se guarde la memoria.

Otros formatos de textura comprimida se utilizan de manera similar a estos dos formatos, por lo que concluye la parte de la textura comprimida. Aunque OpenGL ES3.0 proporciona un estándar de textura comprimida para que todas las plataformas puedan usar el mismo formato de textura comprimida, llevará mucho tiempo que los dispositivos actuales en el mercado popularicen por completo OpenGL ES3.0. Por lo tanto, todavía necesitamos usar diferentes formatos de textura comprimida para diferentes dispositivos. Al comprimir texturas, el paquete del juego se vuelve más pequeño, el ancho de banda también se ahorra al transferir texturas y la huella de memoria en la GPU también es menor. Este es el primer paso de la optimización de texturas. A continuación, hablaremos sobre el segundo paso de la optimización de texturas, caché de texturas, caché de texturas.

caché de textura

La API para la optimización de texturas en los puntos de conocimiento de OpenGL ES 2.0 solo tiene texturas comprimidas. Podemos reducir el uso de memoria de las texturas seleccionando un formato de imagen apropiado o usando texturas comprimidas. Sin embargo, dado que la optimización de texturas es demasiado importante, aquí hay algunas más. Método de optimización de texturas. Las texturas comprimidas son solo para una sola textura, y se necesita usar una gran cantidad de texturas en el juego, por lo que debe haber un mecanismo para administrar las texturas, administrar la carga, el uso y la destrucción de texturas, tratar de evitar lo mismo. la textura se cargue repetidamente e intente Eliminar las texturas no utilizadas para ahorrar memoria. A continuación, presentaremos el mecanismo de almacenamiento en caché de texturas para administrar el ciclo de vida de cada textura en la escena.

El propósito del caché de textura es: Aunque una textura se puede optimizar comprimiéndola, se necesita usar una gran cantidad de texturas en el juego, y muchas texturas se usarán más de una vez. -cargar, por ejemplo, en el juego Plants vs. Zombies, hay 10 girasoles idénticos y cada girasol usa la misma textura, así que si tengo que volver a cargar la textura cada vez que dibujo un girasol, entonces debe hacerlo sea ​​malo, lo mejor La solución es que solo subo una textura, que pueden usar estos 10 girasoles. Y si llama a glTexImage2D o glCompressedTexImage2D para cargar texturas al dibujar girasoles, no es bueno, porque estas dos API toman una cierta cantidad de tiempo, lo que puede causar que el juego se bloquee. Además, si el siguiente cuadro necesita usar una cierta textura, pero debido a la falta de memoria, la textura se eliminó de la memoria en el cuadro anterior, entonces no es bueno. En otras palabras, es: el objetivo principal del sistema de caché de texturas es hacer que las texturas que deben mostrarse en la escena actual residan en la memoria, y la responsabilidad del desarrollador es definir qué recursos necesita usar la escena actual. siempre debe ingresar La precarga de texturas relevantes en una escena es un proceso que lleva mucho tiempo, y este proceso se completa en el hilo principal, que no es adecuado para leer y cargar durante el juego, por lo que se debe evitar la carga dinámica de texturas. Además, la textura solo debe crearse 1 vez durante su uso. Entonces la solución es implementar tres funciones:

1) Al ingresar a la escena, cargue todas las texturas que se utilizarán en esta escena.
2) Todos los girasoles usan la misma textura.
3) Cuando la escena ya no necesite girasoles y no esté dibujando nuevos girasoles, elimine la textura de girasol para guardar memoria. Estas soluciones se implementan a través de caché de texturas.

Echemos un vistazo al ciclo de vida de la textura primero. Cuando se crea la textura 2D, cargará los datos del disco y los cargará en la memoria de la GPU. Luego, antes de que se destruya la Textura 2D, la GPU siempre almacenará en caché el objeto de la textura. que puede ser destruido por glDeleteTexture.texturity2D object. Si administra la textura directamente controlando el objeto texture2D, debemos manejar el ciclo de vida de la textura 2D con cuidado. Debe eliminarse después de que la textura ya no se use, y también debemos prestar atención al hecho de que la textura puede no ser usado temporalmente Si lo elimina accidentalmente Sí, debe volver a crearse la próxima vez que se use. Entonces, en resumen, es muy complicado manejarlo de esta manera, por lo que generalmente no creamos objetos de textura 2D directamente, sino que creamos y destruimos objetos de textura 2D a través de la caché de texturas. texturecache proporciona una mejor manera de administrar objetos Texture2D.

El caché de textura es una instancia única. Si crea una textura a través de este caché de textura, primero verificará si hay una textura correspondiente a la imagen original almacenada en el caché de textura original. Si la hay, puede usarla directamente. Si no, cree una textura, guardada en el caché de textura, para este momento y más tarde si es necesario. Cada vez que se crea, el recuento de referencias de textura se incrementa en 1. Entonces, si crea N texturas que usan la misma textura, entonces el recuento de referencias de textura es N+1, e incluso al cambiar de escena, debido a que el caché de textura es una sola instancia, la textura no se liberará, por lo que aunque todas las texturas se se liberará al cambiar de escena. La textura se borra, luego el recuento de referencia de la textura sigue siendo N + 1 - N = 1. Por lo tanto, no importa cómo cambies de escena, la textura añadida al caché de texturas siempre existirá, lo que cumple la segunda función del caché de texturas que acabamos de mencionar. No importa cuántos girasoles se dibujen, incluso si son girasoles en diferentes escenas. , Usa la misma textura.

La tercera función que acabamos de mencionar, cuando se determina que la textura ya no se usa, se espera que la textura se pueda eliminar. Pero de acuerdo con nuestro cálculo del recuento de referencias en este momento, siempre que la textura se agregue al caché de texturas, a menos que el caché de texturas desaparezca, el recuento de referencias de texturas será al menos 1, es decir, la textura no puede ser automáticamente eliminado por el sistema. Pero no importa, la caché de texturas puede proporcionar algunas funciones de eliminación de texturas, como la función removeUnusedTextures, a través del análisis del recuento de referencias en este momento, también sabemos que si la textura no se usa, entonces el recuento de referencias es 1 , y la función removeUnusedTextures es establecer Se liberan todas las texturas no utilizadas con un recuento de referencia de 1. Pero esta función es un poco mala. Por ejemplo, no hay girasoles o tiradores de guisantes en la escena actual. Borré todas las texturas de girasoles y tiradores de guisantes, pero es posible que tenga que crear tiradores de guisantes más tarde, así que tengo que recrearlos. textura arriba. Por lo tanto, la caché de texturas debe tener las funciones removeTexture y removeTextureForKey, de modo que solo la textura del girasol se elimine directamente, porque el desarrollador sabe que el girasol se puede eliminar en este momento, pero el tirador de guisantes sigue siendo útil, así que primero elimine la textura de girasol por separado Lose. Pero es posible que todavía haya girasoles en la escena en este momento, y el recuento de referencia de la textura no sea 1. Luego, a través de esta función, el recuento de referencia se reducirá en 1. Por ejemplo, hay 2 girasoles en el escena, entonces el conteo de referencia cambiará de 3 a 2. Cuando Después de que los dos girasoles en la escena también sean destruidos, el conteo de referencia será 0, y la textura será destruida. Además, se necesita removeAlltexture, es decir, si el juego está a punto de finalizar y estas texturas nunca se volverán a usar, entonces suelte todas las texturas, y el caché de texturas ya no guardará ni se preocupará por la información de estas texturas. finaliza la escena, estas La textura será completamente destruida. Entonces, el caché de texturas usa estas funciones para permitir que los desarrolladores eliminen texturas de acuerdo con la lógica del juego.

De esta forma, queda por resolver la primera función que es la de cargar todas las texturas que se van a utilizar al inicio del juego, esto debe ser controlado por el propio desarrollador, pero por supuesto la caché de texturas también debe proporcionar algunas relacionadas. se implementan las funciones. Por ejemplo, si necesito usar 300 texturas en la primera escena, de acuerdo con este requisito funcional, necesito precargar 300 texturas al comienzo del juego, pero será muy difícil precargar tantas texturas a la vez. está atascado, si todo se procesa en el primer cuadro, entonces el primer cuadro puede tardar mucho tiempo en esperar. Sin embargo, la caché de texturas necesita la función addImageAsync, que divide 300 texturas en 300 cuadros y carga previamente una textura para cada cuadro. Si se reparte así, no quedará muy pegado. Este es el método proporcionado por el caché de texturas para la precarga.

Y esto no es suficiente, porque aunque implementa la precarga, varios sprites que usan la misma textura usan la misma textura, pero cuando se elimina la textura del caché de textura, en realidad debe ser controlado por el propio desarrollador. En pocas palabras, los desarrolladores deben eliminar texturas de acuerdo con la lógica del juego, pero si todas las texturas requieren que los desarrolladores controlen la lógica, será un poco complicado. De hecho, aquí también presentaremos algunos mecanismos para ayudar a los desarrolladores a controlar.

Veamos primero los requisitos para la gestión de recursos en el juego real. Por lo general, solo se deben realizar algunos cálculos lógicos en el bucle del juego para actualizar el estado de varios objetos del juego. Para no afectar el ciclo del juego, debemos precargar todos los archivos de recursos requeridos al ingresar a la escena, o en algún otro momento asíncrono, almacenarlos en caché y eliminar el caché cuando sea apropiado para reducir el uso de memoria. Sin embargo, cada recurso tiene diferentes requisitos en el ciclo de vida, los ejemplos son los siguientes:

1) Algunos recursos deben cargarse al comienzo del juego y residir en la memoria hasta el final del juego, como algunos elementos comunes a cada escena, como los botones.
2) El ciclo de vida de algunos recursos corresponde a una escena específica, por ejemplo, cierto jefe solo aparece en cierto nivel, el cual pertenece a los recursos que necesita especialmente ese nivel, y otros niveles no lo necesitan.
3) Es difícil definir el ciclo de vida de algunos recursos. Por ejemplo, los recursos en los juegos de parkour están relacionados con la distancia recorrida por el jugador. En este momento, la precarga dinámica debe realizarse con cuidado.

No podemos simplemente usar el caché de texturas para resolver perfectamente esta textura. En este momento, los desarrolladores deben pensar en qué etapa se encuentra esta escena, qué texturas se pueden eliminar y, al cambiar de escena, también deben juzgar qué texturas están en la siguiente escena. También se utilizan escenas. Por lo tanto, existe un mecanismo de administración de texturas que los desarrolladores pueden usar para administrar la situación cuando se usa una textura en dos escenas consecutivas. Por ejemplo, la textura 123 se usa en la primera escena y la textura 234 se usa en la segunda escena.Si elimina toda la textura 123 a través de removeAlltexture al cambiar de escena, entonces al ingresar a la escena 2, 234 se eliminará nuevamente. de estas dos texturas se acaban de borrar, y se vuelven a cargar, lo que provocará un desperdicio. Entonces puede ser así, usando el conteo de referencias, al cambiar de escena, no ejecute primero la función removeAlltexture, de modo que cuando finalice la escena actual, los conteos de referencia de las texturas restantes en esta escena sean todos 1, y luego ingrese el siguiente escena, y la siguiente El número de referencias de la textura que debe usarse en la escena aumenta en uno, por lo que, según el ejemplo de ahora, el número de referencias de la textura 1 sigue siendo 1, el número de referencias de la textura 23 se convierte en 2, y el recuento de referencia de la textura 4 es 1, y luego la escena de ahora El recuento de referencia de la textura utilizada se reduce en uno, de modo que el recuento de referencia de la textura 1 se convierte en 0, el recuento de referencia de la textura 23 se convierte en 1, y el recuento de referencia de la textura 4 sigue siendo 1. En este momento, elimine la textura con un recuento de referencia de 0 y elimine la textura 1 se elimina, y la textura 23 permanece en la escena 2 sin eliminarse. A continuación, cargue el que tenga un recuento de referencias distinto de 0 y, dado que la textura 23 no se ha eliminado, no se volverá a cargar, solo se debe cargar la textura 4. De esta manera, después de cambiar entre dos escenas, solo se necesita cargar 4 texturas en total, de las cuales la textura 23 solo se carga una vez, mientras que antes, se necesita cargar un total de 6 texturas y la textura 23 se debe cargar dos veces Esta solución ahorrará recursos. De esta forma, podemos gestionar con flexibilidad el uso compartido de recursos entre varias escenas y reservar de forma efectiva solo los recursos necesarios en cada escena. Para cada escena o nivel, solo necesitamos definir una lista de todos los recursos que necesita, y el administrador de recursos precargará los datos requeridos antes de ingresar a la escena o nivel, y los eliminará cuando abandone la escena o nivel. H.

Permítanme expandirme aquí. De hecho, no solo las texturas se pueden administrar a través de este mecanismo. Además de las texturas, hay muchos otros recursos de información, como datos de audio. Estos recursos también pueden usar este mecanismo para administrar recursos a nivel de escena o de nivel. Los recursos se almacenan en caché a través del caché, y la reutilización de recursos entre escenas se resuelve mediante el recuento de referencias.

Hay otra área en la que los desarrolladores deben controlarse a sí mismos. Como se mencionó anteriormente, los juegos grandes, como el parkour, usan muchas texturas. Aunque se usa la carga asíncrona al entrar en escena, todavía no es muy buena. Es mejor para el desarrollador para controlarlo y cargarlo en etapas. Es decir, precarga dinámica. La precarga dinámica no carga recursos al comienzo de la escena, ni carga recursos cuando es necesario. En su lugar, se debe estimar cuidadosamente que esos recursos se usarán pronto y cargar dinámicamente los recursos relacionados por adelantado en Demanda, como parkour. Puede cargar los recursos que se utilizarán en los primeros 50 KM cuando ingrese por primera vez a la escena, y luego cargar los recursos nuevamente a los 50 KM, y así sucesivamente, cargando nuevos recursos cada 50 KM. En resumen, necesitamos basarse en las características del juego. Muchos esquemas de precarga asincrónicos se definen en él para lograr una experiencia de juego fluida y fluida en escenas enormes.

Resumir

La textura es un contenido importante en todas las aplicaciones gráficas, y su uso inadecuado puede conducir fácilmente a problemas graves de rendimiento, memoria, consumo de energía y otros. Sin embargo, la textura no es una parte independiente en la aplicación, está íntimamente relacionada con cada sistema.

nivel de hardware

1) Mejorar la velocidad de transmisión de texturas. En la capa inferior, puede interactuar con la GPU. Al optimizar la GPU, se pueden lograr operaciones de datos como una transmisión más rápida y una lectura de píxeles. Por lo tanto, a nivel de hardware, las empresas de motores de juegos, como cocos y unity, tratarán con las empresas de hardware para ver si pueden aumentar la velocidad de carga del hardware, de modo que la textura se pueda transferir más rápido de la CPU a la GPU.
2) Aumente la memoria e intente almacenar en caché las texturas. Además de mejorar la velocidad de transmisión de datos, otra forma es aumentar la memoria. También dijimos anteriormente que si el siguiente cuadro necesita usar una textura, pero antes de usarla, la textura acaba de eliminarse debido a memoria insuficiente. Entonces esto la textura debe recargarse, por lo que esta situación es muy mala, por lo que si puede almacenar en caché tantas texturas como sea posible en la GPU, esto aumentará la tasa de aciertos del caché de textura, que también es muy bueno.
3) Formato especial de textura comprimida. El aspecto más importante a nivel de hardware es admitir texturas comprimidas especiales. De esta manera, las empresas de motores de juegos pueden proporcionar soluciones que se adapten mejor al hardware en función de su comprensión del hardware.
Por supuesto, incluso si la empresa del motor del juego no requiere la mejora en los tres aspectos anteriores, la empresa del hardware lo hará. Casi todos los fabricantes de hardware proporcionarán algunas optimizaciones específicas para sus productos de hardware. Estas optimizaciones se pueden utilizar para mejorar las texturas. Velocidades de transferencia más rápidas, velocidades de lectura de datos más rápidas y optimización para cálculos en ciertos tipos de datos. Y estos suelen estar diseñados con alguna extensión GL especial, por supuesto, la mejora de rendimiento que trae también es obvia. Por lo tanto, las empresas de juegos solo necesitan cooperar con estas empresas de hardware.

nivel de software

1) Precarga de texturas. En el lado de la aplicación, hay mejores formas de administrar y usar texturas, principalmente en función de lo que proporciona el motor. Por tanto, a nivel de software, lo primero es precargar siempre las texturas con antelación para evitar cargar recursos de forma dinámica mientras se ejecuta el juego. Por lo general, debemos cargar los activos con anticipación al ingresar a un nivel u otras ocasiones, y dejarlos residir en la memoria hasta que el activo ya no se use. Si lo hace, puede mejorar el rendimiento de representación de la aplicación sin causar una mala experiencia como la tartamudez. También introdujimos la función de carga previa proporcionada por el caché de texturas anterior, y también introdujimos una forma de administrar los recursos basada en el conteo de referencias, para que la carga previa de varios recursos se pueda manejar bien, así como entre escenas y niveles. Transición.
2) Eliminar texturas no utilizadas. Reduzca el uso de texturas no utilizadas y elimine los recursos de textura que ya no se utilizan. Esto requiere que los desarrolladores definan claramente el ciclo de vida de cada recurso. Algunas funciones que puede proporcionar la caché de texturas, así como los métodos de gestión de recursos basados ​​en el recuento de referencias, pueden ayudar a los desarrolladores a gestionar fácilmente el ciclo de vida de los recursos y liberar los recursos no utilizados a tiempo. Los desarrolladores solo necesitan describir el ciclo de vida del uso de texturas. Además, también podemos calcular manualmente el tamaño de la memoria que ocupa la textura para limpiar manualmente algunos recursos. Los dos puntos anteriores se han introducido en detalle anteriormente y no se explicarán aquí.
3) Fusión de texturas. Combine texturas pequeñas en texturas grandes para reducir los tiempos de dibujo. Aunque el DC no tiene mucho impacto en el rendimiento ahora, cambiar el estado de renderizado entre dos DC todavía provoca una gran cantidad de consumo de energía de la CPU, por lo que fusionar texturas, fusionar VBO, IBO y reducir DC ahorra mucho tiempo de CPU. debe prestar atención a una cosa, debido a la fusión de texturas, la presión del ancho de banda aumentará (se pasan demasiadas texturas e información de BO al mismo tiempo), por lo que para evitar el límite de rendimiento en el ancho de banda, haga un equilibrio 4) Use texturas multinivel
. El uso de texturas multinivel puede reducir el uso de la memoria de la GPU. Los dispositivos inteligentes de hoy en día tienen diferentes resoluciones y las diferencias son enormes. Las aplicaciones generalmente se diseñan con resoluciones relativamente altas. En este caso, no tiene sentido usar texturas grandes para modelos con resoluciones relativamente pequeñas. Por ejemplo, si la resolución de un teléfono móvil es 800 600, pero el tamaño de nuestra textura original es 10241024, de hecho, la pantalla de todo el teléfono móvil no es tan grande, y el tamaño de esta textura en el teléfono móvil puede ser solo 512 512, por lo que si no hay una textura multinivel, pero si sigues usando una gran textura de resolución, necesita usar la textura de 1024 1024, 512 512 información de valor de píxeles se muestrea , por lo que el resultado final es que solo se extrae información de 512 512 píxeles de esta gran textura . Por lo tanto, para algunos dispositivos de baja resolución, solo cargue el nivel correspondiente de texturas multinivel. Podemos decidir qué nivel de textura multinivel usar calculando la resolución del dispositivo y la resolución del recurso, reduciendo así el desperdicio de memoria del dispositivo de gama baja. Además, el uso de texturas multinivel puede reducir el uso del ancho de banda de la memoria, ya que solo es necesario cargar mipmaps de bajo nivel, es decir, se carga menos información en la GPU y también se reduce el uso de estos anchos de banda de la memoria. Además, usar texturas multinivel es más rápido cuando la GPU toma muestras de la textura, porque originalmente necesitaba analizar y obtener 512 512 píxeles de 1024 1024 píxeles , pero ahora solo necesita analizar y obtener datos de 512*512 píxeles, por lo que la eficiencia del muestreo mejorará considerablemente y el rendimiento de la renderización mejorará hoy. Pero las texturas multinivel ocuparán más memoria de CPU, aproximadamente 1/3 más de memoria, por lo que es un método para intercambiar memoria de CPU por ancho de banda y memoria de GPU.
5) Usa múltiples texturas. El propósito también es reducir las llamadas de dibujo. Por ejemplo, queremos dibujar un sol y una casa. Estos dos objetos corresponden a una textura. Si no se usan texturas múltiples, primero usaremos la textura del sol y VBO e IBO para dibujar Sale el sol, y luego la casa se dibuja de acuerdo con la textura de la casa, VBO e IBO, por lo que debe dibujarse dos veces, y debido a que los dos dibujos se realizan en serie, lleva mucho tiempo. Sin embargo, si usamos múltiples texturas, pase las texturas del sol y la casa a la tubería de renderizado al mismo tiempo, luego combine el VBO y el IBO del sol y la casa, haga la lógica en el sombreador, use dos conjuntos de uv coordenadas, múltiples texturas pueden usar la capacidad de ejecución paralela de la GPU para reducir el cambio de tubería, etc., puede mejorar efectivamente el rendimiento de representación.De esta manera, el sol y la casa se pueden dibujar con una sola llamada. Entonces, deberíamos intentar pasar más texturas en lugar de dibujar varias veces en un comando de dibujo.
6) El último método es utilizar la premultiplicación alfa, que puede reducir la cantidad de cálculo de texturas transparentes al mezclar escenas.

nivel de recursos

En cuanto a los recursos, el formato de textura utilizado, el tamaño, etc., todos tienen un impacto directo en el rendimiento de la aplicación. Antes de comenzar a hablar sobre la optimización de esta pieza, déjame decirte cómo calcular el tamaño de memoria que ocupan las texturas.

Aunque el tamaño de la textura puede usar algunas herramientas para ver el uso de memoria de la textura, como OpenGL ES Analytics que viene con Xcode, etc., en la aplicación, todavía es muy necesario calcular el uso de memoria de la textura. . Por un lado, podemos imprimir el tamaño de la memoria en cada momento durante el juego y asociar estos usos de memoria con texturas específicas, para que podamos optimizar mejor el uso de texturas, como algunos recursos son demasiado grandes, o Algunos recursos tardan demasiado, etc. Por otro lado, durante el proceso de ejecución, el tamaño de la memoria informática puede establecer algunos valores de advertencia para la aplicación, a fin de liberar los recursos de textura a tiempo para lograr el mejor rendimiento.

A continuación, hablemos de cómo calcular el tamaño de memoria que ocupan las texturas. A través de los conocimientos relacionados con los formatos de textura explicados anteriormente, podemos calcular fácilmente la memoria que ocupan las texturas. La fórmula de cálculo es: tamaño de memoria que ocupan las texturas = ancho de textura * textura Alto*bpp. La unidad del resultado calculado aquí es bit, y el nombre completo de bpp es bit por píxel, es decir, cuántos bits ocupa cada píxel. Por ejemplo, en el formato RGBA8888, cada píxel ocupa 32 bits, por lo que la textura con una resolución de 1024 1024 ocupa un espacio de memoria de 1024 1024*32 = 4 MB. Por lo tanto, siempre que se conozca el formato de la textura, se puede calcular el tamaño de memoria ocupado por la textura.

Por lo tanto, a nivel de recursos, podemos reducir el tamaño de los recursos de alguna manera.

1) Usa texturas en un formato razonable. Por ejemplo, si los bpp de GL_RGBA8888 y GL_RGBA4444 son 32 y 16 respectivamente, el uso de un formato de textura de 16 bits requerirá la mitad de memoria que un formato de textura de 32 bits, por lo que para las texturas que no requieren alta precisión, el uso de GL_RGBA4444 puede ahorra mucha memoria. Otro ejemplo es que algunas texturas que se usan para imágenes no transparentes, como los fondos, pueden usar formatos como GL_RGB 565. Dado que no se requieren canales alfa, no se usan formatos de textura con canales alfa, lo que también puede reducir en gran medida el uso de memoria. También hay imágenes simples correspondientes al canal alfa, puede usar el formato de textura de GL_RGBA5551.
2) El segundo método es usar texturas comprimidas. Por ejemplo, el bpp del formato PVR es 2 o 4, y la relación de compresión es muy alta. Esta solución se ha presentado en detalle anteriormente, por lo que no se explicará aquí.
Las texturas son una parte importante del desarrollo del juego. La importancia de las texturas a menudo se revela en las últimas etapas del desarrollo del juego. Los primeros programas y artistas a menudo usan texturas, efectos especiales y animaciones sin escrúpulos. Solo cuando se acerca el lanzamiento, de repente se enfrentarán a problemas extremadamente serios como la memoria y el consumo de energía. e incluso afectar el juego Juego publicado texturas. Por lo tanto, esta clase y la última clase discutirán el conocimiento relevante de las texturas desde varios ángulos. Espero que todos puedan aclarar los detalles de varios aspectos relacionados con las texturas para lograr la optimización en todos los aspectos, para que el juego tenga un mejor rendimiento y experiencia.

Supongo que te gusta

Origin blog.csdn.net/u012124438/article/details/128446705
Recomendado
Clasificación