Tengo un terreno generado, con geometría hexagonal, según la captura de pantalla a continuación:
Luego genero biomas, pero como pueden ver, los límites entre ellos son realmente feos y rectos. Para ocultar ese origen hexagonal, necesitaría suavizar los bordes entre los biomas. Así es como se ve ahora en estructura metálica con caras tringulares reales:
Lo que busco es algo más como esto:
Cada vértice tiene un atributo que contiene el tipo de bioma, también puedo agregar atributos especiales a los vértices en el borde entre dos biomas, pero parece que no soy capaz de descubrir cómo lograr esto en el código del sombreador, obviamente ruido está involucrado aquí, pero ¿cómo hago que sea continuo a través de múltiples caras y todo el borde de múltiples biomas?
Estoy renderizando con WebGL usando THREE.js
Respuestas:
Otras respuestas aquí sugieren usar una textura. Aquí hay una técnica que no usa texturas.
Desea que los límites entre hexágonos sean interesantes. Es más fácil establecer límites interesantes cuando los mueve al centro de lo que está dibujando. En lugar de dibujar los mosaicos directamente, dibuja el "dual" del mosaico. Esta técnica se llama “azulejos de esquina” ( aquí y aquí y aquí ). El dual de un hexágono es un triángulo, por lo que dibujaríamos estos triángulos en lugar de los hexágonos:
Los límites entre los hexágonos ahora están en el medio de los triángulos renderizados, por lo que nos permitirá hacer cosas más interesantes con ellos. Bonificación: solo necesitas dibujar dos triángulos por hexágono, en lugar de seis (o veinticuatro como lo estás haciendo ahora).
Dentro de cada uno de esos triángulos queremos que el sombreador de fragmentos dibuje los hexágonos. Podemos hacer eso con coordenadas barcéntricas . Ponga (1,0,0), (0,1,0) y (0,0,1) en cada vértice del triángulo. Dentro del triángulo, esas coordenadas serán interpoladas. El sombreador de fragmentos recibirá (a, b, c) y puede mirar para ver qué valor es el más grande; eso nos dirá cuál de los tres hexágonos se debe dibujar en este punto.
float max_n = max(barycentric.r, max(barycentric.g, barycentric.b)); if (max_n == barycentric.r) { color = v_color0; } else if (max_n == barycentric.g) { color = v_color1; } else if (max_n == barycentric.b) { color = v_color2; }
Eso es para líneas rectas.
Si desea bordes ruidosos, puede agregar ruido a las coordenadas barcéntricas:
Al jugar con la amplitud de onda / frecuencia de ruido, puede obtener algunos efectos geniales:
Debe tener cuidado con el ruido, asegurándose de que sea consistente a través de los límites de los triángulos. Una forma de hacerlo es pasar una identificación hexadecimal y usarla como valor inicial para cada uno de los tres valores de ruido agregados a las coordenadas barcéntricas.
Hice una demostración interactiva aquí . (Para la demostración, no implementé la identificación hexadecimal o algunas de las otras cosas que podría necesitar si estuviera haciendo que esto funcione en un proyecto real, es solo una demostración rápida y sucia)
fuente
Estoy seguro de que "podría" resolverse con algún algoritmo de imagen, pero si fuera yo, probablemente lo resolvería con texturas. Hacía texturas hexagonales, las ponía todas en un atlas de texturas, luego, para cada hexágono, miraba a sus vecinos y decidía qué textura aplicar.
Las texturas necesitarían tener versiones para cada tipo de terreno más versiones para cada tipo de transición.
Esto es similar a la cantidad de sistemas basados en mosaicos que hacen el terreno. Aquí hay un ejemplo de juegos 2D .
Otra posibilidad sería simplemente tener sus texturas para sus diversos tipos de terreno (agua, nieve, tierra, hierba) y agregar cantidades de mezcla a cada vértice del hexágono para decidir cómo mezclarlos.
Este artículo muestra la idea de mezclar texturas de terreno. No sugiero seguir su implementación, pero muestra la idea.
fuente
Primero, convierte tus biomas en una textura. Mapear los triángulos a texcoords. Puede hacer esto usando una proyección de mercator o, mejor, un mapa de cubos . Ahora, en el fragment shader, haz algo como esto:
donde
noise
hay alguna función pseudoaleatoria (usando, por ejemplo, sinusoides) en la posición 3D del vértice en el espacio modelo que devuelve un desplazamiento ruidoso a la coordenada de textura. Pruebe la textura usandoGL_NEAREST
para mantener bordes afilados.fuente