7. Perlin noise por dentro (opcional)
Cinco passos para transformar uma coordenada (x, y) em um número entre −1 e 1.
A imagem para ter em mente. Os pontos pretos são estacas fincadas no chão. A seta vermelha de cada estaca diz "o terreno sobe para cá". Você está no ponto laranja. Cada uma das quatro estacas ao redor dá uma opinião sobre a sua altura: se você andou da estaca até aqui na direção da seta, "subiu"; contra, "desceu"; de lado, "ficou no nível". A altura final é a média das quatro opiniões, com a estaca mais próxima pesando mais.
Mova o mouse sobre a grade (ou clique para fixar um ponto). Use os botões de passo para revelar o cálculo aos poucos. A grade tem nós em coordenadas inteiras; cada nó guarda um vetor gradiente pseudo-aleatório (setas vermelhas), escolhido pela semente.
Quem é quem no painel
| Nome | O que é | Na imagem das estacas |
|---|---|---|
P | o ponto (x, y) | onde você está |
x0, y0 / fx, fy | canto inferior esquerdo da célula / posição dentro dela (0 a 1) | a estaca de trás / quanto você andou desde ela |
g00 … g11 | gradiente de cada canto (primeiro dígito é x, segundo é y) | a seta de cada estaca |
d00 … d11 | vetor do canto até P | o caminho que você andou saindo daquela estaca |
n00 … n11 | produto escalar g · d | a opinião de cada estaca: positivo subiu, negativo desceu |
u, v | fade(fx), fade(fy) | os pesos suavizados da média |
nx0, nx1 | média da fileira de baixo e da de cima | opinião de cada fileira |
n | média das duas fileiras; ×√2 para caber em −1..1 | a altura do chão sob seus pés |
A curva S: por que não interpolar linearmente
peso
u = curva(fx) em função de fxCom peso linear, o valor é contínuo mas a derivada salta ao cruzar um nó: aparecem "quinas" e a imagem mostra a grade. Smoothstep zera a primeira derivada nos nós; o fade de 2002 zera também a segunda. Troque a curva no seletor e olhe o fundo da grade: com linear, dá pra ver os quadrados.
Marcador laranja: o fx do ponto atual.
O algoritmo em 12 linhas
function perlin2(x, y):
x0 = floor(x); y0 = floor(y); x1 = x0+1; y1 = y0+1
fx = x - x0; fy = y - y0 // posição dentro da célula, 0..1
g00 = gradiente(x0,y0); g10 = gradiente(x1,y0) // 1. vetor pseudo-aleatório por canto
g01 = gradiente(x0,y1); g11 = gradiente(x1,y1) // (tabela de permutação + semente)
n00 = dot(g00, [fx, fy ]); n10 = dot(g10, [fx-1, fy ]) // 2-3. distância canto→ponto
n01 = dot(g01, [fx, fy-1]); n11 = dot(g11, [fx-1, fy-1]) // e produto escalar
u = fade(fx); v = fade(fy) // 4. curva S nos pesos
return lerp( lerp(n00, n10, u), // 5. interpolação bilinear
lerp(n01, n11, u), v )
Por que gradiente e não valor? No value noise o valor no nó é o próprio número sorteado, então todo máximo e todo mínimo cai em um nó, e o olho percebe a grade.
No Perlin, o valor em todo nó é exatamente zero (distância zero, produto escalar zero) e o que varia é a inclinação. O resultado tem mais "movimento" e menos alinhamento com a grade.
Consequência importante: se você amostrar Perlin só em coordenadas inteiras (por exemplo
PerlinNoise(x, y) com x e y inteiros de um grid), todos os valores serão iguais. Sempre multiplique por uma escala fracionária. Isso é visto na demo 2.