Estoy desarrollando un juego en 2D y tengo muchos sprites. Usé animaciones 3D y modelos para renderizar en 2D, para darles ese aspecto de "Fallout" o "Diablo". También es más fácil que dibujar a mano, jajaja.
Ya he tenido que reducir la velocidad de fotogramas a 15 fps, que fue la más baja que pude bajar sin hacer que tengan un aspecto entrecortado. Sin embargo, fue triste debido a lo increíblemente suave que se veían los 24 cuadros.
Hay dos razones por las que hice esto:
1) Reduzca el espacio en el disco duro. Cuantas menos imágenes, más pequeño será mi juego total.
2) Reducir el consumo de RAM. Cuantas menos imágenes se carguen, más probabilidades tendré de evitar problemas que hinchen mi limitación de RAM.
Sin embargo, si hubiera una manera de comprimir las imágenes tanto en el espacio del disco duro como en la RAM, lo haría. Lo he probado antes, y la mayoría no recibe ningún cambio en la calidad cuando doy de RGBA8888 a RGBA5555 y solo un pequeño golpe al convertir a RGBA4444 en mi programa TexturePacker. Actualmente no hago esto, porque SFML parece usar la misma cantidad de memoria independientemente del tipo de imagen .PNG que sea. Busqué investigar cómo cargarlo de manera diferente, pero no pude encontrar nada sobre el tema.
He leído mucho sobre cómo manejar los videojuegos en 2D. El consenso es abrumador: empaca tus Sprites en una textura más grande para un gran rendimiento. Así que empaco mis pequeños sprites en una hoja de sprites mucho más grande usando TexturePacker.
Sin embargo, planeo tener 10-15 animaciones por personaje, 5 direcciones para mover y 15-40 cuadros por animación (probablemente un promedio de 24). Con 15 animaciones, 5 direcciones y un promedio de 24 cuadros por animación; Eso es 1800 fotogramas individuales por personaje. Si se empaqueta en una hoja de sprite, solo son 75 imágenes. (Una hoja de sprites por Animación, por Dirección. 15 * 5)
Para el gran personaje jefe en el juego, no puedo usar una hoja de sprites y tengo que programar una forma de cargar simplemente una imagen a la vez. Todavía no sé si puedo hacer esto por rendimiento.
Para los personajes, ya los empaqué en una hoja de sprites. Para un solo personaje caminando, esto parece funcionar la mayor parte del tiempo, aunque a veces se detiene. Sin embargo, lo atribuyo a mi código mal concebido que intercambia texturas en lugar de precargar todas las texturas para ese personaje.
Si tuviera que precargar las texturas, tiene sentido para las hojas de sprites. Solo me imagino que es una mala idea precargar 1800 imágenes pequeñas para cada personaje.
Sin embargo, imagino que transmitirlos dentro y fuera de la memoria uno a la vez sería extremadamente rápido, por lo que solo necesitaría tener una sola imagen en la memoria al mismo tiempo. ¿No significa esto que en un momento dado solo haría que cada personaje consumiera unos pocos KB en lugar de 45 + MB?
Me imagino que esto mataría mi rendimiento, ya que la transmisión tendría que ser increíblemente rápida (15 imágenes que entran y salen de la memoria y la representación, por segundo) y aunque las imágenes serían muy pequeñas, podría ser una mejor idea cargar hojas de sprites de caracteres en memoria en su lugar. Pero tendré que codificar un sistema de renderizado de flujo de una sola imagen para mi personaje jefe más grande de todos modos.
He estado experimentando, pero no es un proceso simple. Especialmente dado el hecho de que estoy trabajando en otras partes del motor del juego que no manejan gráficos en este momento.
Respuestas:
Tenemos un caso similar con nuestro RTS Remake. Todas las unidades y casas son sprites. Tenemos 18 000 sprites para unidades y casas y terreno, más otros ~ 6 000 para colores de equipo (aplicados como máscaras). De largo alcance también tenemos unos ~ 30 000 caracteres utilizados en las fuentes.
Entonces, la razón principal detrás de los atlas son:
Lo que no funcionó para nosotros:
Ahora tenemos todo empaquetado en varias docenas de atlas de 1024x1024 (las GPU modernas admiten dimensiones aún más grandes) y eso funciona bien comiendo solo ~ 300 mb de memoria, lo cual es bastante bueno para un juego de PC. Algunas optimizaciones que tuvimos:
Cuando considere seriamente cambiar a dispositivos móviles, se preocupará por las restricciones. ¡Por ahora solo haz que el juego funcione y atrae a los jugadores! ;)
fuente
Tengo una respuesta tangencialmente relacionada en aquí , pero la idea general es que, si está cargando y dibujando texturas en diferentes momentos (no está cargando texturas adicionales mientras está renderizando), entonces hay dos lugares donde hacer afectará su rendimiento:
Tiempo de carga:
Este es el momento en que carga sus texturas en la memoria. la totalidad cantidad de datos que está enviando a VRAM es lo que definirá principalmente cuánto tiempo durará su carga. Hacer que sus texturas tengan formatos más pequeños, como RGBA4444, lo hará más rápido. Sin embargo, a menos que esté cargando texturas en los cientos de megabytes a VRAM, probablemente no tendrá un cuello de botella aquí. Si lo hace, una buena pantalla de carga puede facilitar la espera.
Unir sus texturas en atlas tendrá poco efecto, ya que la cantidad total de información que envía a VRAM será la misma. De hecho, si está clasificando sus texturas y tiene que dejar espacios vacíos en sus atlas, entonces realmente enviará más datos a VRAM y, por lo tanto, esta parte será más lenta.
Rendimiento de renderizado:
Una vez que todas sus texturas estén en VRAM, la cantidad de texturas que tenga no afectará el rendimiento del renderizado. Hay cuatro elementos que afectan su rendimiento de representación:
Renderizar cambios de estado : cada vez que cambie la imagen desde la que desea renderizar, aumentará seriamente el tiempo requerido para renderizarla. En general, desea minimizar la cantidad de cambios de estado, y puede reducir la cantidad de cambios de estado al agrupar varias imágenes que dibujará consecutivamente, en un atlas de texturas.
Solo atlas no es suficiente. Debe atlas de una manera en que se reducen los cambios de estado, para obtener ganancias de rendimiento. Por ejemplo, uno puede pensar que tener su personaje principal en una hoja de sprites le dará una ganancia de rendimiento, pero si solo está dibujando un sprite de esa hoja de sprites por cuadro, no obtendrá ninguna ganancia de rendimiento en comparación con tener cada sprite en un archivo separado.
El atlas adecuado no es trivial, pero en general puede agrupar sprites de forma segura desde la misma capa. Por ejemplo, tener todos los elementos de la GUI en una hoja de sprites es una idea muy prometedora, mientras que agrupar monstruos alfabéticamente puede no serlo.
Llamadas de sorteo: en general, es posible que desee mantener sus llamadas de sorteo al mínimo. Una buena regla general es que si no hay cambios de estado de representación entre dos llamadas de extracción, puede unirlas en una sola llamada de extracción. Para obtener ganancias de rendimiento más avanzadas, puede usar, por ejemplo, 8 muestreadores de textura y llamadas de dibujo grupales por cada 8 texturas, por lo que solo tiene que cambiar las texturas cada 8 texturas.
Recuento de triángulos: de hecho, cuantos más triángulos dibujes, más tiempo tomará dibujarlos. Sin embargo, en las computadoras modernas, y para la mayoría de los juegos en 2D, estarás muy lejos de maximizar esto. Puede dibujar de forma segura cientos de miles de sprites por cuadro y aún así obtener tasas de fotogramas increíblemente buenas. Probablemente estará más vinculado a la CPU si está dibujando cantidades extremas de sprites antes de tener problemas con su GPU.
Configuración de la API: si está haciendo todo bien y sigue obteniendo velocidades de fotogramas extrañamente bajas, verifique la configuración con la que está dibujando sus sprites. No conozco SFML, pero, por ejemplo, en Direct3D 9, la creación de un búfer de vértices con
D3DUSAGE_DYNAMIC
, o enD3DPOOL_MANAGED
puede aumentar fácilmente sus tiempos de representación por diez. Por supuesto, el uso de vSync limitará su velocidad de cuadros a la frecuencia de actualización de su monitor. Además, el uso de FVF no alineados puede disminuir el rendimiento en algunas GPU. Esto también es para Direct3D 9.En su caso, consulte la documentación de la API que está utilizando.
Si solo tiene una cantidad de texturas baja a moderada (menos de 1GB), y está dibujando cantidades bajas de sprites (menos de un millón por cuadro), entonces lo primero que miraría sería cambiar la configuración de la API, y luego reduciendo la cantidad de estados de renderizado y llamadas atraídas.
fuente