Generación de mapas de polígonos aleatorios procedimentales

Original: https://www.jianshu.com/p/08e9b772964b

prefacio

Recientemente, el equipo quería desarrollar un juego de mundo abierto. Este es un concepto de juego muy interesante. Sin embargo, después de referirnos a la configuración de "The Legend of Zelda: Breath of the Wild", descubrimos que el éxito de este juego se debe en gran parte debido a la gran cantidad de arte y diseño. Este es un continente muy interesante, pero nuestro equipo no tiene forma de construir manualmente una escena tan grande, así que se me ocurrió una idea muy natural: escribir un guión que genere automáticamente un terreno razonable .

Al principio probé el ruido de Perlin para generar directamente un mapa de altura, pero el terreno resultante era demasiado extremo y el desarrollo del script también entró en un punto muerto, hasta que vi un artículo en 2010: Dirección original: http://www
-
cs - Students.stanford.edu/~amitp/game-programming/polygon-map-generation

Este artículo implementa una demostración de un mapa de polígonos aleatorio automático en flash. Seguí la idea de este artículo y básicamente copié una versión de unity3D. Es posible que escriba una versión irreal en el futuro.

Dirección de github del código fuente

representaciones

Mapa básico de celdas poligonales

Dado que se va a generar un mapa basado en polígonos, el primer paso es, por supuesto, generar un gráfico bidimensional lleno de polígonos. En términos de terminología, este gráfico se llama Diagrama de Voronoi, y prefiero llamarlo mapa de celdas. .

Hay muchos principios para generar tales gráficos en Internet. Me refiero a este artículo:

http://blog.csdn.net/k346k346/article/details/52244123

Cabe señalar que el gráfico generado por este método es demasiado aleatorio, necesitamos que se vea más ordenado, este usa el algoritmo de relajación llamado Lloyd, que es un algoritmo de agrupamiento, simplemente hablando, después de varias iteraciones, cada iteración mueve el punto central. del diagrama de Voronoi al centro del polígono y vuelve a calcular el diagrama de Voronoi. Después del experimento real, se descubrió que 2 iteraciones pueden lograr el efecto por completo.

estructura de datos

El archivo VoronoiElement en el código fuente guarda la estructura de datos, y la mayoría de ellos tienen comentarios.La clase Center que necesita ser explicada representa el punto central del diagrama de Voronoi, que es el vértice de la red triangular de Delaunay, y la clase Corner representa el centro exterior del triángulo, y también es el punto de intersección de los polígonos en la figura. El propósito de hacer esto es en realidad generar la información de dos imágenes, la imagen triangular y la imagen poligonal. En el desarrollo posterior, la imagen triangular se puede usar para la búsqueda de rutas y la imagen poligonal se usa principalmente para renderizar.

Diferenciar entre tierra y agua.

En el segundo paso, debemos agregar la diferencia entre los continentes y el agua a nuestro mapa. Hay muchos factores en la formación de agua superficial en la naturaleza, pero solo podemos usar simulación aleatoria al simular.

El artículo original dio muchas ideas de simulación, así que utilicé el método de ruido de Perlin para la simulación. Primero, calculé un valor de ruido de Perlin para cada punto de esquina en el mapa y establecí ciertos parámetros para determinar si el valor de ruido puede hacer que la esquina tenga propiedades del agua. La forma en que solo uso es comparar (PerlinNoise) y (waterScale + waterScale * Distancia (centro del mapa, el punto)) el tamaño, de modo que el valor del parámetro de waterScale se pueda modificar para modificar la cantidad de agua generada por el mapa , y al mismo tiempo asegúrese de que el borde del mapa sea más fácil de ver, lo que hace que nuestro mapa se vea como un continente en el mar (el borde de mi mapa predeterminado es el agua).

Después de determinar los atributos del punto de la Esquina, registramos el Centro (es decir, el polígono) conectado a la Esquina del agua como el atributo del agua, y el Centro conectado a él se puede obtener a través de la lista de toques de la Esquina.

Diferenciar entre océanos, lagos interiores y costas

En primer lugar, estipulamos que el polígono que bordea el límite del mapa es el océano, toda el agua en contacto con el océano es el océano, la tierra en contacto con el océano es la costa y el resto del agua es el lago.

Aquí, se utiliza un algoritmo de llenado de semillas para el cálculo. De hecho, esta es una estrategia de búsqueda en amplitud. Primero agregamos el centro en el borde del mapa a una cola de cola y luego ejecutamos un bucle hasta que no quedan elementos en la cola. Cada vez que el bucle saque el Centro al final de la cola, verifique los polígonos adyacentes que están en contacto directo con el Centro (esto se puede encontrar en la lista vinculada de vecinos). Si el Centro adyacente es agua y no un océano, significa que este es un Centro que aún no ha sido procesado Establézcalo como Océano y únase a la cola, si el Centro adyacente no es agua, configúrelo como Costa y únase a la cola.

Después de procesar todos los Centros, solo necesitamos establecer el polígono de la esquina del océano como el océano y el polígono de la esquina de la costa como la costa.

 

dar altura

A continuación, agregamos elementos de altura a nuestro mapa, lo que hace que nuestro terreno sea accidentado.

Para hacer que el terreno fuera aleatorio pero razonable, adoptamos esta estrategia:

Tiene sentido que los lugares cercanos a la costa tiendan a ser bajos y los centros de las islas tienden a ser altos.

El plan de implementación también es una búsqueda en amplitud. Definimos un atributo de elevación para cada Esquina, que representa la distancia más corta desde la línea de costa. Cada vez que pasa una Esquina, se agrega un cierto valor aleatorio a esta distancia (cuanto mayor sea el rango de esta valor aleatorio, el terreno se volverá más accidentado).

Una vez finalizada la búsqueda, unificamos la elevación de cada esquina a 0~1 como la altura de este punto, y la altura de cada centro es la altura promedio de todas las esquinas del polígono.

Cabe señalar que necesitamos realizar una operación adicional después de unificar la altura de la esquina, necesitamos calcular la dirección de la pendiente máxima de cada esquina, que preparará para la generación de ríos en el futuro.

 

río

En el paso anterior, hemos calculado la dirección de la mayor pendiente de cada esquina, por lo que nuestra generación de ríos es simple, solo necesitamos dar algunos parámetros: la altura mínima del río y el rango del número de ríos. . Luego damos al azar el punto de partida del río (asegúrese de que sea mayor que la altura mínima y en tierra), y luego dejamos que el río fluya hacia abajo de acuerdo con el gradiente, y cada Corener que fluye se establece como un río hasta fluye hacia un lago u océano, o después de cierta distancia

 

  • En este punto, nuestro mapa es bastante bueno, pero para el juego todavía agregamos dos características al polígono.

Humedad y Biomas

Todavía usamos el proceso opuesto al mundo natural. Determinamos la humedad del polígono por la distancia desde el polígono a la fuente de agua. El esquema de cálculo es básicamente el mismo que el cálculo de la altura.

 

Con la humedad y la altura, podemos simular los tipos de plantas en el terreno. Aquí usamos un gráfico de este tipo para la simulación:

Los lectores pueden modificar los datos para hacer que el terreno sea más seco o más húmedo.

representación

Hasta ahora hemos utilizado la depuración gráfica para mostrar, también necesitamos renderizar una malla 3D.

Usé el método de representación de malla que viene con Unity, agregué componentes MeshRenderer y MeshFilter a un GameObject, modifiqué las propiedades de vértice y triángulo de la malla, y usé todo el centro y la esquina como vértices. Para cada polígono, deje que el vértice central y cada uno de los lados forma una malla triangular (aquí, tenga en cuenta que los vértices de los triángulos deben ordenarse en el sentido de las agujas del reloj para garantizar que la dirección normal sea correcta) y, al mismo tiempo, divida la malla en 13 submallas (que representan 13 tipos de comunidades), y determine la distribución de la malla triangular según el bioma poligonal A qué submalla (mesh.SetTriangles), asigne 13 materiales a MeshRenderer para completar la representación.

fin

Actualmente, solo uso colores sólidos para reemplazar los materiales de diferentes comunidades. En el futuro, refinaré cada material para lograr un efecto similar al renderizado de polígonos bajos.

Y hay muchos cálculos de ruido y fusión que no se han hecho, como límites mixtos.

Las imágenes en los pasos de este artículo son un total de 500 polígonos, y el renderizado final tiene un total de 2000 polígonos. La compilación, el inicio, el cálculo y el renderizado tardan unos 20 segundos. El juego real tardará menos tiempo en calcularse y no hay La biblioteca del motor de Unity se usa para que pueda completarse en subprocesos múltiples.

Supongo que te gusta

Origin blog.csdn.net/tangyin025/article/details/123301572
Recomendado
Clasificación