Comprendo la impaciencia del que ve en estos artículos una especie de ‘cómo se hizo’ de algo que aún no se sabe que es exactamente.
Los asiduos seguidores de mi Blog, en su mayoría profanos, en esto de la animación 3D o del trazador de Rayos Povray, estarán deseando de ver ya el producto final de esta serie de artículos, pero aún falta para eso, porque para los interesados en aventurarse a usar este trazador de rayos, hay que ir paso a paso explicando el procedimiento empleado.
En este artículo vamos a mostrar el vídeo que resulta de haber incorporado a nuestra ruta los datos relativos a la altura estimada del terreno en cada punto de la ruta.
De momento para no complicarnos, usaremos como sucedáneo del vehículo una simple bola, porque aún no hemos explicado como se consigue dar orientación a un vehículo en correspondencia con una ruta spline.
Difícilmente una bola de color uniforme se puede orientar apuntando a ninguna parte, así que no notaremos esta deficiencia.
Hemos modificado nuestro programa Python ‘rutaspline.py’ para que incluya la coordenada Y responsable de la altura.
Ini= [1123, -1.8, 327]
p1= [1053, -2.2, 687]
tramo1=[
[1194, -1.2, 843],
[1401, -1, 921],
[1602, 0.15, 960]
]
P2= [1695, -1.1, 924]
tramo2=[
[1668, -1.5, 846],
[1581, -1.5, 783],
[...]
fp=open("rutaspline.inc", "w")
y=0.0
for n in range(1, len(ruta)-1): # Los extremos no intervienen
x=fx(ruta[n][0])
y=ruta[n][1]
z=fz(ruta[n][2])
if n==len(ruta)-1:
fp.write ("%d, <%f,%f,%f>\n" % (n, x, y, z))
else:
fp.write ("%d, <%f,%f,%f>,\n" % (n, x, y, z))
fp.close()
[...]
El resultado es un nuevo fichero ‘rutaspline.inc’ que contendrá lo siguiente:
Dejaremos la construcción de la nave para el siguiente capítulo, pero ahora vamos aprovechar para probar que efecto visual tendría incluir en la nave tres faros delanteros que iluminen el camino. Para ello usaremos a la propia nave como punto de referencia a la cual el foco y la propia cámara virtual (que viaja que grabando la escena) apuntarán.
Para los focos hemos usado un tipo de luz ‘spotlight’. Recordemos que en Povray todos los giros se aplican tomando el origen de coordenadas. Por ello los giros de un objeto que se hagan sobre sí mismos (ya sea nave, luz spotight, cámara, etc.) y que no se encuentren previamente en <0,0,0> requieren ser trasladarlos en primer lugar a ese punto de origen, luego girarlos, y por último volverlos a dejar en su sitio.
Matemáticamente la diferencia de dos vectores A -B se define como la suma del vector A con el B invertido de dirección. (Si tenemos los vectores A y B la resta A -B es lo mismo que A+ (B*-1) ). Cosas de vectores. Suena algo lioso, pero si no tienes un modelador o un software que te resuelva este tipo de cosas, necesitaras tener una base de matemáticas (vectores y trigonometría). De momento esto te ayudará a entender el fuente si te da por ahí.
La primitiva spotlight ademas de la dirección de la luz necesita un radio para determinar la anchura del cono con brillo total y un varor falloff que será el radio del cono de luz donde esta muere.
En el fuente POV usaremos lo siguiente:
#declare Ruta = spline { natural_spline
#include "rutaspline.inc" // ** Incluye la funcion Ruta que calcula cada punto por interpolación spline
}
#declare camara1=camera{ // ** Usar para vista desde vehículo.
location Ruta(clock) + <0,1,0> //
look_at Ruta(clock+.75) + <0,.20,0>
right <4/3,0,0> // **
angle 80 // gran angular
}
camera {camara1}
#declare Bola= object {sphere {<0,0,0> 0.3} pigment {Yellow}}
object {Bola translate Ruta(clock+1)+<0,0.5,0> }
#macro TripleFaro (PotFaro, RadFaro, From, At)
#local Fall=RadFaro*3;
union {
/** Antes de girar hay que llevarlo a <0,0,0> y luego volver a dejarlo
donde estaba ***/
object { light_source { <0,0,0> White*PotFaro*.6
spotlight point_at (At - From) // La resta de vectores nos da la dirección correcta en <0,0,0>
radius RadFaro falloff Fall}
rotate y*(15)
translate From
}
object { light_source { From White*PotFaro
spotlight point_at At
radius RadFaro falloff Fall}
}
/** Antes de girar hay que llevarlo a <0,0,0> y luego volver a dejarlo
donde estaba ***/
object { light_source { <0,0,0> White*PotFaro*.6
spotlight point_at (At - From) // La resta de vectores nos da la dirección correcta en <0,0,0>
radius RadFaro falloff Fall}
rotate y*(-15)
translate From
}
}
#end
TripleFaro(1, 4, Ruta(clock) +<0,1.5,0>, Ruta(clock+0.8)+<0,-0.3,0> )
TripleFaro( .9, 4, Ruta(clock+1)+<0, 1 ,0>, Ruta(clock+2 )+<0,-0.5,0> )
Para finalizar:
Hemos continuado trabajando con el mismo escenario y con el mismo número de fotogramas para poder contrastar las imagenes de la escena en un determinado momento desde distintas perspectivas, pero ya hemos completado la ruta 3D. En futuros ensayos seremos libres para abandonar estas restricciones que nos habíamos autoimpuesto.
En este artículo construiremos la ruta 2D para unas naves espaciales. Para ello recurriremos al uso de la función de ‘spline()’ que incorpora Povray. Los vídeos que obtengamos, como los que puedes ver aquí , no son vídeos de producto final. Tenemos que eliminar todo lo superfluo para que el proceso de renderizado de la escena sea rápido. Nos van a interesar estos vídeos como fuente de información para continuar el proyecto. Son una forma de mirar antes de programar algo y la estética no es importante en este momento.
Visión desde arriba:
Tal y como acabo de explicar, los vídeos no importan mucho. Lo realmente importante van a ser los fotogramas que debemos conservar. Ahora mostramos un segundo vídeo con idéntico número de fotogramas y que se corresponde en el tiempo fotograma a fotograma con el anterior. Este segundo vídeo muestra una toma realizada desde una cámara virtual que vuela siguiendo el desplazamiento de nuestra sonda de profundidad. Se trata de un objeto cilíndrico que tiene marcas negras cada 0.5 unidades, y que se moverá por la ruta que seguirá nuestra nave lo más cerca posible del suelo.
Visión siguiendo al vehículo:
La función spline de Povray:
Una función spline permite unir puntos mediante una línea con curvas suaves evitando que esta parezca quebrada. Explicaremos esta función con un ejemplo:
#declare Mi_Funcion_Spline =
spline {
natural_spline // ** Tipo de función spline (natural_spline, linear_spline, etc.)
1,< 23, 24>, // Punto de control
2,<123, 64>,
3,<167,200>,
4,<212,285>,
5,<293,297>,
6,<552,205>,
7,<537, 71>,
8,<358,122>,
9,<262,130>,
10,<238, 24> // Punto de control
}
Curva spline.
Hemos puesto un ejemplo de una curva abierta. En una curva cerrada los puntos de control preparan la dirección correcta para que la unión de los extremos no forme un ángulo.
Nuestra curva spline:
Para nuestro proyecto, empezaremos construyendo una curva spline aplanada y adaptada con precisión a la ruta del terreno. Este será el primer paso para la construcción de una verdadera ruta 3D que incluya también la navegación en altura. Como punto de partida para calcular la ruta sólo disponemos de la imagen del terreno. Es la imagen ‘terreno2.png’ que es la responsable de definir el relieve de la escena. Se trata de una imagen de 2000×2000 pixels. Lo que haremos será sacar una copia ‘terreno3.png’ y marcar en ella los puntos de nuestra ruta spline para la navegación de nuestras naves.
Terreno2.png
terreno3.png
Usaremos las coordenadas X,Y de la imagen como referencia posteriormente, así que iremos anotando cada uno de los puntos que situaremos con precisión en nuestra ruta que tiene forma de ocho con un tramo central corto.
Descripción del trazado de la ruta (solo para el que le interese):
Empezaremos el trazado de la ruta por aquí llamando a este tramo ‘tramo1’ que tendrá solo tres puntos, y antes de ello hay que definir un punto que llamaremos ‘Ini’ inicializar el spline adecuadamente, y otro justo antes del ‘tramo1’ que será común a las otras dos rutas porque se trata el punto de una bifurcación. Al final del ‘tramo1’ hay otra encrucijada situada en un punto que llamaremos ‘p2’. Al llegar a ella tiramos por el ‘tramo2’ que hace un bucle y termina de nuevo en el punto ‘p1’ del cual salimos pero ahora en lugar de tomar por el ‘tramo1’ tomamos el ‘tramo3’ que después de otro bucle termina en el punto ‘p2’. Hemos completado el circuito en forma de ocho, pero nuestro recorrido continuará ahora en sentido inverso ‘tramo1’, ‘tramo2’ y ‘tramo3’.
Podríamos finalizar aquí el recorrido, pero lo que hacemos es duplicarlo (más adelante quizás necesitemos triplicar la ruta) . Esto de duplicar o triplicar la ruta lo hacemos para tener margen para planificar recorridos con varias naves desfasadas unas de otras, con la idea de que se crucen entre ellas navegando a distinta altura, y que pese al desfase no se salgan nunca de la ruta definida.
Por desfase quiero significar que usarán la misma ruta pero como si hubieran salido en distinto momento. No vamos a intentar dar valor a la altura de las naves en este momento, porque hemos preparado una ruta que tiene irregularidades en altura para hacerlo más interesante y no tenemos ni idea de donde quedan los baches.
La cuarta dimensión de la función spline en Povray:
Puedes ver en terreno3.png la situación de los puntos. La ruta spline debes imaginarla como una ruta en cuatro dimensiones porque el tiempo viene marcado por la situación de los puntos (nosotros por claridad hemos usado un punto por cada unidad de tiempo). Entre punto y punto se van a interpolar un número constante de fotogramas y por eso, si distancias mucho los puntos, el vehículo se moverá rápido, y si los ponemos juntos irá lento.
Si hubiéramos pretendido diseñar una carrera de naves como en la guerra de las galaxias no podríamos compartir la misma ruta para las naves jugando con el truco del desfase. Por el contrario, cada nave necesitaría tener definida su propia ruta y todas las rutas irían sincronizadas con un mismo valor de clock. De esa forma los adelantamientos entre vehículos simplemente requerirían poner el punto más adelantado para un mismo valor clockc. Nuestro caso es mas sencillo, pero estamos dando toda la información para intentarlo tú mismo.
Los puntos los hemos dibujado con Gimp y puedes verlos en la imagen ‘terreno3.png’ (sólo es una imagen para referencia) puedes comprobar que en las curvas hemos puesto los puntos más apretados y las naves irán más lentas en las curvas acelerando luego después en las zonas más rectas.
A partir de este momento con los puntos que definen la ruta bien situados, tendremos que convertirlos a las coordenadas que use povray, porque estamos usando coordenadas X,Y obtenidas con Gimp. Mejor que usar la calculadora haremos un script en lenguaje Python, que podría servirnos para asociar eventos a la ruta, o par añadir nuevas rutas en un futuro.
Si implementas más de una ruta te recomiendo que uses incrementos de tiempo iguales y constantes para todas las rutas. Es decir, todas las rutas tendrán una ruta spline con el mismo número de puntos y con valores cada cierta unidad de tiempo para todas las rutas. Panificarlo así te resultará más sencillo.
Uso de un script en python para generar la ruta:
Nuestro script en lenguaje python se llama ‘rutaspline.py’ y generará un largo fichero ‘rutaspline.inc’ que contendrá todos los puntos del recorrido. Este script tiene que convertir unas coordenadas que en Gimp vienen referidas a un sistema donde la esquina superior izquierda es (0,0) y la inferior derecha es la (2000,2000) a otro donde Povray usa un sistema donde a vista de pájaro con nuestra cámara definida (porque así nos interesó). A continuación te muestro como quedaría el fuente pov relativo a las cámaras y al objeto que se mueve por nuestra ruta.
#declare camara0=camera{ // ** Usar para vista desde arriba
location <0, 140, 0>
look_at <0, 0, 4>
right <16/9,0,0> // **
angle 22
}
#declare camara1=camera{ // Usar para vista persiguiendo a un objeto por la ruta
location Ruta(clock) + <0,1,0> // Un poco por detras del objeto movil en la ruta
look_at Ruta(clock+.75) + <0,.20,0> // Mira a la parte trasera del objeto movil situado delante de la cámara.
right <16/9,0,0> // **
angle 80 // gran angular
}
object {ObjetoMovil translate Ruta(clock+1)} // Movimiento .
En este caso la esquina superior izquierda del terreno se corresponderá con la coordenadas Povray <-20,20,?> y la inferior derecha <20,-20,?>. (Siempre es recomendable definir los objetos centrados en el centro de coordenadas <0,0,0>).
Para pasar de un sistema de coordenadas a otro hacemos uso de unas funcioncitas fx() y fy() que aplicadas a los datos recogidos obtengan el dato ya convertido tal y como lo necesitamos en ‘rutaspline.inc’. El trozo del programa en lenguaje Python que hace esto sería:
No vamos a poner el código completo en este momento, porque sería muy pesado hacerlo para cada cambio introducido. En esta primera versión usamos listas de dos elementos para guardar las coordenadas de los puntos (coordenadas X , Z ) ya que la coordenada y será constante.
Es decir, la coordenada del punto ‘Ini’ (de control), ‘P1’, las tres del ‘tramo1’, y las del punto ‘P2’ se codificarían como:
No ponemos más para abreviar (Los tramos 2 y 3 y el punto de control End se codificaría de forma similar). En lenguaje Python con los tramos y los puntos almacenados así podemos juntar los tramos, añadir puntos, invertir tramos, concatenarlos, duplicarlos, etc. Operar con listas de elementos resulta muy sencillo en este lenguaje:
ruta=[]
ruta.append(p1)
for p in tramo1:
ruta.append(p)
ruta.append(p2)
for p in tramo2:
ruta.append(p)
ruta.append(p1)
for p in tramo3:
ruta.append(p)
ruta.append(p2)
#### Sentido contrario ####
tramo1.reverse()
tramo2.reverse()
tramo3.reverse()
for p in tramo1:
ruta.append(p)
ruta.append(p1)
for p in tramo2:
ruta.append(p)
ruta.append(p2)
for p in tramo3:
ruta.append(p)
## Para finalizar duplicamos la ruta y rematamos los extremos con los puntos de control.
ruta = [Ini] + (ruta *2) + [End]
Hemos creado una ruta muy larga con varias vueltas al circuito. El fichero ‘rutaspline.inc’ generado tendrá este aspecto.
Cuando necesitemos añadir la coordenada Y que ahora va con un valor constante, el programa python apenas variará salvo para incluir esos datos en la declaración de las listas (Las operaciones con listas en lenguaje Python facilitan mucho esta labor).
El programita Python ‘rutas.py’ puede ir incorporando nuevas funcionalidades. Por ejemplo lo usé para generar un segundo fichero include ‘marcas.inc’ que construye una serie de objetos cónicos situados en cada uno de los puntos de marca de la ruta spline. Estos conos tendrán unos colores que nos ayudarán a la identificación de esos lugares.
Por ejemplo la bolita cerca de la punta tiene un color que identifica la ruta, y el ajedrezado combina los colores siguiendo una secuencia que puede orientar sobre el número del punto spline en ese tramo.
Nosotros aplicaremos la ruta spline a un poste cilíndrico graduado que desplazaremos por el recorrido de forma que nos sirva de referencia para sondear la profundidad del terreno en cada punto. La marca más gruesa del poste se corresponde con la altura cero, y cada marca fina está a 0.5 unidades de las marcas adyacentes.
Con todo ello, generaremos dos animaciones que solo difieren en el punto de vista de la cámara. Una vista desde arriba y otra siguiendo el movimiento de ese poste que hace de sonda para estimar la profundidad del terreno en cada punto de la ruta.
Trabajaremos durante un tiempo con estas escenas donde las 750 imágenes de estos dos vídeos tienen una correspondencia que nos permitirá más adelante evaluar la altura del terreno en cada punto de la ruta spline, pero con lo que ya hemos comentado me parece más que suficiente materia para un solo capítulo que seguramente ya estabas deseando que finalizara.
El paso de esta ruta 2D a una 3D será objeto del siguiente capítulo.
Este artículo será el primero de una serie de ellos en los cuales iremos elaborando paso a paso un proyecto de animación con Povray que llamaremos «Exploración Espacial» y que será suficientemente completo como para ilustrar un amplio repertorio de técnicas, muchas de las cuales no las habíamos comentado anteriormente.
El contenido del artículo y de sus ficheros son de libre uso bajo licencia GPL. Las imágenes se incluyen a resolución completa para que se puedan usar junto con el fuente de Povray que en esta primera parte es muy sencillito.
Para esta serie de artículos asumiremos que ya tiene algo de experiencia en el uso de Povray. En caso contrario se recomienda practicar con los tutoriales anteriores.
Gaviones una mirada retrospectiva:
Gaviones
Gaviones fue mi primer vídeo con cierta complicación técnica debida a las limitaciones con las que tuve que trabajar. Lo desarrollé en 1998 y en aquel entonces Povray carecía de muchas de las facilidades actuales para generar animaciones. Para colmo la lentitud de los ordenadores de aquella época resultaba un grave inconveniente.
Este proyecto «Exploración Espacial» tiene bastante que ver con aquel «Gaviones» ya que tratará de persecución de naves espaciales por un terreno con un relieve accidentado. En Gaviones no necesité hacer una ruta muy precisa ya que el escenario era un archipiélago, mis gaviones volaban alto, y lo que hice fue orientarme muy a grosso modo dibujando una cuadrícula que podía superponer encima del escenario (el archipiélago).
En esta ocasión pretendo que las naves recorran un angosto valle a poca distancia de las paredes del mismo para crear un efecto visual más interesante.
El Terreno:
La Isla de Macaula, (otro proyecto del cual ya hablé) la dibujé entera y en ese proyecto ya se explicó ampliamente el uso de la primitiva ‘height_field’ que también usaremos ahora.
Terreno1.png
Terreno2.png
En esta ocasión la usaremos suministrando un terreno que se ha construido inicialmente en Gimp con el siguiente procedimiento:
En una imagen de 2000×2000 pixels se aplicó una función plasma: Filtros–>Renderizado–>Nubes–>Plasma.
Luego lo pasamos todo a tono de grises usando: Colores–>Tono y saturacion –> Saturación=-100 (Veasé imagen Terreno1.png)
Por último con el spray se dibujó en blanco un circuito con forma similar a un ocho (Veasé Terreno2.png). Esto nos dará el relieve.
La altura del terreno queda marcada por la oscuridad de cada pixel.
Falta colorearlo. Para ello pensé inicialmente darle unos tonos rojizos al terreno simulando así un terreno marciano, pero me quedó un pelín soso.
'Pigmentación desértica': (pigment0.png)
Paisaje desértico (ExploracionEspacial0.png)
Véanse las imágenes: ‘Pigmentación desertica’: ‘pigment0.png’; ‘Paisaje desértico’: ‘ExploracionEspacial0.png’.
Decidí entonces espolvorear un poquito de nieve en las cumbres y otro poco en la parte baja del valle. Véanse las imágenes ‘Pigmentación nevada’: ‘pigment.png’ y ‘Paisaje nevado’: ExploraciónEspacial.png’.
Pigmentación nevada (pigment)
'Paisaje nevado': (ExploraciónEspacial.png)
Para conseguir una correcta iluminación he tenido que crear numerosos puntos de luz repartidos circularmente en la periferia del terreno. Esto lo he hecho con un bucle while.
Todo esto lo he hecho en primer lugar porque es interesante averiguar el potencial estético del escenario antes de continuar construyendo sobre él, pero para continuar desarrollando eliminaremos muchas cosas que retrasan el proceso de renderizado.
Para hacer ensayos de prueba y error hay que agilizar al máximo el proceso de renderizado. Eso se logra trabajando con resoluciones más bajas, el terreno lo usaremos sin suavizar y con un color uniforme blanco, y también usaremos un solo foco de luz. No tendrá el mismo aspecto pero nos permitirá ver lo que hacemos.
Es importante que tengamos esta referencia visual previa del aspecto final que deseamos obtener antes de continuar construyendo más cosas sobre este escenario, porque sobre él trazaremos una ruta y no podemos estar haciendo cambios más adelante.
Dejamos el tema del trazado de la ruta, que debe ajustarse con la máxima precisión al terreno para un artículo posterior.
Utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si continúa utilizando este sitio asumiremos que está de acuerdo.