Conteúdo principal
Programação
Curso: Programação > Unidade 5
Lição 3: RuídoRuí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.
Por outro lado, o gráfico a seguir mostra números puramente aleatórios no decorrer do tempo.
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:Tempo | Valor do ruído |
---|---|
0 | 0.469 |
0.01 | 0.480 |
0.02 | 0.492 |
0.03 | 0.505 |
0.04 | 0.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.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.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.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.