Pular para o conteúdo
Fundamento · TempoIniciante

Funções periódicas

Ondas senoidais, triangulares, dente de serra e quadradas, e os três controles que toda onda tem, frequência, amplitude e fase.

Como funciona

Uma função periódica se repete: depois de um período, a saída recomeça. Alimentada com o tempo, ela faz as coisas pulsarem, balançarem, piscarem e orbitarem para sempre. Alimentada com uma coordenada, ela faz listras, anéis e ondulações. As mesmas poucas ondas cobrem os dois casos, e todas respondem aos mesmos três controles.

sin e cos

sin(x) oscila suavemente entre -1 e 1 e se repete a cada 2π (cerca de 6.283). cos(x) é a mesma onda um quarto de período adiantada, então vec2(cos(a), sin(a)) anda em círculo enquanto a cresce. A forma comum escala a entrada para que uma unidade signifique um ciclo completo:

const float TAU = 6.2831853;           // 2π: um ciclo completo
float wave  = sin(TAU * (freq * x + phase)) * amp; // -amp..amp
float pulse = sin(TAU * time) * 0.5 + 0.5;         // 0..1, uma vez por segundo
  • Frequência é quantos ciclos cabem em uma unidade de x. Com o tempo como x, são ciclos por segundo (hertz); com uma coordenada UV, ciclos ao longo da superfície.
  • Amplitude é o quanto a onda oscila para cada lado do centro. Some um deslocamento para mover o centro.
  • Fase desloca a onda ao longo de x, em frações de ciclo. Uma fase de 0.25 faz um seno começar no pico.

* 0.5 + 0.5 leva uma onda de -1..1 para 0..1, o intervalo que cores e máscaras querem.

Ondas que viajam

Ponha espaço e tempo na mesma onda e ela anda. sin(TAU * (4.0 * uv.x - time)) tem quatro cristas ao longo da superfície e as desliza em direção a +x a um quarto da superfície por segundo, um ciclo por segundo. Com + time elas vão para o outro lado; trocando uv.x pela distância até um ponto, saem anéis que se espalham, o começo de toda ondulação.

Dente de serra, triangular, quadrada

O fract da página de fract e mod já é uma onda, o dente de serra: sobe de 0 a 1 e cai de volta. As outras formas clássicas saem dele:

float saw      = fract(x);                       // sobe e cai: /|/|/|
float triangle = 1.0 - abs(fract(x) * 2.0 - 1.0); // sobe e desce: /\/\/\, 0..1
float square   = step(0.5, fract(x));            // metade apagada, metade acesa
float pulseW   = step(1.0 - width, fract(x));     // acesa numa fração "width" de cada período

Todas aceitam a mesma frequência e fase de um seno: fract(freq * x + phase). A triangular é o vaivém de aparência suave mais barato, a quadrada pisca, e o dente de serra é um progresso que se repete, a forma para alimentar uma curva de easing ou uma paleta quando algo deve tocar de novo e de novo.

Moldando uma onda

As ondas se combinam com as curvas da página de curvas de modelagem. pow(sin(...) * 0.5 + 0.5, 8.0) transforma um seno em picos curtos com longas pausas entre eles, um batimento cardíaco. smoothstep(0.4, 0.6, triangle) é uma onda quadrada cujas bordas viram rampas em vez de saltos. Somar senos de frequências sem relação entre si, como 1.0, 2.3 e 3.7, dá um movimento que demora a se repetir e parece orgânico, o truque de sempre para chamas tremulando, grama balançando e objetos flutuando parados.

Dois cuidados

Ondas de borda dura sofrem aliasing. Uma quadrada ou um dente de serra desenhado no espaço tem um salto instantâneo, e um pixel pode cair de qualquer lado dele; listras finas viram um ruído que rasteja. Suavize a borda para mais ou menos um pixel de largura, o que a página de derivadas automatiza. E argumentos grandes perdem exatidão: as GPUs calculam sin bem perto de 0, mas muitas vezes mal em milhares de radianos. Quando x pode crescer muito, como o tempo vezes uma frequência alta, dê a volta antes: sin(TAU * fract(freq * time)) só pede ângulos entre 0 e 2π. O valor repetido continua tão preciso quanto o próprio time, assunto da página de tempo.

Leitura complementar