Saltar al contenido principal

Rendimiento en PS1: gráficos, animación y sonido

· 6 min de lectura
Desarrollador de Unity y creador de Polygon Engine

Conforme fui integrando gráficos, scripts, colisiones, animación y audio en Polygon Engine, tuve que revisar el trabajo que realizan en conjunto. Contar los polígonos de una escena ayuda a entender parte de ese trabajo, pero deja fuera muchas operaciones necesarias para que el juego funcione.

Incluso una habitación pequeña puede tener scripts que se ejecutan constantemente, objetos animados, luces y varios sonidos activos. Además, algunas superficies pueden dibujarse unas sobre otras y ocupar gran parte de la pantalla. Para decidir qué conviene optimizar, necesitaba distinguir el costo de cada sistema y la forma en que se combinan.

Tiempo por cuadro y uso de memoria​

Una de las primeras distinciones es entre ocupar memoria y consumir tiempo de procesamiento. Una escena puede respetar todos los límites de memoria y aun así tardar demasiado en actualizarse o dibujarse. La validación de capacidad permite revisar los datos almacenados; para conocer el rendimiento también hay que medir el trabajo de la CPU y la GPU.

A una frecuencia nominal de video de 60 Hz, el intervalo entre actualizaciones de pantalla es de aproximadamente 16.7 milisegundos; a 50 Hz, es de 20 milisegundos. El juego puede renderizar a una frecuencia menor. Por eso, al revisar una medición, distingo entre la frecuencia de video, el paso de simulación y los cuadros que el juego alcanza a completar.

También necesito saber si el tiempo medido corresponde a procesamiento o a una espera. Si mido una sección de código que incluye la sincronización gráfica, parte del resultado puede ser tiempo en que la CPU espera a la GPU. Atribuirlo todo a la lógica del juego me llevaría a optimizar el sistema equivocado. Para interpretar el dato, necesito conocer dónde comienza y termina la medición.

Sobredibujado y visibilidad​

Dos escenas con la misma cantidad de triángulos pueden exigir un trabajo muy distinto a la GPU. Unos objetos pequeños a lo lejos cubren pocos píxeles. En cambio, varias superficies grandes superpuestas obligan a dibujar repetidamente la misma zona de la pantalla, aunque el número de triángulos sea igual.

Dibujar repetidamente píxeles que después quedarán cubiertos produce sobredibujado. La transparencia y ciertas distribuciones de superficies pueden dificultar evitarlo. Reducir los triángulos enviados solo ayuda si esos triángulos representaban una parte significativa del cuello de botella.

Las herramientas de visibilidad ayudan a reducir ese trabajo. Rooms y Portals permiten limitar qué partes del nivel se envían a dibujar según el espacio desde el que se observa. Para que funcionen bien, las conexiones entre habitaciones deben estar configuradas correctamente. Su función es controlar la visibilidad; no cargan ni descargan automáticamente el mundo por streaming.

Al ajustar un portal, necesito comprobar que siga mostrando todo lo que el jugador puede ver. Si restringe demasiado la visibilidad, aparecerán huecos o desaparecerán objetos; si permite demasiado, la reducción de trabajo será pequeña. Las herramientas de inspección son útiles para encontrar ese equilibrio sin introducir errores en la imagen.

El costo de la iluminación​

Con la iluminación también tuve que relacionar los controles del editor con los cálculos disponibles en PS1. El trabajo se apoya en iluminación por vértice y colores preparados, con resultados y costos distintos a los de los shaders por píxel y mapas de sombras habituales en engines modernos.

El GTE ofrece operaciones útiles para iluminación, pero el engine todavía decide qué superficies se ven afectadas, prepara los datos de entrada y maneja sus tipos de luz compatibles. Más luces y más vértices afectados pueden significar más trabajo antes de empezar a dibujar.

En un pasillo con lámparas fijas, por ejemplo, algunos colores pueden prepararse de antemano para sugerir la iluminación. Una luz que cambia o se mueve durante la partida sí necesita actualizarse. Separar esos casos permite reservar los cálculos durante la ejecución para los cambios que realmente se verán en el juego.

Datos de animación y deformación​

Un clip de animación necesita poses almacenadas u otros datos, y el entorno de ejecución necesita evaluar la pose actual. Después, deformar la malla agrega trabajo que un objeto estático no requiere.

El sistema de animación esquelética de Polygon Engine usa hard skinning: una influencia de hueso por vértice. Esto limita el trabajo de deformación, pero también influye en cómo se prepara el modelo. Funciona bien para articulaciones rígidas; una zona que necesita deformarse suavemente, como un hombro, requiere más cuidado porque no dispone de pesos mezclados entre varios huesos.

Al revisar una animación, necesito considerar la cantidad de huesos, la duración del clip, la frecuencia de muestreo y los vértices animados visibles. Reducir los triángulos de la malla puede ayudar al renderizado, pero no reduce por sí solo los datos del clip. La guía de animación esquelética explica el proceso de importación y sus restricciones.

Memoria de sonido y voces de reproducción​

La SPU dispone de 24 voces ADPCM y 512 KiB de memoria de sonido. Las voces permiten reproducir muestras de audio, mientras que la memoria limita cuántas pueden mantenerse cargadas y cuánto espacio queda para la reverberación. La referencia de la SPU explica cómo se utilizan ambos recursos.

Una misma muestra corta puede reproducirse simultáneamente en varias voces. También puede haber muchas muestras cargadas aunque solo suenen unas cuantas. Por eso necesito revisar tanto la memoria ocupada como la cantidad de reproducciones simultáneas; contar archivos de audio no alcanza para evaluar esos límites.

La función de cada sonido también influye en su preparación. El efecto de una puerta necesita responder rápidamente, mientras que una pista larga de fondo requiere planear su almacenamiento y reproducción continua. Desde los scripts, conviene activar cada efecto cuando sucede el evento: pedirlo en cada cuadro puede ocupar varias voces y repetir el sonido de forma accidental.

Comparar mediciones de rendimiento​

Para comparar resultados, procuro mantener la misma cámara, la misma interacción y los mismos ajustes de ejecución. Después puedo variar un aspecto concreto: reducir las luces que afectan a una superficie, limitar el área visible, espaciar una operación de scripting o simplificar una animación. Así puedo relacionar el cambio con la medición.

Estas comparaciones también dependen de dónde se ejecuta el juego. El editor permite revisar la escena durante el trabajo, el emulador permite probar la compilación de PS1 y la consola permite medir su comportamiento en hardware real. El rendimiento de la computadora y los reportes de capacidad aportan información útil, pero necesito mediciones en el destino para evaluar cómo corre ahí.

Por eso me interesa que las herramientas del engine muestren tanto el uso de recursos como los tiempos de ejecución. Al relacionar ambos datos, puedo decidir si conviene cambiar un recurso, ajustar una escena o revisar un sistema. Integrar todos estos módulos me ha ayudado a mirar el rendimiento de esa forma, con cambios concretos cuyo efecto pueda comprobar.