If you're seeing this message, it means we're having trouble loading external resources on our website.

Se você está atrás de um filtro da Web, certifique-se que os domínios *.kastatic.org e *.kasandbox.org estão desbloqueados.

Conteúdo principal

Ruído de Perlin

Um bom gerador de números aleatórios produz números que não têm nenhuma relação entre si e não mostram nenhum padrão discernível. Como estamos começando a ver, um pouco de aleatoriedade pode ser uma coisa boa ao programar comportamentos orgânicos, semelhantes aos encontrados na vida real. No entanto, a aleatoriedade como o único princípio orientador não é necessariamente natural.
Há um algoritmo que gera resultados mais naturais, e que é conhecido como "ruído de Perlin". Ken Perlin desenvolveu a função de ruído enquanto trabalhava no filme Tron original, no início dos anos 1980. Ele usou a função para criar texturas procedurais para efeitos gerados por computador. Em 1997, Perlin ganhou um prêmio de realização técnica pela realização desse trabalho. O ruído de Perlin pode ser usado para gerar vários efeitos com qualidades naturais, tais como nuvens, paisagens e texturas como mármore.
Ele tem uma aparência mais orgânica porque produz uma sequência naturalmente ordenada (“suave”) de números pseudoaleatórios. O gráfico abaixo mostra o ruído de Perlin no decorrer de um determinado tempo, sendo que o eixo x representa o tempo. Observe a suavidade da curva.
Imagem da Natureza do Código
Figura I.5: Ruído
Por outro lado, o gráfico a seguir mostra números puramente aleatórios no decorrer do tempo.
Imagem da Natureza do Código
Figura I.6: Aleatório
A ProcessingJS tem uma implementação interna do algoritmo do ruído de Perlin: a função noise(). A função noise() conta com um, dois ou três argumentos, já que o ruído é calculado em uma, duas ou três dimensões. Vamos começar analisando um ruído unidimensional.

Detalhe do ruído

A referência do ruído nos diz que o ruído é calculado sobre diversas “oitavas.” Chamando a função noiseDetail() irá mudar o número de oitavas e a sua importância relativa de uma para a outra. E isso muda o comportamento da função do ruído.
Considere desenhar um circulo em nossa janela de ProcessingJS em um local aleatório x:
var x = random(0, width);
ellipse(x, 180, 16, 16);
Agora, ao invés de uma posição x aleatória, queremos uma posição x do ruído de Perlin que seja “mais suave.” Você pode pensar que tudo o que precisa fazer é substituir random() por noise(), isto é:
var x = noise(0, width);
ellipse(x, 180, 16, 16);
Embora, de um modo conceitual, isso seja exatamente o que queremos fazer &mdash ;calcular um valor x que varie entre 0 e a largura, de acordo com o ruído de Perlin — essa não é a implementação correta. Embora os argumentos da função random() especifiquem um intervalo de valores entre um mínimo e um máximo, noise() não funciona assim. Em vez disso, noise() espera que passemos um argumento que signifique um "momento no tempo," e que sempre retorne um valor entre 0 e 1.  Podemos pensar em um ruído de Perlin unidimensional como uma sequência linear de valores no decorrer do tempo. Veja aqui exemplos de valores de entrada e de retorno:
TempoValor do ruído
00.469
0.010.480
0.020.492
0.030.505
0.040.517
Agora, para acessar um desses valores de ruído em ProcessingJS, precisamos passar um momento específico no tempo para a função noise(). Por exemplo:
var n = noise(0,03);
De acordo com a tabela acima, noise() vai retornar 0.505 no tempo de 0.03. Podemos escrever um programa que armazena uma variável de tempo e solicita o valor do ruído continuamente em draw ().
Os resultados do código acima com o mesmo valor impresso várias vezes. Isso acontece porque estamos pedindo o resultado da função noise() várias vezes, no mesmo ponto no tempo.
Contudo, se pudermos incrementar a variável de tempo t , vamos obter um resultado diferente.
A taxa com a qual podemos incrementar t também afeta a suavidade do ruído. Se fizermos grandes saltos no tempo, os valores serão mais aleatórios.
Ruído ao longo do tempo
Figura 1.7
Tente executar o código acima diversas vezes, incrementando t em 0,01; 0,02; 0,05; 0,1; 0,0001, e assim você verá resultados diferentes.

Mapeando o ruído

Agora estamos prontos para responder à questão: o que fazer com o valor do ruído? Assim que tivermos o valor com um intervalo entre 0 e 1, cabe a nós mapear esse intervalo para o que quisermos.
Só poderíamos multiplicar pelo número máximo no intervalo, mas essa também é uma boa oportunidade para introduzir a função map() existente em ProcessingJS, que vai nos ajudar em situações mais adiante. A função map() recebe cinco argumentos. O primeiro é o valor que desejamos mapear, neste caso, n . Então temos que inserior o intervalo atual do valor (mínimo e máximo), seguido por nosso intervalo desejado.
Imagem da Natureza do Código
Figura I.8
Neste caso, sabemos que o ruído tem um intervalo entre 0 e 1, mas gostaríamos de desenhar um retângulo com uma largura entre 0 e a largura atual.
Podemos aplicar exatamente a mesma lógica ao nosso pedestre aleatório e atribuir os valores de x e de y, de acordo com o ruído de Perlin.
Observe como o exemplo acima pede um par adicional de variáveis: tx e ty. Isso acontece porque precisamos manter o controle de duas variáveis de tempo, uma para a localização de x de Walker e uma para a localização de y.
Mas existe algo um pouco estranho em relação a essas variáveis. Por que tx começa em 0 e ty começa em 10.000? Embora esses números sejam escolhas arbitrárias, inicializamos de forma muito específica nossas duas variáveis de tempo com valores diferentes. Isso porque a função de ruído é determinística: ela tem o mesmo resultado para cada tempo t específico todas as vezes. Se pedíssemos os valores do ruído no mesmo t tanto para x como para y, então x e y seriam sempre iguais, o que significa que o objeto Walker só moveria na diagonal . Em vez disso, simplesmente usamos duas partes diferentes do espaço do ruído, começando em 0 para x e em 10.000 para y , de forma que x e y pareçam agir de forma independente uma da outra.
Imagem da Natureza do Código
Figura I.9
Na verdade, não há um conceito real de tempo em jogo. É uma metáfora útil para nos ajudar a entender como a função de ruído funciona, mas o que temos na verdade é o espaço, e não o tempo. O gráfico acima representa uma sequência linear de valores de ruído em um espaço unidimensional, e podemos pedir um valor em uma posição x específica sempre que quisermos. Nos exemplos, você frequentemente verá uma variável chamada xoff para indicar o deslocamento em x ao longo do gráfico de ruído, ao invés de t para tempo (conforme observado no diagrama).
No próximo desafio, você vai tentar usar o ruído com o Walker de uma maneira um pouco diferente. Divirta-se!

Este curso "Natural Simulations" é um derivado do "The Nature of Code" por Daniel Shiffman, usado sob a Creative Commons Attribution-NonCommercial 3.0 Unported License.

Quer participar da conversa?

Nenhuma postagem por enquanto.
Você entende inglês? Clique aqui para ver mais debates na versão em inglês do site da Khan Academy.