Pular para o conteúdo
Fundamento · Matemática de corIniciante

Paletas e rampas

Transforme um valor de 0 a 1 numa cor com rampas de várias paradas, paletas de cosseno ou uma textura de faixa de gradiente.

Como funciona

A maioria dos shaders calcula primeiro um único número, uma distância, um valor de ruído, uma altura, um produto escalar, e só depois decide que cor ele deve ter. Uma paleta é esse último passo: uma função de um valor t entre 0 e 1 para uma cor. Mantê-la separada permite recolorir um mesmo padrão de uma dúzia de jeitos, e as escolhas de cor ficam num lugar só.

Duas paradas e mais

A menor paleta é um mix entre duas cores. Para mais paradas, divida o intervalo de 0 a 1 em trechos e misture dentro de cada um. Três paradas pedem uma escolha:

vec3 ramp3(vec3 a, vec3 b, vec3 c, float t) {
    return t < 0.5 ? mix(a, b, t * 2.0) : mix(b, c, t * 2.0 - 1.0);
}

Qualquer número de paradas igualmente espaçadas cabe num array. Escale t pelo número de trechos, use a parte inteira como o trecho e a parte fracionária como a posição dentro dele:

const vec3 STOPS[4] = vec3[4](
    vec3(0.02, 0.01, 0.05),  // noite
    vec3(0.45, 0.05, 0.20),  // ameixa
    vec3(0.95, 0.40, 0.10),  // brasa
    vec3(1.00, 0.90, 0.60)); // chama

vec3 ramp(float t) {
    float x = clamp(t, 0.0, 1.0) * 3.0;   // 3 trechos entre 4 paradas
    int i = int(min(floor(x), 2.0));       // o último trecho inclui t = 1
    return mix(STOPS[i], STOPS[i + 1], x - float(i));
}

Troque o mix por um smoothstep da posição para suavizar as quinas onde os trechos se encontram, ou por um step para ter faixas chapadas, um visual posterizado barato.

Paletas de cosseno

Uma paleta de cosseno, forma popularizada por Inigo Quilez, descreve um esquema de cores inteiro com quatro parâmetros vec3 e nenhuma parada. Cada canal segue a própria onda de cosseno ao longo de t:

vec3 cosinePalette(float t, vec3 offset, vec3 amp, vec3 freq, vec3 phase) {
    return offset + amp * cos(6.2831853 * (freq * t + phase));
}

Leia os parâmetros por canal, como uma onda da página de funções periódicas: offset é o centro em volta do qual o canal oscila, amp o quanto ele oscila, freq quantos ciclos ele faz enquanto t vai de 0 a 1, e phase em que ponto do ciclo ele começa. Dar valores diferentes aos três canais é o que produz os matizes; com os mesmos quatro valores em todos os canais eles andam juntos e o resultado continua cinza.

// uma rampa de pôr do sol: do vermelho escuro ao laranja e ao amarelo claro
vec3 sunset = cosinePalette(t, vec3(0.70, 0.485, 0.325), vec3(0.30, 0.465, 0.275),
                               vec3(0.5), vec3(0.50, 0.45, 0.40));

Mantenha offset ± amp dentro de 0–1 em todos os canais e a paleta nunca corta. Como as ondas se repetem, t pode passar de 1: passe uma distância ou um t + time * 0.1 rolando e as cores circulam suavemente para sempre. Uma paleta com freq igual a 1 em todos os canais fecha o ciclo sem emenda a cada unidade de t.

Faixas de gradiente

Quando um artista já pintou o gradiente, guarde-o numa textura de um texel de altura e leia com t como coordenada horizontal:

// no escopo do arquivo:
uniform sampler2D uRamp; // N×1 texels, clamp to edge
// dentro de main():
vec3 color = texture(uRamp, vec2(t, 0.5)).rgb;

A filtragem linear mistura os texels, e a filtragem nearest dá faixas duras, o que combina com paletas de pixel art. O clamp to edge impede que as duas pontas se misturem uma com a outra. Com filtragem linear, o primeiro e o último meio texel ficam chapados; para espalhar as paradas por igual de uma ponta à outra, leia em (t * (N - 1.0) + 0.5) / N. Uma faixa custa uma leitura de textura, mas guarda qualquer curva, e uma textura mais alta pode guardar várias paletas, uma por linha, escolhida por uma segunda coordenada.

Quais valores escolher

As cores de uma paleta costumam ser escolhidas no olho, como num programa de pintura, então são valores sRGB codificados. Num shader que trabalha com valores lineares, converta-as antes de usar (a página de gama mostra como), senão todas as cores da rampa, inclusive as pontas, saem mais claras e lavadas que as escolhidas. Os cards deste site fazem isso com os controles de cor. Misturar em OKLab em vez de RGB mantém o brilho de uma rampa uniforme ao longo dela; a página de espaços de cor mostra essa conversão.

Leitura complementar