UV e proporção de tela
Transforme a posição de um pixel em coordenadas de 0 a 1, centralize-as e mantenha os círculos redondos.
Como funciona
Um fragment shaderO programa da GPU que roda uma vez para cada pixel coberto por um triângulo e decide a cor dele. Shader de fragmento O programa da GPU que roda uma vez para cada pixel coberto por um triângulo e decide a cor dele.gl_FragCoord, a posição do pixel na janela, em pixels:
gl_FragCoord.xy vale (0.5, 0.5) no centro do pixel do canto inferior esquerdo e cresce em direção ao canto superior
direito. Só que pixel é uma unidade incômoda: um shader escrito nela fica diferente em cada tamanho de tela.
Dividir pelo tamanho do canvas resolve isso. O resultado é a coordenada UV: 0 nas bordas esquerda e inferior, 1 nas bordas direita e superior, seja qual for a resolução.
// no escopo do arquivo:
uniform vec2 uResolution; // o tamanho do canvas em pixels, definido pelo código host
// dentro de main():
vec2 uv = gl_FragCoord.xy / uResolution; // 0..1 nos dois eixos
Numa malha, as UVs vêm do modelo: cada vértice guarda uma coordenada 2D que diz onde ele fica numa textura plana, e o
rasterizador a interpola ao longo do triângulo. De um jeito ou de outro, o fragment shader recebe um vec2 que vai de
0 a 1 pela superfície. Os cards deste site entregam esse valor pronto em i.uv, com a origem no canto inferior
esquerdo.
Veja como cor
O jeito mais rápido de entender uma coordenada é mostrá-la na tela. Escrever uv nos canais vermelho e verde pinta
preto no canto inferior esquerdo, vermelho no inferior direito, verde no superior esquerdo e amarelo no superior
direito:
#version 300 es
precision highp float;
uniform vec2 uResolution;
out vec4 fragColor;
void main() {
vec2 uv = gl_FragCoord.xy / uResolution;
fragColor = vec4(uv, 0.0, 1.0);
}
Essa também é a sua primeira ferramenta de depuração: qualquer valor entre 0 e 1 pode ser conferido escrevendo-o num canal de cor.
Centralizando
Formas radiais ficam mais fáceis de escrever em torno do meio da tela. Dobrar e deslocar leva a origem para o centro e o intervalo para -1..1:
vec2 p = uv * 2.0 - 1.0; // -1..1, com (0, 0) no meio
Agora Vetor Um grupo de dois a quatro números tratado como um só valor (vec2, vec3, vec4). O mesmo tipo guarda uma posição, uma direção, uma cor ou uma UV.length(p) é a distância até o centro, o ponto de partida de todo círculo e anel (veja
vetoresUm grupo de dois a quatro números tratado como um só valor (vec2, vec3, vec4). O mesmo tipo guarda uma posição, uma direção, uma cor ou uma UV.
Proporção de tela
As UVs esticam junto com o canvas. Num canvas de 1600×900, 0.1 em x cobre 160 pixels, mas 0.1 em y só 90, então um
círculo desenhado como length(p) < 0.5 sai como uma elipse. Multiplicar x pela proporção (largura dividida pela
altura) faz uma unidade valer o mesmo número de pixels nos dois eixos:
p.x *= uResolution.x / uResolution.y;
Um atalho comum centraliza e corrige numa linha só, dividindo apenas pela altura:
vec2 p = (2.0 * gl_FragCoord.xy - uResolution) / uResolution.y;
Aqui y vai de -1 a 1 e x vai um pouco além numa tela larga. Escolha uma convenção por shader e mantenha: todos os números das formas que vêm depois dependem dela.
Leitura complementar
- gl_FragCoord (abre em uma nova aba)Referência
- Uniforms (abre em uma nova aba)Livro
- UV mapping (abre em uma nova aba)Referência