Pular para o conteúdo
Fundamento · Funções de formaIniciante

Curvas de forma

Curve uma rampa de 0 a 1 com pow, exp e abs para controlar como um valor sobe e desce.

Como funciona

Muitos valores num shader são uma rampa de 0 a 1: uma coordenada UV, uma distância remapeada, o progresso de uma animação, um produto escalar limitado aos positivos. Uma rampa reta raramente é o visual que você quer. Uma curva de forma é uma função que transforma uma entrada entre 0 e 1 numa saída entre 0 e 1, mas muda o que acontece no meio (a maioria mantém 0 no 0 e 1 no 1): assim um degradê pode se concentrar numa ponta, uma borda pode ficar mais nítida ou um pulso pode subir rápido e sumir devagar.

Para ver uma curva, desenhe o gráfico: acenda os pixels cuja altura está perto do valor da função no x deles.

float y = pow(uv.x, 2.0);                                // a curva a inspecionar
float line = 1.0 - smoothstep(0.0, 0.01, abs(uv.y - y)); // 1 perto da curva
vec3 color = mix(vec3(y), vec3(0.1, 0.9, 0.3), line);    // uma linha verde sobre a rampa

Potências

pow(x, k) entre 0 e 1 é o burro de carga. Com k acima de 1, a curva fica baixa e sobe tarde (um ease-in); com k abaixo de 1, ela sobe cedo e achata (um ease-out). 1.0 - pow(1.0 - x, k) espelha a curva e dá o ease-out que combina com o ease-in de pow(x, k). Um rim light de Fresnel eleva 1.0 - dot(n, v) a uma potência exatamente por isso: uma potência maior empurra o brilho para uma faixa mais fina na silhueta.

O pow é indefinido para base negativa, e para base zero com expoente zero ou menor. Limite a base antes, pow(max(x, 0.0), k), sempre que ela puder ficar abaixo de zero.

Exponenciais

exp(-k * x) começa em 1 e decai em direção a 0 sem nunca chegar lá: o formato da névoa que engrossa com a distância e de um brilho que some ao se afastar de uma forma. Um k maior decai mais rápido. Multiplicar um termo que sobe por um que desce dá um impulso que dispara e some devagar; x * exp(1.0 - x) chega ao pico exatamente em 1 quando x é 1.

Dobrando com abs

abs(x) dobra os valores negativos para cima e transforma uma rampa de -1 a 1 num V. 1.0 - abs(uv.x * 2.0 - 1.0) é uma tenda: 0 nas duas bordas e 1 no meio. Para uma versão arredondada, 4.0 * x * (1.0 - x) é uma parábola que vale 0 nas duas pontas e 1 em x = 0.5, um jeito barato de fazer algo aparecer e sumir ao longo de um intervalo de 0 a 1.

smoothstep como curva

smoothstep(0.0, 1.0, x) também é uma curva de forma: um S que suaviza a entrada e a saída (veja smoothstep). Passar a saída dele por ele mesmo deixa o S mais íngreme.

A graça está em combinar. Cada curva custa poucas instruções, e uma cadeia de duas ou três, como um remap, depois uma potência, depois um smoothstep, cobre a maior parte do que um shader precisa antes de recorrer a uma textura de consulta. Desenhe o gráfico de cada elo enquanto monta a cadeia.

Leitura complementar