O mundo confuso do barulho de Perlin

imagem

Qual é o ruído Perlin?


O ruído de Perlin foi inventado em 1983 por Ken Perlin (que recebeu um prêmio da Academia Americana de Artes e Ciências Cinematográficas por essa conquista). Veja bem, naqueles dias, todos estavam se esforçando para o fotorrealismo, mas sempre faltava. Ken Perlin inventou esse algoritmo de ruído para se livrar da aparência miserável de "computador" dos modelos 3D. O ruído é um gerador de números aleatórios em computação gráfica. Esse é um padrão aleatório não estruturado e é útil quando você precisa de uma fonte de peças detalhadas que faltam na estrutura óbvia 1 . O ruído Perlin é um algoritmo multidimensional usado na geração procedural, texturas, geração de elevação, geração de mapa, geração de superfície, geração de vértice, e assim por diante. A tabela abaixo 2 mostra os limites dos recursos de ruído perlin:

DimensãoRuído bruto (escala de cinza)Aplicação
1

Objetos de vetor olhando desenhados à mão
2
Objetos como texturas processuais e chamas
3
Ruído Perlin usado no relevo do Minecraft

Perlin deu a seguinte definição de ruído: o ruído é uma aproximação ao ruído branco, limitada a um intervalo de uma oitava 3 . A definição formal de ruído é a seguinte:

fN(y1,y2, cdots,yn;x1,x2, cdots,xn)=P(N(x1),N(x2), cdots,N(xn))


Onde N(x)- função de ruído. O ruído de Perlin é um ruído processual . “O adjetivo procedural é usado na ciência da computação para separar as entidades descritas pelo código do programa daquelas descritas pelas estruturas de dados.” 4 Ou seja, algo gerado , e não difícil. O que é bom usar ruído processual em vez de, por exemplo, criar ruído manualmente? O ruído processual é compacto , ou seja, ocupa menos espaço. É inextricável , isto é, aperiódico . É paramétrico , pode ser acessado aleatoriamente ; ele também tem muitas outras vantagens que simplificam a vida do artista ... Mas esse não é nosso objetivo final - servir o artista? Ontem, criei um plug-in para o After Effects, que pode ser visto na minha postagem anterior. Eu não levei em conta os interesses do artista nele, apenas os interesses do meu ego, então ninguém o baixou. Eu entendi a lição: sirva o artista, não a si mesmo.

Antes de Perlin, o barulho dos gradientes das grades apareceu. Eles foram gerados por interpolação entre valores aleatórios e, no ruído Perlin, uma rede cúbica é usada para cada vértice e, em seguida, é realizada a interpolação de spline . “Um gradiente pseudo-aleatório é obtido através do hash do ponto da rede e usando o resultado para selecionar o gradiente.” 5 Esses hashes se transformam em 12 vetores e são interpolados do centro para as bordas usando um polinômio de quinto grau. É difícil imaginar, certo? Não se preocupe. Vou mostrar isso nas imagens 6 e no pseudo-código 7 .


"... são interpolados do centro para as bordas usando um polinômio de quinto grau"

E aqui está o pseudocódigo clássico Perlin sem uma função hash:

// Function to linearly interpolate between a0 and a1 // Weight w should be in the range [0.0, 1.0] float lerp(float a0, float a1, float w) { return (1.0 - w)*a0 + w*a1; // as an alternative, this slightly faster equivalent formula can be used: // return a0 + w*(a1 - a0); } // Computes the dot product of the distance and gradient vectors. float dotGridGradient(int ix, int iy, float x, float y) { // Precomputed (or otherwise) gradient vectors at each grid node extern float Gradient[IYMAX][IXMAX][2]; // Compute the distance vector float dx = x - (float)ix; float dy = y - (float)iy; // Compute the dot-product return (dx*Gradient[iy][ix][0] + dy*Gradient[iy][ix][1]); } // Compute Perlin noise at coordinates x, y float perlin(float x, float y) { // Determine grid cell coordinates int x0 = int(x); int x1 = x0 + 1; int y0 = int(y); int y1 = y0 + 1; // Determine interpolation weights // Could also use higher order polynomial/s-curve here float sx = x - (float)x0; float sy = y - (float)y0; // Interpolate between grid point gradients float n0, n1, ix0, ix1, value; n0 = dotGridGradient(x0, y0, x, y); n1 = dotGridGradient(x1, y0, x, y); ix0 = lerp(n0, n1, sx); n0 = dotGridGradient(x0, y1, x, y); n1 = dotGridGradient(x1, y1, x, y); ix1 = lerp(n0, n1, sx); value = lerp(ix0, ix1, sy); return value; } 

Também vale a pena saber que “todas as funções de ruído, exceto o ruído Perlin e o ruído de convolução rarefeito, são aproximadamente do tipo tira. O ruído do Perlin é apenas de banda fraca, o que pode levar a problemas com distorção e perda de detalhes. ” 8 Além disso, o ruído Perlin não possui distribuição de amplitude gaussiana. Ou seja, os pontos de ruído não são espalhados com base em uma função gaussiana, o que não consideraremos neste artigo. Há muitas coisas em que Perlin está muito confortável, mas há coisas em que ele é muito fraco. Na tabela abaixo 9, você pode vê-lo.



Ruído Perlin na prática: implementações GLSL


Então, vamos falar sobre o ruído de Perlin no GLSL. O ruído Perlin pode ser usado como uma onda, como uma cor difusa, como material difuso, como luz trêmula ou como manchas em uma textura. Pessoalmente, eu o usei neste exemplo como uma cintilação de cores.


Enquanto escrevo este artigo, estou pensando em criar um plug-in para o After Effects que adiciona a funcionalidade de ruído Perlin.

O ruído mais simples da Perlin pode ser criado 10 da seguinte maneira:

 float rand(vec2 c){ return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453); } float noise(vec2 p, float freq ){ float unit = screenWidth/freq; vec2 ij = floor(p/unit); vec2 xy = mod(p,unit)/unit; //xy = 3.*xy*xy-2.*xy*xy*xy; xy = .5*(1.-cos(PI*xy)); float a = rand((ij+vec2(0.,0.))); float b = rand((ij+vec2(1.,0.))); float c = rand((ij+vec2(0.,1.))); float d = rand((ij+vec2(1.,1.))); float x1 = mix(a, b, xy.x); float x2 = mix(c, d, xy.x); return mix(x1, x2, xy.y); } float pNoise(vec2 p, int res){ float persistance = .5; float n = 0.; float normK = 0.; float f = 4.; float amp = 1.; int iCount = 0; for (int i = 0; i<50; i++){ n+=amp*noise(p, f); f*=2.; normK+=amp; amp*=persistance; if (iCount == res) break; iCount++; } float nf = n/normK; return nf*nf*nf*nf; } 


 #define M_PI 3.14159265358979323846 float rand(vec2 co){return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);} float rand (vec2 co, float l) {return rand(vec2(rand(co), l));} float rand (vec2 co, float l, float t) {return rand(vec2(rand(co, l), t));} float perlin(vec2 p, float dim, float time) { vec2 pos = floor(p * dim); vec2 posx = pos + vec2(1.0, 0.0); vec2 posy = pos + vec2(0.0, 1.0); vec2 posxy = pos + vec2(1.0); float c = rand(pos, dim, time); float cx = rand(posx, dim, time); float cy = rand(posy, dim, time); float cxy = rand(posxy, dim, time); vec2 d = fract(p * dim); d = -0.5 * cos(d * M_PI) + 0.5; float ccx = mix(c, cx, dx); float cycxy = mix(cy, cxy, dx); float center = mix(ccx, cycxy, dy); return center * 2.0 - 1.0; } // p must be normalized! float perlin(vec2 p, float dim) { /*vec2 pos = floor(p * dim); vec2 posx = pos + vec2(1.0, 0.0); vec2 posy = pos + vec2(0.0, 1.0); vec2 posxy = pos + vec2(1.0); // For exclusively black/white noise /*float c = step(rand(pos, dim), 0.5); float cx = step(rand(posx, dim), 0.5); float cy = step(rand(posy, dim), 0.5); float cxy = step(rand(posxy, dim), 0.5);*/ /*float c = rand(pos, dim); float cx = rand(posx, dim); float cy = rand(posy, dim); float cxy = rand(posxy, dim); vec2 d = fract(p * dim); d = -0.5 * cos(d * M_PI) + 0.5; float ccx = mix(c, cx, dx); float cycxy = mix(cy, cxy, dx); float center = mix(ccx, cycxy, dy); return center * 2.0 - 1.0;*/ return perlin(p, dim, 0.0); } 

No entanto, esta é uma versão refeita do ruído de Perlin, criada em 2002. Vá para Gist para ver como o ruído clássico de Perlin é realizado.

Bem, isso é tudo por hoje. Um post curto, eu sei, e falta conteúdo original, mas até agora fiquei sem ideias, porque ainda não li a renderização em tempo real . Este livro está cheio de conceitos e idéias para aprender e aprender. Eu a amo!


Paralelamente, estou lendo outro livro - Fundamentos de computação gráfica . Estou um pouco preso ao tópico das curvas implícitas, mas vou pedir ao meu parente com um PhD em matemática para me ajudar.


Referências


  • Uma Pesquisa de Funções de Ruído Processual, Fórum de Computação Gráfica, Volume 29 (2010), Número 8, pp 2379-2600
  • Ruído computacional eficiente, Journal of Graphics Tools Volume 16, Nº 2: 85-94

  1. A Survey, et al.
  2. flafla2.imtqy.com/2014/08/09/perlinnoise.html
  3. A. Lagaue e cols.
  4. A. Lagae e outros
  5. A. Lagae e outros
  6. From flafla2.imtqy.com/2014/08/09/perlinnoise.html
  7. Da Wikipedia
  8. A. Lagae e outros
  9. Adaptado de A. Lagae, et al.
  10. gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83

Source: https://habr.com/ru/post/pt441312/


All Articles