domingo, 7 de septiembre de 2014

Render in progress

Qué encontrarás en esta entrada?
  • Monitorización renderizaciones en Blender en Linux.

En Astaroth's World no es la primera vez que intentamos monitorizar Blender. El proceso de renderizado (creación de una imagen digital a partir de un diseño previo), es un proceso en la mayor parte de las ocasiones costoso tanto a nivel de recursos del sistema como en tiempo. No es raro que un proyecto de animación amateur tarde días o semanas en renderizar, y este tiempo siempre puede dispararse hasta el infinito según las calidades que queramos o la duración de nuestra secuencia. Por ello, es especialmente interesante poder monitorizar el proceso, incluso a distancia, mientras que invertimos ese tiempo en otras actividades.

La solución propuesta hace meses en este blog involucraba un costoso análisis del vídeo generado. Como el vídeo en formación estaba incompleto, primero lo reconstruía corrigiendo el índice, y luego contaba los fotogramas y el tiempo (relacionados por los "fotogramas por segundo"). Finalmente, lo enviaba por correo usando mutt. De esta manera podíamos programar un informe periódico para recibirlo en el correo electrónico (en aquella versión incluso se incluía el último fotograma renderizado extraído del vídeo en formación).

La solución propuesta ahora es más eficiente, puesto que aprovecha los propios recursos de Blender y no implica un procesamiento de vídeo mientras que se está generando (muy costoso para el sistema).

La clave está en que Blender permite un acceso por línea de comandos (más información aquí), de tal manera que se puede renderizar en una consola de Linux sin necesidad de abrir el entorno gráfico de la aplicación. A priori, esto parece ser más eficiente para el sistema. A cambio, perdemos la capacidad de ver el fotograma que se está generando, lo cual a veces puede resultar útil para detectar errores durante el renderizado.

La sintaxtis básica podría ser la siguiente:

./blender -b archivo.blend -s 001 -e 100 -a -x 1

De esta manera se renderizaría el proyecto guardado en "archivo.blend" desde el primer fotograma hasta el número 100. En pantalla podremos ver algo parecido a lo siguiente:

Fra:1 Mem:23.51M (0.00M, Peak 29.46M) | Preparing Scene data
Fra:1 Mem:23.51M (0.00M, Peak 29.46M) | Preparing Scene data
Fra:1 Mem:23.51M (0.00M, Peak 29.46M) | Creating Shadowbuffers
Fra:1 Mem:23.51M (0.00M, Peak 29.46M) | Raytree.. preparing
Fra:1 Mem:34.57M (0.00M, Peak 34.57M) | Raytree.. building
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) | Raytree finished
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) | Creating Environment maps
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) | Caching Point Densities
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) Sce: Scene Ve:180482 Fa:80512 La:1
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) | Loading voxel datasets
Fra:1 Mem:33.92M (0.00M, Peak 51.19M) Sce: Scene Ve:180482 Fa:80512 La:1
Fra:1 Mem:33.93M (0.00M, Peak 51.19M) Sce: Scene Ve:180482 Fa:80512 La:1
Fra:1 Mem:33.93M (0.00M, Peak 51.19M) | Volume preprocessing
Fra:1 Mem:33.93M (0.00M, Peak 51.19M) Sce: Scene Ve:180482 Fa:80512 La:1
Fra:1 Mem:33.93M (0.00M, Peak 51.19M) Sce: Scene Ve:180482 Fa:80512 La:1
Fra:1 Mem:48.35M (0.00M, Peak 51.19M) | Scene, Part 8-135

Como vemos, en este "log" se da información a tiempo real sobre el proceso. Lo interesante es que no es difícil redirigir esta salida en pantalla a un archivo de texto, basta con hacer:

./blender -b archivo.blend -s 001 -e 100 -a -x 1 > log.txt

Con ello conseguimos obtener un archivo "log.txt" en el que venga información a tiempo real sobre el renderizado. Bastaría con leerlo para saber en qué punto se encontraría nuestra animación.

El flujo de trabajo constaría entonces de dos partes: renderizado por consola y lectura de los datos generados. Para la primera parte podríamos utilizar un script parecido al siguiente:

#!/bin/bash
tmps=`date +%s`
echo "$tmps;$2;$3" > log.txt
dir=`pwd`
cd /url_donde_este_blender/
ini=`printf "%03d" $2`
fin=`printf "%03d" $3`
./blender -b $dir/$1 -s $ini -e $fin -a -x 1 >> log.txt
Si a este archivo le llamásemos "render.sh", habría que ejecutarlo en la misma carpeta donde estuviera el ".blend" de la siguiente manera:

./render.sh archivo.blend 1 100

En dicho caso, cogería el archivo "archivo.blend" y renderizaría la animación desde el fotograma 1 al 100. Primero tomaría el tiempo inicial (para poder dar estimaciones de cuánto va a tardar). Luego, escribiría esa información, junto con la de los fotogramas iniciales y finales en el log (para poderlos usar más tarde en nuestros cálculos posteriores). Tras dar el formato adecuado a los números de fotogramas renderizaría la animación mandando el log a un archivo de texto.

Ya se está generando la animación, y nuestro log tiene la siguiente pinta:

1410073356;1;100
Read new prefs: /********/userpref.blend
found bundled python: /********/python
read blend: /********/untitled.blend
Fra:1 Mem:23.51M (0.00M, Peak 29.46M) | Preparing Scene data

En la primera fila, separados por ";", tenemos los datos sobre tiempo y fotogramas que hemos introducido nosotros a través del primer script. La última fila con el texto "Fra:[número]" nos da el último fotograma con el que se está trabajando. Con todo ello, podemos iniciar la segunda fase: lectura de los datos generados.

   Un script como el siguiente leería los datos del log y nos calcularía lo que deseamos:

# Tiempo de inicio de la animación:
tinibl=`cat log.txt | sed -n '1p' | awk -F\; '{print $1}'`

# Primer fotograma:
fotblendin=`cat log.txt | sed -n '1p' | awk -F\; '{print $2}'`

# Último fotograma:
fotblendfn=`cat log.txt | sed -n '1p' | awk -F\; '{print $3}'`

# Archivo blender renderizado:
archblen=`cat log.txt | sed -n '4p' | grep -o "/.*blend"`

# Último fotograma renderizado:
framblen=`cat log.txt | grep -o "Fra:[0-9]*" | sed -n '$p' | grep -o "[0-9]*"`

# Hora actual:
tfinbl=`date +%s`

# Tiempo de renderizado hasta el momento:
tbl=`echo "scale=2; ( $tfinbl - $tinibl ) / 60" | bc`

# Fotogramas por renderizar (el último de la animación menos el último renderizado):
fotporren=`echo "$fotblendfn - $framblen" | bc`

# Fotogramas renderizados (el último renderiado menos el primero de la animación):
fotyarend=`echo "$framblen - $fotblendin" | bc`

# Porcentaje renderizado:
porcblen=`echo "( $fotyarend * 100 ) / ($fotblendfn - $fotblendin)" | bc`

# Estimación de lo que queda por renderizar:
tiempestbl=`echo "scale=2; $fotporren * $tbl / $fotyarend" | bc`

# Redondeo del tiempo:
tiemptrunc=`echo "$tiempestbl / 1" | bc`            # truncado.
tdiscb=`echo "($tiempestbl * 10 - $tiemptrunc * 10) / 1 " | bc`    # Regla redondeo.
if [ $tdiscb -lt 5 ] ; then
    inctimbl=$tiemptrunc
else
    inctimbl=`echo "$tiemptrunc + 1" | bc`
fi

# Fecha fin:
ffinble=`date +%d/%m/%Y\ \(%H:%M\) -d "+$inctimbl min"`

Y con los datos ya leídos, simplemente tenemos que redirigirlos hacia donde queramos. Por ejemplo, podríamos mandarnos un correo electrónico con ellos a través de mutt. Mi opción ha sido aprovechar el sistema que me estoy creando basado en centerIM y Hangouts para poderme comunicar con mi ordenador a través de mi móvil (ver más acerca de esto). De esta manera, puedo preguntar por el móvil cómo va la renderización y recibiría algo como lo siguiente.


En fin, una herramienta más para sobrellevar el tedioso tiempo de espera durante el renderizado.

No hay comentarios:

Publicar un comentario

Querido astarothista!,

Si te ha gustado la entrada y quieres dejar constancia de ello, tienes alguna sugerencia para completarla o corregirla, quieres mostrar tu opinión respecto a algo de lo que se haya hablado en esta entrada (con respeto) o simplemente quieres dejarme un mensaje a mi o a la comunidad, no dudes en comentar ;)!

Recuerda que también estamos en Facebook y en Google+.