‘Exploración espacial’ (parte 2): Trazado de la ruta en 2D.

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.
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
Terreno2.png

terreno3.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:

##############################
def fx(x):
      return (x-1000)/50.0

##############################
def fz(z):
     return (z-1000)/-50.0

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:

Ini=[1123,327]
p1=[1053,687]
tramo1=[ [1194, 843], [1401, 921], [1602, 960] ]
p2=[1695, 924]

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.

1, <1.060000,-2.200000,6.260000>,
2, <3.880000,-1.200000,3.140000>,
3, <8.020000,-1.000000,1.580000>,
4, <12.040000,0.150000,0.800000>,

...

184, <-11.420000,-2.400000,2.900000>,
185, <-8.660000,-2.400000,4.460000>,
186, <-2.060000,-2.400000,5.600000>,

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.

object{ cone { <1.0600,-2,6.2600> 0.8000, <1.0600,0.5,6.2600> 0} pigment { checker  Red  transmit .65, Red  transmit .65 scale .5 } } // -1
object{ sphere { <1.0600,0,6.2600> 0.17} pigment { White  transmit .65 } }
object{ cone { <13.9000,-2,1.5200> 0.8000, <13.9000,0.5,1.5200> 0} pigment { checker  Red  transmit .65, Red  transmit .65 scale .5 } } // -1
object{ sphere { <13.9000,0,1.5200> 0.17} pigment { White  transmit .65 } }
object{ cone { <3.8800,-2,3.1400> 0.6000, <3.8800,0.5,3.1400> 0} pigment { checker  Yellow  transmit .65, Gray30  transmit .65 scale .5 } } // 0
object{ sphere { <3.8800,0,3.1400> 0.17} pigment { Red  transmit .65 } }

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.

Share

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*