POV-Ray como herramienta de visualización
En este post me voy a centrar en cómo usar POV-Ray, Python y ffmpeg como herramientas de visualización. Recientemente, como parte de las actividades de una jornada de puertas abiertas, decidimos añadir una visualización en un monitor que teníamos disponible que ayudara a explicar la síntesis de materiales usando reacciones autolimitadas. El resultado es el siguiente vídeo, el producto de jugar unas horas con POV-Ray, Python y ffmpeg para conseguir generar animaciones sencillas de manera automática.
Sobre POV-Ray
POV-Ray (Persistence of Vision Ray-tracer) es un programa de raytracing de software libre.
Las animaciones se construyen usando scripts, tradicionalmente con la extensión .pov.
El usuario define una cámara, iluminación y el contenido de una escena en la que se describen los objetos y sus texturas. Cada imagen generada por POV-Ray es un fotograma de la animación.
Sobre FFmpeg
La idea es usar POV-Ray para generar una secuencia de imágenes y convertirlas luego en una animación. Para esta segunda parte del proceso decidí usar el programa FFmpeg.
FFmpeg es un programa para crear y convertir vídeos. Desde la línea de comandos, es posible generar un vídeo en formato mp4 a partir de una colección de imágenes usando el siguiente comando:
Esta instrucción coge una secuencia de ficheros image%04d.png (por ejemplo image0001.png, image0002.png) y genera un vídeo usando diez fotogramas por segundo.
Integrándolo todo con Python
Una vez escogidas estas dos herramientas, lo único que falta es automatizar el proceso para generar cientos de fotogramas de manera automática. Para ello, Python es perfecto.
El objetivo es generar los ficheros .pov de manera automática a partir de una colección de objetos. Para ello decidí crear una clase PovSpace que contiene los siguientes elementos:
- Una lista de templates, prototipos de objetos que queremos representar
- Una colección de objetos, donde especificamos el tipo de objeto (la template a la que pertenecen) y su posición.
- Una paleta que permite asociar colores específicos (en el espacio RGB) con nombres sencillos, de manera que podamos definir
"verde"como(0,0.9,0). POV-Ray usa una escala de 0 a 1 en lugar de 0 a 255.
class PovSpace:
def __init__(self, palette):
self.templates = {}
self.objs = []
self.current = 1
self.palette = palette
La clase PovSpace contiene un método, generate, que crea el contenido del fichero .pov
a partir del contenido del objeto:
def generate(self):
out = header
out += self._generate_templates()
out += self._generate_boxes()
return out
Finalmente, una función run_pov coge un objeto de la clase PovSpace y se encarga
de crear el fichero, ejecutar POV-Ray y opcionalmente visualizar el resultado.
Con estos métodos, podemos generar todos los fotogramas necesarios para crear el vídeo de arriba usando un script muy sencillo:
basename = "ald{:04d}.pov"
index = 1
ps = PovSpace(palette)
ps.add_box((0,0,0), (8,2,16), "grey")
index = grow_cycle(ps, index, 2, 0.25, "red", basename)
ps = PovSpace(palette)
ps.add_box((0,0,0), (8,2,16), "grey")
ps.add_box((0,2,0), (8,0.25,16), "red")
index = add_n(ps, index, 10)
index = grow_cycle(ps, index, 2.25, 0.5, "green", basename)
ps = PovSpace(palette)
ps.add_box((0,0,0), (8,2,16), "grey")
ps.add_box((0,2,0), (8,0.25,16), "red")
ps.add_box((0,2.25,0), (8,0.5,16), "green")
index = add_n(ps, index, 10)
index = grow_cycle(ps, index, 2.75, 0.25, "blue", basename)
ps = PovSpace(palette)
ps.add_box((0,0,0), (8,2,16), "grey")
ps.add_box((0,2,0), (8,0.25,16), "red")
ps.add_box((0,2.25,0), (8,0.5,16), "green")
ps.add_box((0,2.75,0), (8,0.25,16), "blue")
index = add_n(ps, index, 10)
...