Como crio ruído sólido inclinável para geração de mapas?


16

Ei, pessoal, estou tentando descobrir como gerar fractais inclináveis ​​no código (para mapas de jogos, mas isso é irrelevante ). Estou tentando modificar o plug-in Solid Noise, fornecido com o GIMP (com meu entendimento extremamente limitado de como o código funciona) mas não consigo fazer o meu funcionar corretamente.

Meu código modificado até agora (Java)

Módulo de ruído sólido do GIMP do qual estou baseando meu código (C)

Aqui está o que estou tentando alcançar, mas é isso que estou recebendo

Portanto, se alguém puder ver o que eu fiz de errado, ou tiver uma sugestão de como eu poderia fazê-lo de maneira diferente, eu apreciaria muito. Desde já, obrigado. E se estou pedindo muito ou apenas um enorme fracasso na vida, peço desculpas.


tente usar interpolação bicúbica em vez de bilinear? Não tenho idéia se esse é o seu problema, mas parece que é.
Stephen Furlani

Respostas:


4

Não sigo exatamente o seu código, mas aqui está uma descrição simplificada do algoritmo que atingirá aproximadamente o efeito (com base na imagem que você postou).

A explicação a seguir não é a versão super otimizada, mas é conceitualmente clara (espero). Depois de executá-lo, você pode otimizá-lo (drasticamente, de fato).

  1. Gere n camadas de ruído aleatório uniforme (apenas pixels em escala de cinza aleatórios).
  2. Agora experimente cada um deles, amostrando todos os 1, 2, 4, 8, ... 2 ^ (n-1) pixels e interpolando os pixels intermediários. Cada camada é mais lisa que a anterior.
  3. Agora dimensione-os com um fator de 1, 2, 4, 8, etc. Cada camada é mais escura que a anterior.
  4. Adicione tudo isso junto.
  5. Normalize dividindo cada pixel com (1 + 2 + 4 + 8 + ... 2 ^ (n-1)).

O passo difícil é o passo de amostragem e interpolação. Suponha que estamos na camada pulando a amostragem de cada m-ésimo pixel. Aqui está a idéia básica para m> 1 (se m for 1, usamos a imagem 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)

Algumas dicas:

  • O resultado do algoritmo acima pode parecer um pouco desbotado. Você pode reduzir esse efeito usando a mesma camada de ruído para todas as camadas ou melhorar a imagem posteriormente.
  • O algoritmo acima usa interpolação linear, mas a interpolação de cosseno (faça uma pesquisa) fornece resultados muito melhores.
  • Torne possível observar suas camadas separadamente durante todas as partes do algoritmo. Isso ajudará você a eliminar os bugs rapidamente.

3

Parece que minha pastabin original expirou de alguma forma, então não tenho como comparar meu código não útil, mas no meu jogo atual eu passei e traduzi o código GIMP em java novamente e parece funcionar bem agora.

Se alguém planeja usar esse código, eu recomendo modificar o construtor para modificar os parâmetros de configuração (detalhes e tamanho) para que você possa fazer o que quiser. EDIT: Percebi que minha pergunta original era sobre torná-lo inclinável, então lembre-se de defini-lo como verdadeiro!

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

Exemplo: exemplo de gerador perlin


2

Apenas percorri as versões Java e C e percebi uma pequena diferença na maneira como você usa a função de ruído. Aqui está o seu:

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 que você optou por não subtrair o deslocamento? (col - xoffset) e (linha - yoffset)

Apenas me perguntando. Não tenho tempo para fazer uma análise completa do código.

Espero que isto ajude.


xoffset e yoffset são para calcular no caminho divide GIMP imagens em grades, mas o meu programa de todos os trabalhos sobre uma telha assim deslocamentos X e Y seria 0
Nick Badal

2

Não sei se poderia ajudar, mas o seguinte truque funcionou para mim:

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

Esse sujeito está usando uma função de ruído 4d e simplesmente fornece valores xy de dois círculos como valores xyzw para o ruído 4d. O resultado é um loop perfeito.

Aqui está a idéia (simplificada) para uma imagem de 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

Eu recomendo que você use o algoritmo diamante-quadrado , também conhecido como fractal de plasma ou fractal de deslocamento aleatório no ponto médio. Usando esse algoritmo, é muito fácil restringir as arestas para que tenham os mesmos valores. Ao gerar um valor para uma aresta, copie-o para a aresta correspondente do outro lado. Isso produz um mapa perfeitamente lado a lado.


0

Há um ótimo artigo sobre geração de ruído aqui . Não é ruído Perlin, como afirma o artigo (na verdade é ruído rosa), mas ainda é incrivelmente útil entender como as imagens de ruído são geradas.

Portanto, para realmente responder à sua pergunta: para criar uma imagem de ruído inclinável, você só precisa manter a "tileabilidade" durante toda a geração. Ou seja, quando o ruído é suavizado, você o suaviza como se fosse repetido infinitamente em todas as direções - lado a lado.


0

A partir da captura de tela, meu palpite é que apenas as camadas "grandes" estão sendo geradas, razão pela qual o ruído parece muito regular e carece de detalhes.

Isso pode parecer estúpido, mas você tentou aumentar a variável "detalhe" (linha 16)? No seu código, ele é definido como 1, o que significa que o algoritmo gera apenas duas camadas de detalhes antes de parar. Tente aumentá-lo para algo como 8.


0

Você também deve dar uma olhada no Simplex Noise , desenvolvido por Ken Perlin para corrigir algumas das deficiências do ruído da Perlin.

Eu tenho trabalhado em uma implementação do Simplex Noise para um jogo em C ++. Ele suporta ruído 1D / 2D / 3D / 4D de várias oitavas. No momento, a única textura interna é o mármore, mas você pode adicionar mais facilmente:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.