martes, 6 de septiembre de 2016

Regreso al pasado: Píxeles, colores y efectos especiales


No tengo intención de escribir de forma frecuente, pero cuando se inició Citrogamers me estrené con una entrada explicando cómo funciona la famosa Inteligencia Artificial y por qué no te puede atacar una tostadora aunque le instales Windows. El caso es que hice pocos artículos así y me quedé con las ganas de explicar algunas técnicas de videojuegos antiguos. Por eso os voy a explicar cómo funcionaban los píxeles, las paletas y el Color Cycling como perfecto ejemplo de aquello.


 Introducción

Antes que nada, os diré que siempre admiré a los programadores de los 80. Sí, seguramente en los 70 usaban otras técnicas e incluso yo tuve que inventarme alguna cosilla cuando estudiaba, aunque seguro que ya estaba inventado y simplemente no lo conocía entonces.

El caso es que en aquella época las limitaciones de hardware eran enormes.Cuando tienes sólo 48KB de memoria, no puedes desperdiciar recursos en guardar cada imagen de una animación. Recordemos que por entonces no existían formatos como el GIF, que se hizo en 1987. Tampoco podían gestionar paletas de colores amplias porque implicaban gastar más memoria. De hecho, de ahí viene la limitación de colores de los GIFs, ya que en la época no se mostraban gráficos mejores.

Optimización de memoria


Para que lo entendáis, para una imagen de 100x100 píxeles, si fuisteis al colegio no os costará adivinarlo, hacen falta 10.000 píxeles. Vamos a redondearlo en 10Kpx. Si usas dos colores, blanco y negro para aclararnos, necesitarías 10Kbits. Sí, bits. Usarías un bit para cada uno de los píxeles, por lo que 8 píxeles ocuparían un byte. Es poco, ¿verdad? Pero si quieres hacerlo en CGA con sus 4 colores, necesitas dos bits por cada punto, por lo que se DUPLICA la memoria necesaria. Al hacerlo en EGA y sus 16 colores se CUADRUPLICA. Con los 256 colores en VGA se OCTUPLICA. Sí, existe ese verbo. Eso convierte la imagen de 10Kpx en 8KB para mostrarlo en VGA, 4KB para mostrarlo en EGA, 2KB para mostrarlo en CGA y 1KB en blanco y negro.

Cuando tienes 48KB como en un Spectrum y una resolución de 256×192 con hasta 15 colores porque el negro se repetía, estás consumiendo 24KB sólo en mostrar una imagen. Obviamente había trucos para mejorar eso, ya que hacía inviable hacer nada así. Se crearon píxeles de distintos tamaños. ¿Creías que un píxel era un punto nada más? Pues no, o sí, según lo veas. Para la máquina el píxel sigue siendo de 1x1, pero para el programa podría ser de 8x1, viéndose unos píxeles estirados, pero reduciendo drásticamente el uso de memoria y permitiendo hacer juegos más complejos. Esto significaría que el Spectrum pintaría 256x192px, pero el programa realmente usaría 32x192px. Tal vez os suene lo que tan de moda está ahora de la resolución nativa y la resolución escalada. No es un invento nuevo y es lo que se hacía en los sistemas antiguos. De hecho, por eso los píxeles eran tan alargados y gruesos en la Atari 2600.

Este era uno de los juegos con mejores gráficos en Atari 2600.


La razón de este tipo de píxeles es que cuando dibujas a un personaje 2D, la cara la puedes hacer de un único color, por lo que podrías usar dos píxeles de esos apilados y otros dos para el tronco y otro para los zapatos. Con eso tu personaje se dibujaría con 5 píxeles, pero quedaría el personaje típicamente achatado como le pasaba a Mario en sus primeras entregas de NES.

Retorciendo el truco

A los píxeles alargados no se les escalaba, sino que cuando llegaba el momento de pintarlos en pantalla, era el mismo programa el que pintaba punto por punto en la salida de vídeo. Por aquél entonces no había tarjetas gráficas como las de ahora. El programa reservaba una parte de la memoria para pintar, escribía ahí y cada cierto tiempo se mandaba al monitor/televisor.

Siendo así, que cuando tenías que pintar un píxel, en lugar de pintarlo en la posición (15,30), lo pintaba de seguido en las posiciones (15,30-38). Eso era el modo 8x1 que expliqué antes. Spectrum tenía más modos, pero dependía del sistema y lo que te permitiera retorcer las reglas.

Estos son los gráficos que se conseguían con 48KB de memoria y un Z80.


El truco en este caso es que cuando pintabas los píxeles del personaje, por ejemplo, en lugar de pintar del mismo color las coordenadas (15,30-38), al pintar en el (15,34) podías saltarte el pintar, de modo que quedasen los pies separados con lo que hubiese pintado antes. Así se conseguía añadir detalles al personaje. Podrías hacer que en lugar de saltarse ese punto, lo pintase de otro color y sería la hebilla del cinturón, por ejemplo.

Claro, eso no se podía hacer con toda la pantalla, porque entonces estarías pintando con píxeles de 1x1 y volviendo al exagerado consumo de memoria RAM con las limitaciones que implicaba. Era por tanto algo para los detalles fácilmente identificable como el personaje o tal vez algún enemigo.

Lo de los píxeles se podía retorcer mucho más, creando códigos semánticos propios para que cuando un píxel fuese de "color 1", tu juego pintase una línea de 8 píxeles con un patrón definido. Es decir, que no fuese el color 1, sino "3 píxeles azules, 1 rojo, 2 amarillos y 2 morados". Si tu código semántico era demasiado grande, volvía a crecer la memoria, pero a veces podía ser útil usar eso en lugar de los colores fijos por temas varios, pero aumentaba la complejidad del diseño del juego también. Básicamente, alterando los colores y los píxeles, estaban hackeando el sistema en el sentido puro y original de la palabra. Un ejemplo que da para una entrada entera lo tenemos en el uso de los gráficos CGA y del que hablaré en otra ocasión.

Si alguien busca juegos de Spectrum ahora, verá que los píxeles parecen cuadrados. Aparte de esos trucos de antes, se aprovechaban trucos de rasterización que no tienen que ver con esta entrada, pero para que os hagáis una idea, aprovechaban cómo pintaba un televisor, de modo que entre línea y línea podían realizar unas pocas operaciones para cambiar la paleta. De este modo conseguían que apareciesen más colores en pantalla de los que podía mostrar el sistema. Seguías con la limitación por línea, pero ya te permitía hacer cosas más vistosas y detalladas. Por ejemplo se usaba para los típicos carteles con dos o más colores en líneas horizontales cuando el resto de los colores ya estaban siendo usados en la línea.


Color cycling

Esto nos lleva a una de las formas más curiosas de aprovechar las paletas de colores. Como decía al principio, animar a un personaje y guardar varias imágenes suyas suponía un coste de memoria enorme. Significaba almacenar cada uno de los fotogramas de la animación en la memoria RAM y ya hemos visto lo costoso que era una imagen para la época. ¿Qué se hacía entonces? Pues cuando se podía, se alteraba la paleta de colores aprovechando el efecto phi.

Para el que no lo sepa, alguna vez habréis visto uno de esos carteles de neón "animados". También las señales de curva peligrosa con LEDs. Esto es básicamente un cartel con varias luces. Se enciende una y las demás se apagan. Se hace lo mismo con la que hay al lado. Se vuelve a hacer y así hasta terminar con todas las luces. El resultado es que parece que la luz se ha movido.

Esto es el efecto Phi que también se usar en los throbber, las imágenes de carga.


Si hacemos lo mismo cambiando los colores, puedes tener una llama básica con los colores naranja y rojo, que al intercambiarlos, da la sensación de estar moviéndose. Si tuviese tres colores podrías hacer que pareciese que el color se desplaza del centro hacia afuera simulando un mejor fuego. Si además, ya con gráficos mejores, alteras los colores que lo rodean, simulas el titileo de la llama y su iluminación como en la imagen inicial.

Esto que nació como una técnica para ahorrar memoria, se podía usar para crear efectos mejores también. Podías hacer que la noche se volviera día cambiando la paleta de forma dinámica. Hacías que lo que se pintase con el color 5 de la paleta en lugar de pintarse con azul claro, se pintase con un azul más oscuro. Se pintaba toda la escena de nuevo. Cambiabas el color 5 de la paleta por otro azul aún más oscuro y volvías a pintar el cielo. ¡Parecía que oscurecía! Para que el efecto fuese bueno tenías que cambiar casi toda la paleta de modo que se oscureciesen los árboles, el protagonista, etc.

El efecto del agua es un ejemplo Color Cycling.

Podías hacer "lluvia transparente" cuando no llueve. ¿Para qué quieres la lluvia invisible? Porque igual que haces el cambio de color del cielo, puedes hacer que esa lluvia transparente tenga 3 colores, por ejemplo. Dejando dos transparentes y otro del color blanco/celeste de la lluvia en los juegos. En la siguiente animación ese se vuelve transparente y coloreas al siguiente bloque de colores que era la gota un poco más abajo y finalmente repetías el proceso. Al terminar de animar y volver a pintar la primera gota, en realidad estás pintando una gota nueva en la animación. Bastante simple, ¿verdad? Pues así se podían crear efectos bastante vistosos en la era de los 16bits.

Conclusión

Esto que hoy en día llamamos técnica, en su momento eran trucos. Exprimir algo más allá de lo que da. Era el equivalente de meterle óxido nitroso a un coche. Aquél que creaba un truco nuevo, sorprendía con un juego con gráficos increíbles y entonces el resto se ponía a examinar el juego a conciencia para sacar el truco. Así nacían variantes, mejoras y juegos a cual más sorprendente. Especialmente cuando las limitaciones no fueron tantas y dieron rienda suelta a la creatividad.

Hoy en día no es necesario usar este tipo de trucos. Se usan otros, pero sólo se optimiza el núcleo del motor gráfico. Determinados efectos como la oclusión ambiental son muy costosos. En cambio, la forma de poder ofrecer mejor iluminación, es renderizar a menor resolución. De ahí que la generación de consolas no sea capaz de dar el salto a los 1080p reales y tenga que usar trucos como la resolución nativa a 720p o 900p, la resolución dinámica y demás. En este caso es por rendimiento y no tanto por limitación de memoria, pues hay que trazar menos rayos al pintar la pantalla, que es la forma de saber el color de un píxel en juegos 3D. Lo importante es que ya sabéis de dónde viene la resolución nativa distinta a la de la salida y qué implica.

La misma imagen anterior con lluvia en Color Cycling.

Esto ya permite explicar en una futura entrada por qué CGA me resulta tan interesante, los efectos de rasterización (raster effects) que permitían cosas como el modo 7 de SNES y el paralelaje (parallax) que permitía crear desplazamientos por capas dando una sensación de profundidad o permitiendo juegos como Outrun con doble paralelaje.

Aquí tenéis más ejemplos de color cycling, que es la mejor fuente que encontré y no quiero fusilárselos todos:
Imágenes animadas en color cycling de Gamedev

8 comentarios:

  1. Es la diferencia de como se programaba antes y como se hace ahora, antes exprimían el hardware haciendo encaje de bolillos, y aún así sacaban juegos que ya quisieran muchos indies perroflautis de hoy en día... y que decir de la primera playstation donde usaban el ensamblador como si fueran putos matemáticos....igualito que ahora, todos tirando de motores, librerías y venga a llorar porque quieren memoria, memoria, memoria... me temo que han malacostumbrado a los programadores, que el termino optimización les suena a arameo gangoso

    y lo se de buena tinta, me acuerdo cuando aprendí a programar en pascal, cuanto más limitadas son las herramientas, más ingenio se le pone al asunto, mientras que ahora todo se hace con un puto corta y pega, o me van a decir ahora que ese battlefield 1 no es sino un battlefront disfrazao...

    ResponderEliminar
    Respuestas
    1. También depende mucho de que lenguaje de programación se utilice pero sí. Cuanto de mayor nivel es el lenguaje que se utiliza, más se desaprovechan los recursos.
      Aun así, por ejemplo tengo que reconocer el buen hacer de Naughty Dog, que aunque podamos considerar que sus "press X to drake" no sean juegos en realidad (a gusto de cada uno) lo que hacen gráficamente es pa darle una de bofetadas a los otros títulos que tela, porque gráfica y artísticamente es que te deja con la boca abierta (sobre todo porque corre en una ps4). Para mi esta gente si que sabe utilizar y exprimir los recursos al máximo (ale, ya lo he soltao, ya me puedo ir a la cama tranquilito esta noche).

      Eliminar
    2. creo que pocos rebatirán que naughty dog es una de las compañías que mejor gestionan los recursos hoy en día, sobre todo con lo que hicieron con ps3 y uncharted 2, independientemente que te gusten sus juegos o no (yo me pase ese y ya tuve suficiente)

      Eliminar
    3. La diferencia entre un lenguaje de alto nivel y otro de bajo nivel efectivamente importa, pero los motores gráficos tienen optimizadas las rutinas más repetitivas. Todo lo que se repita mucho o requiera muchos recursos, se optimiza a nivel de código, pero la ganancia es poca. Los procesadores son tan rápidos que 3 o 4 instrucciones menos no suponen una gran diferencia.

      El cuello de botella siempre son los accesos fuera del procesador. Especialmente las operaciones de E/S como el disco duro, pero también los accesos a memoria. No por el acceso a la RAM en sí, sino por el cálculo de posiciones cada vez que se accede, por lo que la idea es poner todos los registros de un bucle contiguos en la memoria. De este modo se optimiza mucho el código máquina resultante y eso sí que otorga bastante velocidad, por lo que el lenguaje ya importa poco para la velocidad. La diferencia de usar un lenguaje u otro ahora influye en el tiempo de desarrollo, que además, es lo más costoso.

      Respecto a ND, programando sólo para una máquina cualquiera saca unos gráficos de escándalo. Mirad los Gears y los GoW. Es más, mirad iOS, que al no tener que dar soporte a 500 modelos diferentes no necesita tirar recursos en ser compatible.

      Eliminar
    4. es mas, yo creo que la industria japonesa ha pegado ese tropezón porque no han sabido adaptarse de los tiempos de la ps2 donde iban a saco con ensamblador a los tiempos de ahora que se usan motores, la mayoría extranjeros

      eso ha dado como resultado, o empresas que siguen en la era ps2 haciendo juegos para portátiles, o empresas como squarenix que se han fusionado con eidos, una empresa occidental

      sea como sea, les ha cogido con el pie cambiado, y por muy mágico que sea japón para los frikillos la verdad es que hace mucho que han dejado de ser la potencia que fueron, y aún así ponen las ventas japonesas cada semana, ah, esa nostalgia...

      Eliminar
    5. Estoy de acuerdo sobre lo de naughty dog y su capacidad para abarcar proyectos. Anuncian, terminan, empiezan otro, terminan y ya estaban trabajando en otro. Quizás los tapizan en dinero para trabajar tranquilos pero no creo que sean los únicos en la industria que se forran y aún así, con recursos y todo tienen problemas en su desarrollo.

      Eliminar
  2. todavía me acuerdo en clase de cobol (si, arcaico pero todavía se usa) cuando me pidieron hacer un programa de karaoke, y me las ingenié en hacer una jukebox dibujada en código ascii para adornar las líneas de la letra de la canción...cuando lo vio mi profesora se lo enseño a todos los profesores del instituto... Si los programadores no estuvieran esclavizados por esos putos plazos para tener los juegos cada noviembre y supieran usar las herramientas más allá de sus posibilidades usando el ingenio, los videojuegos estarían a años luz de lo que es ahora, que llevamos jugando a las mismas mierdas de hace 10 años

    ResponderEliminar
  3. Este tipo de entradas no se pueden leer a la rápida, hoy con mi café de la mañana lo leí tranquilo...notable.

    Esos gifs fácilmente pueden curar el cancer -feels good man-. Me recuerda mucho a los escenarios de los juegos de SNK (en especial KOF), hay unos por ahí que cuesta creer que sean con pixeles. Como alguien viejo en esto, siempre recuerdo el tema de conversación por ese tiempo : "de NES a SNES el cambio fue grande, mira como se ven los personajes de KOF o SFIII... piensa en como se verán los personajes con más potencia, serán ilustraciones mangas en movimiento" y llegamos al "futuro" donde los pixeles tienen menos calidad, cantidad y dedicación.

    Recuerdo que los megaman de NES tenían un limite de pixeles que podían mostrar, por eso a veces cuando uno disparaba y al mismo tiempo alguien te disparaba comenzaban a desaparecer partes del escenario :D, pero esto del color cycling está a otro nivel, es alucinante :O

    ResponderEliminar