Mapas 3D con Godot engine 3.0

Mapas 3D, y sus aplicaciones

Generar mapas en 3D de cualquier parte del mundo… para que sirve?
Bueno, a parte ser visualmente impactante, puede ser útil en algunos campos cómo arquitectura, aplicaciones de rastreo y videojuegos.

De hecho esa última es la razón principal del módulo (addon) que he creado en Godot 3.0.

Como funciona

Primero he decidido utilizar lo que MapBox pone a disposición: imágenes satelitales y mapas de elevación.
La API es fácil de utilizar y solo necesitas crear una cuenta y obtener el token.

Imágen satelital del volcán Cotopaxi y su heightmap

Imágen satelital del volcán Cotopaxi y su heightmap

El proceso de generación de los mapas utiliza los heightmap para dibujar el modelo 3D, y una imagen satelital de la misma área para el color de cada polígono dibujado.

Próximamente planeo añadir texture y normals (que permitiría aumentar el nivel de detalle, o reducir el número de poligonos sin perder cualidad), también de ser posible LOD automático

Mapas de elevación

Las mapas de elevación utilizan imágenes cuya información de elevación es codificada en sus colores:
Cada componente de color (rojo, verde y azul) corresponde a una cantidad (en metros). Y eso, según la documentación oficial, se decodifica con esta fórmula:

var altitude = -10000 + ((r * 256 * 256 + g * 256 + b) * 0.1)

Así que es de notar que las mapas de elevación, no son una falsa coloración que nos indica la elevación.
Por eso, de la imagen de elevación, no siempre se puede entender la forma del objeto.

En mi implementación cada pixel corresponde a un quad, o 2 triangulos que toman como elevacíon la del pixel analizado y de sus pixeles contiguos, de esta forma:

var bottomleft = Vector3(i * dist - half_size, ht[i][j]["height"] * altitude_multiplier, j * dist - half_size)
var bl_color = ht[i][j]["color"]
var upperleft = Vector3(i * dist - half_size, ht[i][j + 1]["height"] * altitude_multiplier, (j + 1) * dist - half_size)
var ul_color = bl_color.linear_interpolate(ht[i][j + 1]["color"], 0.5)
var upperright = Vector3((i + 1) * dist - half_size, ht[i + 1][j + 1]["height"] * altitude_multiplier, (j + 1) * dist - half_size)
var ur_color = bl_color.linear_interpolate(ht[i+1][j+1]["color"], 0.5)
var bottomright = Vector3((i + 1) * dist - half_size, ht[i + 1][j]["height"] * altitude_multiplier, (j) * dist - half_size)
var br_color = bl_color.linear_interpolate(ht[i+1][j]["color"], 0.5)
surf_tool.add_color(bl_color)
surf_tool.add_vertex(bottomleft)
surf_tool.add_color(br_color)
surf_tool.add_vertex(bottomright)
surf_tool.add_color(ul_color)
surf_tool.add_vertex(upperleft)
surf_tool.add_color(br_color)
surf_tool.add_vertex(bottomright)
surf_tool.add_color(ur_color)
surf_tool.add_vertex(upperright)
surf_tool.add_color(ul_color)
surf_tool.add_vertex(upperleft)

Es de notar que al momento de renderizar los colores no son exactamente los mismos de la texture, eso debido a la interplación de colores, aspecto que mejoraré en las próximas versiones.

Imágen Satelital (texture)

La imágen satelital, o texture, es utilizada para dar un color por cada triangulo dibujado en 3D.

Así que cáda vertex que se añade toma el color del pixel correspondiente.

Obtener los datos desde MapBox

Otro elemento importante de esta implementación es el servicio que MapBox pone a disposición (la verdad, he buscado entre los datos que la NASA pone a disposición, pero no encontré una respuesta rápida, y decidí ir por la ruta más fácil, ya que estoy familiarizado con las APIs de MapBox).

Simplemente decodificando las coordenadas en el tile correspondiente se obtienen las imágenes de elevación y satelitales. Aproveché de esta necesidad (de decodificar latitud, longitud y zoom en el tile correspondiente), para crear una pequeña librería que me permite esta y otras decodificaciones.

 

Resultado final y problemas técnicos encontrados

El resultado final (el glitch verde, al final, no es del renderer, sino una falla en la conversión a gif)

Bueno, cómo siempre se dice, una imagen dice mas que mil palabras, así que aquí pueden ver el resultado final.

Cabe destacar que debido a problemas no resueltos, cada imagen resulta en el rendering de 4 o hasta 16 tiles, o mesh, más pequeñas, lo que resulta en el desalineamento, en ciertos casos, de los tiles contiguos, cómo se puede notar en la animación.

Posted in 3D, Videojuegos and tagged , , , , , , .

Deja un comentario

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.