miércoles, 18 de abril de 2018

Amiga JuggleR. OpenGL con R

En julio de 1985 Commodore lanzó al mercado el Amiga, un ordenador adelantado a su tiempo que ridiculizaba en capacidades multimedia a todo lo aparecido hasta la fecha.

Fuente: MacPaint de Apple para Macintosh

Fuente: DigiPaint de NewTek para Amiga


Junto al primer SO multitarea, el Amiga poseía coprocesadores de gráficos y sonido que lo dotaban de altas prestaciones multimedia, liberando de carga al procesador Motorola 68000. Pero una deficiente gestión de memoria, su falta de estabilidad, y en último término una pérdida competitiva en el terreno gráfico impidieron que el Amiga perdurase.

"The light that burns twice as bright burns half as long.
And you have burned so very, very brightly, Roy."
(Eldon Tyrrell en 'Blade Runner')

Si te apetece probar el entorno gráfico (Workbench) del Amiga, aquí hay un emulador con las carpetas más típicas del SO y varias demos. No pierdas la perspectiva de estar usando un ordenador con varias décadas a sus espaldas!.


~~~

En la época se hizo popular el 'Amiga Juggler', una cortísima (1s) animación 3D de un malabarista hecha a base de esferas, que Eric Graham creó con su propio código de ray tracing y Commodore usó como reclamo publicitario. El Amiga fue el primer ordenador en hacer asequible la creación de renders y animaciones hiperrealistas en 3D.

Fuente: 'Amiga Juggler', Eric Graham, noviembre 1986

Fuente: revista 'Amiga World', mayo/junio 1987


He querido hacerle mi propio homenaje programando la animación desde cero en R, y solamente renunciando por su complejidad al trazado de rayos. Como sustitutivo de un verdadero algoritmo de eliminación de superficies ocultas pensaba dibujar las esferas de mayor a menor distancia al observador, como hacían los programadores de vector balls de la demoscene.

Fuente: 'Mega Demo', Red Sector Inc.


Sin embargo buscando información para dibujar esferas de forma ágil, di con el paquete rgl (visualización 3D basada en OpenGL) y se impuso la cordura: rgl nos resuelve la proyección 3D y aporta un cálculo preciso de intersecciones entre objetos.

No obstante usar rgl no ha sido un camino de rosas al no estar pensado para animar escenarios 3D sino para representar conjuntos de datos. Lograr con comandos el ángulo de observación preciso es complicado, pues lo habitual en rgl es elegirlo interactivamente de forma visual.

Pero lo más grave es que rgl ajusta dinámicamente el campo de visión para abarcar siempre todos los datos representados. Por este motivo renunciaremos al suelo infinito original, y colocaremos objetos invisibles que delimiten la escena para que animar el 'Juggler' no provoque cambios en el punto de vista de un frame a otro.

Comentario al respecto de Duncan Murdoch, coautor de rgl: "I think you have the only workable solution. rgl always tries to make the whole scene visible, which means it works out a bounding box, and transforms things so the center is in the center and the scale allows the whole thing to be seen. After that you can use userMatrix to modify the viewpoint, but I don't think it would be practical to undo the automatic transform at that point".

~~~

Empezamos mejorando las esferas estándar de la función spheres3d(), codificándolas como superficie paramétrica sobre persp3d() y aplicando un facetado más denso. Pese a ello el cálculo es rápido, siendo el uso de transparencias lo que más ralentiza los render.


~~~

En cuanto a la cinemática, consideramos que la cadera del 'Juggler' solo se desplaza en vertical. El tronco, la cabeza y los hombros suman a esta traslación una oscilación lateral manteniendo la rigidez de forma similar a una biela, dando lugar a trayectorias elipsoidales. Las ecuaciones que definen este movimiento se desarrollan aquí.



Partiendo de los hombros modelamos brazo y antebrazo mediante oscilaciones contenidas en planos verticales. El brazo se separa levemente del tronco rotando sobre el hombro, y el antebrazo oscila arriba y abajo rotando sobre el codo. Evitaremos un aparente pequeño fallo de la animación original: los brazos del personaje parecen estirarse cambiando de longitud.

Las piernas se anclan en puntos fijos a la cadera flexionándose por la rodilla para absorber la oscilación vertical, pero siempre respetando las longitudes de muslo y pierna. El pie derecho está más adelantado que el izquierdo lo que hace las piernas asimétricas, aunque el movimiento de ambas se modela igual. La geometría está formulada aquí.



Los malabares siguen tiros parabólicos sincronizados con el conjunto. Dos de las bolas llegan a la altura mínima y la tercera aparece centrada a máxima altura a la vez que la figura alcanza el punto más bajo en posición erguida, coincidiendo con brazos y antebrazos en el centro de sus respectivos movimientos (alejándose del tronco los primeros y ascendiendo los segundos). Esa posición se corresponde con el primer frame de la animación y la elegiremos como geometría definitoria de la escena.



Aunque la parábola superior alcanza mayor altura, también se tarda el doble de tiempo en recorrerla. Esto posibilita aplicar la misma gravedad en los dos tramos parabólicos, condicionando la relación de alturas máximas tal y como hace un malabarista real. Sin embargo por fidelidad al original he preferido elegir alturas a conveniencia, calculando una aceleración gravitatoria ligeramente diferente para cada recorrido.

Para hacer estas simulaciones 2D se ha empleado la librería gráfica que construimos en 'Dibujando gráficos de mapa de bits con R'.

~~~

Aún sin la sofisticación del trazado de rayos, calcularemos las sombras de forma exacta como proyección de cada esfera sobre el plano XY según la dirección de una fuente de iluminación. La sombra del conjunto será el sumatorio de las sombras de todas las esferas que lo integran.

Una esfera se proyecta sobre un plano como una elipse cuyo eje menor coincide con el diámetro de dicha esfera, mientras el eje mayor se elonga en función del ángulo de incidencia sobre el plano. Una vista cenital en perspectiva axonométrica nos da las dimensiones reales de una esfera y su sombra.



Cuando pasamos a una perspectiva cónica la sombra se deforma dejando de presentarse como una elipse perfecta, pero de esta parte ya se encarga rgl.



Las expresiones que calculan el centro de la proyección de cada esfera así como la elongación elíptica comentada se deducen aquí. De los dos modelos de iluminación expuestos escogemos el de fuente de luz en el infinito por ser el que cumple la condición de rayos paralelos.

~~~

El universo se carga en un dataframe desde un fichero de configuración fácilmente editable. Cada fila define una esfera en base a 8 columnas:
  • x, y, z: posición (centro de la esfera).
  • radius: radio (misma escala que posición).
  • colour: color (numérico o alfanumérico).
  • alpha: transparencia (valor entre 0 y 1).
  • ninterp: esferas a interpolar entre la actual y la siguiente (ninterp=0 en esferas aisladas).
  • desc (opcional): descripción alfanumérica del objeto.

En amigajuggler.csv se especifican solo 22 de las 83 esferas totales que conforman la animación. El parámetro de interpolación nos ahorra tener que describir las esferas intermedias del tronco y las extremidades.



A continuación se muestran las vistas en planta, alzado y perfil de los elementos definidos, añadiendo un suelo finito de cuadros y el cálculo de sombras.


~~~

En lo que respecta al sonido, en este artículo encontramos un muestreo a 22kHz y 8 bits del 'PING!' que hacen las bolas al ser lanzadas. Consiste en un tono de 1kHz y 0,5s de duración con una tosca envolvente ADSR escalonada.



Lo regeneramos a 44kHz y 16 bits con una envolvente progresiva pero fiel a la de partida.



El sonido original seguido de la "restauración" (diezmada a 22kHz) puede escucharse aquí:


~~~

El resultado final en vídeo de alta resolución con sonido puede verse en amigajuggler.mp4:



Añadimos una vista frontal para cerciorarnos de que los malabares no llegan a cruzarse, y movemos la fuente luminosa para sacar más partido al cálculo de sombras alargándolas. En vídeo en amigajugglerfrontal.mp4:



En el posterior artículo 'Anaglifos 3D con R' puede verse una versión estereoscópica de la animación.

Finalmente hacemos una restauración digital de la versión original de la animación. Donde obtuvimos el sonido encontramos también los 24 frames de 320x200 píxeles y hasta 4.096 colores que la componen (el número 13 tiene un artefacto en forma de línea de color que eliminamos). Usamos el sonido anteriormente restaurado y aumentamos el tamaño sin interpolar a 960x600. El resultado está en amigajuggleroriginalrestauracion.mp4. El achatamiento se debe al aspect ratio nativo de los píxeles del Amiga, que no eran del todo cuadrados.

En AmigaJuggleR.pptx puede encontrarse la presentación sobre el ejercicio que utilicé en el meetup del Grupo de Usuarios de R de Madrid el 9 octubre 2018.

En 'Project Amiga Juggler' puedes ver un pedazo de proyecto de Mike Birken recreando también el Amiga Juggler, esta vez sí con ray tracing, todo implementado desde cero. Si el enlace no funciona puede bajarse en PDF desde ProjectAmigaJugglerMeatfighter.pdf.

~~~

Repositorio con el código R y archivos auxiliares: GitHub.

No hay comentarios:

Publicar un comentario

Por claridad del blog, por favor trata de utilizar una sintaxis lo más correcta posible y no abusar del uso de emoticonos, mayúsculas y similares.