Generar terrenos con Perlin Noise y ThreejS
Este ejemplo consiste en generar un terreno en 3 dimensiones con ThreeJS a partir de una imagen generada con Perlin Noise. El Perlin Noise es una función matemática que utiliza gradientes precalculados para generar valores pseudoaleatorios que pueden generar a su vez (por ejemplo) imágenes. Por ejemplo, un par de imágenes generadas a partir de Perlin Noise:
Como se puede ver en la imagen, el Perlin Noise genera imágenes con apariencia aleatoria, pero con cambios de color progresivos entre pixel. Es decir, no vemos un pixel negro junto a uno blanco, sino que los pixels aparecen «difuminados», sin cambios de color bruscos entre ellos.
En este ejemplo he utilizado la libería ToxicLibsJS, que tiene un módulo para generar imágenes con Perlin Noise. Al crear la imagen, almaceno el valor de color de cada pixel generado en una matriz para utilizarlo posteriormente. Después creo un plano con tantos vértices como pixels tiene la imagen. Como la imagen es de 200×200 pixels, necesito un plano de 200×200 vértices. Viendo la estructura de un plano:
Vemos que por ejemplo un plano de 3×3 segmentos tiene 4×4 vértices, es decir, un plano de nxn vértices tendrá (n-1)x(n-1) segmentos (el tercer y cuarto parámetro del constructor de un plano en ThreeJS son los segmentos de ancho y de alto), por lo que generamos nuestro plano con:
1 |
plano_suelo_general = new THREE.PlaneGeometry(1000,1000,lado-1,lado-1); |
Hecho esto, recorremos la matriz de vértices y colocamos cada uno en una altura proporcional al color del pixel que le corresponde(en color hexadecimal, el blanco sería 0, y el negro 1)
1 2 3 |
for(var i = 0; i < puntos_noise.length; i++) { plano_suelo_general.vertices[i].z = Math.max(0,altura * puntos_noise[i]/20); } |
Y ya está! a partir de aquí podemos hacer lo que queramos con el terreno generado. En este caso yo he dejado fija la cámara y giro el terreno para generar la sensación de movimiento, y he añadido unos sliders (con MinimalCompsJS) para hacer modificaciones sobre el terreno. El código del ejemplo está comentado, cualquier duda, comentario o propuesta la podéis hacer en los comentarios del post.