Noções básicas sobre o ruído Perlin

31

Estou brincando com o Perlin Noise depois de algum trabalho com a Diamond Square. Segui a implementação de Hugo Elias que, basicamente, faz uma série de funções com x, y como entrada para lançar cada valor de coordenada.

Meu código PHP está aqui :

Eu tenho duas perguntas:

Como uso o algoritmo para gerar um mapa de altura em uma matriz? Eu não o entendi completamente e apenas mudei para o pseudocódigo do PHP, mas fiz a última função (map_perlined) depois de ler em algum lugar que o algoritmo "magicamente" fornece valores de transição para cada ponto x, y dado (aparentemente, sem precisar ler seu valores adjacentes), eu apenas recebo isso ao usar como função aleatóriamt_rand(-100,100)/100;

insira a descrição da imagem aqui

E isso ao usar o criptográfico: 1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0;(que, BTW, pode ser implementado "como está" no PHP?):

insira a descrição da imagem aqui

Então, resumindo, três perguntas:

  1. Meu código está correto?
  2. A função aleatória pode ser portada para PHP, conforme descrito no código? Não gera erros, mas os resultados não estão lá.
  3. Como eu realmente uso o algoritmo?

ATUALIZAR

Ok, criou uma porta PHP do código mostrado no artigo de Gustavson e, como outro codificador disse, apenas gera uma oitava. Existe algum outro site / documento / guia útil sobre como usar isso com os conceitos de múltiplas oitavas, amplitude, frequência etc. para controlar a função de ruído? No artigo de Gustavson, apenas mostra os resultados, não a implementação real do algoritmo, talvez esteja faltando alguma coisa?

ATUALIZAÇÃO 2
@NATHAN

Eu fiz algo como:

$persistence = 0.5;

for ($j = 0; $j < $size; $j++) {
    for ($i = 0; $i < $size; $i++) {

        for ($o = 0; $o < 8; $o++) {
            $frequency = pow(2,$o);
            $amplitude = pow($persistence, $o);
            $value += SimplexNoise($i*$frequency, $j * $frequency) * $amplitude;
            }

            //$value = SimplexNoise($i, $j) + 0.5 * SimplexNoise($i, $j) + 0.25 * SimplexNoise($i, $j);
            $this->mapArray[$i][$j] = new Cell($value);

E depois de normalizar os valores para 0..1, recebo um mapa de altura bastante monótono, como:

insira a descrição da imagem aqui

Como proponho o mapa? Talvez o que eu preciso implementar seja a versão 3D com o terceiro valor, uma altura aleatória? Mas, nesse caso, eu precisaria descobrir os valores dos vizinhos, que terminariam com algo como um algoritmo de diamante quadrado, exatamente o que não quero fazer.

ATUALIZAÇÃO 3

Mais trabalho de Perlin. Ainda não encontrei uma maneira de orientar o ruído para meus resultados. Verifique estas oitavas e o resultado final:

Oitava I a IV

Octave1Octave2Octave3Octave4

Resumido

As oitavas 1-4 somadas

Cada oitava é praticamente a mesma. Verifique o código:

$persistence = 0.5;

    for ($j = 0; $j < $size; $j++) {
      for ($i = 0; $i < $size; $i++) {
        $value = 0;

        for ($o = 0; $o < 4; $o++) {
          $frequency = pow(2,$o);
          $amplitude = pow($persistence, $o);
          $value += improved_noise($i*$frequency, $j*$frequency, 0.5)*$amplitude;

        }
        $this->map[$i][$j] = new Cell($value);

Os resultados são normalizados. O que você usaria tem uma forte influência no desenvolvimento do ruído? Vejo exemplos em que a alteração da amplitude fornece superfícies suaves ou ásperas, mas mesmo se eu der uma enorme amplitude, vejo pouca diferença.

Gabriel A. Zorrilla
fonte
Basta adicionar várias instâncias, aumentando a frequência e diminuindo a amplitude de cada vez, como: perlin (x) + 0,5 * perlin (2 * x) + 0,25 * perlin (4 * x) + ... (para quantas oitavas quanto você quer). Você também pode tentar alterar os fatores para obter uma aparência diferente; eles não precisam ser potências de 2.
Nathan Reed
1
Após a atualização, parece que você não está redimensionando o Y corretamente - estou cansado demais para inserir o PHP (como não conheço o PHP); mas encontrei um problema semelhante na minha língua materna ao implementar o perlin pela primeira vez. Também mate as oitavas e depure apenas um nível de perlin.
101311 Jonathan Dickinson
Alguém para a minha atualização III?
Gabriel A. Zorrilla

Respostas:

28

O que você implementou não é o ruído Perlin. Não sei por que Hugo Elias diz que é, mas ele está confuso. Aqui está a implementação de referência de Ken Perlin. Na verdade, ele não chama nenhum gerador externo de números aleatórios, mas usa uma função de hash embutida para produzir os vetores de gradiente pseudo-aleatórios.

Observe também que o ruído Perlin consiste em apenas uma oitava. Resumir várias oitavas (instâncias em escala da função de ruído), como sugere Hugo Elias, é uma técnica útil, mas não faz parte do ruído da Perlin. O que você consegue com isso é chamado de ruído fractal, às vezes "ruído browniano fractal" (devido à suposta semelhança com o movimento browniano).

Se você quiser entender geometricamente o que o algoritmo está fazendo, tente este documento . Trata-se de um tipo diferente de ruído chamado "ruído simplex", mas também inclui uma explicação do ruído Perlin clássico. Aliás, o ruído simplex também foi inventado por Perlin e deve ser uma melhoria em relação ao ruído clássico, portanto, você pode tentar implementá-lo também se estiver interessado em tocar com funções de ruído.

Nathan Reed
fonte
2
+1 para o artigo de Gustavson. Explica o ruído perlin e simplex da maneira mais clara que vi até agora. Regras de ruído obviamente simples!
FxIII 10/10
Também encontrei esse jornal há algum tempo, mas o de Hugo parecia mais simples. Vou ler e tentar! Obrigado!
Gabriel A. Zorrilla 10/10
2
ter cuidado ao baixar ruído simplex, ele pode ter um vírus;)
bobobobo
Sei que esse é um tópico antigo, mas dizer que a implementação de referência não usa um número aleatório está incorreto. Quando a biblioteca é inicializada (ou a primeira vez que uma função de ruído é chamada), são gerados 256 gradientes aleatórios. O hash a que você se refere é apenas coagir o conjunto infinito de números inteiros no intervalo [0, 255] que é armazenado em cache. Essencialmente, essa é apenas uma otimização da tabela de consulta, e o algoritmo funciona tão bem se, por exemplo, você semeia um PRNG com uma coordenada de grade e a usa para gerar o gradiente, é (muito) mais lento dessa maneira.
Bcrist
@ Cris Eu acho que você está se referindo a uma versão mais antiga do ruído Perlin. O "ruído aprimorado" de Perlin, ao qual vinculei , usa um conjunto fixo de 12 vetores de gradiente, e não 256 vetores aleatórios. Ele usa uma tabela de permutação como uma função hash para mapear as coordenadas da grade para um desses 12 vetores de gradiente.
Nathan Reed
11

Esse é um equívoco comum. O que Hugo Elias chama de ruído "Perlin" é, na verdade, ruído fractal ou rosa. Para entender melhor o que é o ruído Perlin, você pode ler o artigo de Perlin, vinculado na resposta de Nathan Reed, ou documentos libnoise (existe o mesmo erro: o ruído Perlin é o que eles chamam de ruído Gradiente) ou documentos CoherentNoise .

Agora, para realmente responder à sua pergunta: você não obteve o resultado esperado porque a frequência do ruído é muito alta. Suas frequências começam com 1 e aumentam, o que significa que cada pixel no mapa resultante tem um valor aleatório. Para ver a estrutura mais fina do mapa, você precisa "aumentar o zoom" no ruído. Eu realmente não falo PHP, mas acho que o código deve ficar assim:

$arrayMap[$i][$j] = PerlinNoise_2D($i/$width, $j/$height, $p, $octaves);

Ou seja, você "estica" um período de ruído por todo o mapa. Obviamente, você pode usar outros coeficientes - tente diferentes, veja o que acontece.

deixa pra lá
fonte
Obrigado pelos documentos de ruído coerentes! Vejo que você escreveu :) Qual é o erro nos documentos libnoise? O ruído Perlin não é um tipo de ruído gradiente?
legends2k 31/07