¿Cómo creo un ruido sólido enlosable para la generación de mapas?


16

Hola chicos, estoy tratando de descubrir cómo generar fractales enlosables en el código (para mapas de juego, pero eso es irrelevante ) He estado tratando de modificar el complemento Solid Noise incluido con GIMP (con mi comprensión extremadamente limitada de cómo el código funciona) pero no puedo hacer que el mío funcione correctamente.

Mi código modificado hasta ahora (Java)

Módulo de ruido sólido de GIMP en el que baso mi código (C)

Esto es lo que estoy tratando de lograr pero esto es lo que estoy obteniendo

Entonces, si alguien puede ver lo que he hecho mal, o tiene una sugerencia de cómo podría hacerlo de manera diferente, lo agradecería enormemente. Gracias por adelantado. Y si estoy pidiendo mucho o si es un gran fracaso en la vida, me disculpo.


intenta usar interpolación bicúbica en lugar de bilineal? No tengo idea si ese es tu problema, pero parece que es.
Stephen Furlani

Respuestas:


4

No sigo su código exactamente, pero aquí hay una descripción simplificada del algoritmo que logrará aproximadamente el efecto (según la imagen que publicó).

La siguiente explicación no es la versión súper optimizada, pero es una que es conceptualmente clara (espero). Una vez que lo tienes funcionando, puedes optimizarlo (de hecho, bastante drástico).

  1. Genere n capas de ruido aleatorio uniforme (solo píxeles aleatorios en escala de grises).
  2. Ahora muestree cada uno de estos muestreando cada 1, 2, 4, 8, ... 2 ^ (n-1) píxeles e interpolando los píxeles intermedios. Cada capa es más suave que la anterior.
  3. Ahora escala de estos con un factor de 1, 2, 4, 8, etc. Cada capa es más oscura que la anterior.
  4. Agregue todos estos juntos.
  5. Normalice dividiendo cada píxel con (1 + 2 + 4 + 8 + ... 2 ^ (n-1)).

El paso difícil es el paso de muestreo e interpolación. Supongamos que estamos en el salto de capa de muestreo cada m-ésimo píxel. Aquí está la idea básica para m> 1 (si m es 1, usamos la imagen como está):

for each pixel x and y
   left_sample_coord = m *(x / m) //(integer division, automatically truncated)
   right_sample_coord = (left_sample_point + m) % image_width
   top_sample_point = m*(y / m) 
   bottom_sample_coord = (top_sample_point + m) % image_height

   horizontal_weight = (x - left_sample_point) / (m - 1)
   vertical_weight = (y - top_sample_point) / (m - 1)

   sample_top_left = image(left_sample_coord, top_sample_point)
   //and the same for the other four corners

   //now combine the top two points
   top_interpolate = sample_top_left * horizontal_weight + sample_top_right * (1-horizontal_weight)

  //now combine the bottom two points
  bottom_interpolate = sample_bottom_left * horizontal_weight + sample_bottom_right * (1-horizontal_weight)

  //and combine these two last obtained values

  smooth_noise(x, y) = top_interpolate * vertical_weight  + bottom_interpolate * (1 - vertical_weight)

Algunos consejos:

  • El resultado del algoritmo anterior puede parecer un poco desvaído. Puede reducir este efecto mediante el uso de la misma capa de ruido para todas las capas, o mejorar el contraste de la imagen después.
  • El algoritmo anterior usa interpolación lineal, pero la interpolación de coseno (hacer una búsqueda) da resultados mucho mejores.
  • Haga posible mirar sus capas por separado durante todas las partes del algoritmo. Esto te ayudará a eliminar los errores rápidamente.

3

Parece que mi pastebin original expiró de alguna manera, así que no tengo forma de comparar mi código que no funciona, pero en mi juego actual revisé y traduje el código GIMP a Java nuevamente y parece que funciona bien ahora.

Si alguien planea usar este código, recomendaría modificar el constructor para modificar los parámetros de configuración (detalle y tamaño) para que pueda hacerlo funcionar como desee. EDITAR: Me di cuenta de que mi pregunta original era sobre hacerla enlosable, ¡así que recuerde establecer tilable en verdadero!

Código: http://pastebin.com/KsfZ99Xa

Ejemplo: ejemplo de generador perlin


2

Simplemente hojeé las versiones de Java y C y noté una ligera diferencia en la forma en que usas la función de ruido. Aquí está el tuyo:

int val = Math.abs((int) Math.floor(255.0 * noise(((double)col/(double)width), ((double)row/(double)height))));

Código C:

val = (guchar) floor (255.0 * noise ((col - xoffset) / width,

                                           (row - yoffset) / height));

¿Por qué has elegido no restar el desplazamiento? (col - xoffset) y (fila - yoffset)

Sólo me preguntaba. No tengo tiempo para hacer un análisis completo del código.

Espero que esto ayude.


xoffset y yoffset deben calcularse de la manera en que GIMP divide las imágenes en cuadrículas, pero mi programa funciona en un mosaico, por lo que el desplazamiento xey será 0
Nick Badal

2

No sé si podría ayudar, pero el siguiente truco me funcionó:

http://www.gamedev.net/blog/33/entry-2138456-seamless-noise/

Este compañero está utilizando una función de ruido 4d y simplemente proporciona valores xy de dos círculos como valores xyzw para el ruido 4d. El resultado es perfecto.

Aquí está la idea (simplificada) para una imagen 1000 * 1000:

for(i = 0;i < 1000; i++){

  for(j = 0; j < 1000; j++){

    nx = cos((i/1000) * 2 * PI);
    ny = cos((j/1000) * 2 * PI);
    nz = sin((i/1000) * 2 * PI);
    nw = sin((j/1000) * 2 * PI);

    looped_noise = noise_4D( nx, ny, nz, nw, octaves, persistence, lacunarity, blah...);
    noise_buffer[(i*1000)+j] = looped_noise;

  }
}

1

Le recomiendo que use el algoritmo de diamante cuadrado , también conocido como fractal de plasma o fractal de desplazamiento aleatorio de punto medio. Con este algoritmo es muy fácil restringir los bordes para que tengan los mismos valores. Cuando genere un valor para un borde, cópielo en el borde correspondiente en el otro lado. Esto produce un mapa perfectamente en mosaico.


0

Hay un gran artículo sobre la generación de ruido aquí . No es el ruido de Perlin como dice el artículo (en realidad es ruido rosa), pero sigue siendo increíblemente útil para entender cómo se generan las imágenes de ruido.

Entonces, para responder realmente a su pregunta: para hacer una imagen de ruido enlosable, solo necesita mantener la "capacidad de mosaico" durante toda la generación. Es decir, cuando el ruido se suaviza, lo suaviza como si se repitiera infinitamente en todas las direcciones: mosaico.


0

De la captura de pantalla, supongo que solo se están generando las capas "grandes", por lo que el ruido parece demasiado regular y carece de detalles.

Esto puede sonar estúpido, pero ¿trataste de aumentar la variable "detalle" (línea 16)? En su código, se establece en 1, lo que significa que el algoritmo solo generará dos capas de detalles antes de detenerse. Intenta aumentarlo a algo así como 8.


0

También debe echar un vistazo a Simplex Noise , que fue desarrollado por Ken Perlin para corregir algunas de las deficiencias del ruido de Perlin.

He estado trabajando en una implementación de Simplex Noise para un juego de C ++. Admite ruido de 1D / 2D / 3D / 4D de varias octavas. En este momento, la única textura incorporada es el mármol, pero podría agregar fácilmente más:

(http://code.google.com/p/battlestar-tux/source/browse/trunk/src/lib/procedural/)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.