Pular para o conteúdo
Fundamento · VetoresIniciante

Noções de vetores

vec2, vec3 e vec4, com swizzles, length, distance, normalize e cross.

Como funciona

O GLSL pensa em vetores: vec2, vec3 e vec4 guardam dois, três ou quatro floats. O mesmo tipo armazena uma posição, uma direção, uma cor ou uma coordenada UV; o significado fica por sua conta. As operações aritméticas e a maioria das funções embutidas trabalham componente a componente, então uma linha de código com vetores faz o trabalho de duas a quatro linhas com escalares.

Construindo e combinando

Um construtor aceita qualquer mistura de escalares e vetores menores, desde que a contagem de componentes feche:

vec3 white = vec3(1.0);              // um valor preenche todos os componentes
vec4 color = vec4(white * 0.5, 1.0); // um vec3 mais um alfa
vec2 a = vec2(1.0, 2.0);
vec2 b = a * 2.0 + vec2(0.5);        // (2.5, 4.5)
vec2 c = a * b;                      // componente a componente: (2.5, 9.0)

a * b entre dois vetores multiplica componente a componente. Não é o produto escalar nem o produto vetorial, que têm funções próprias. O GLSL ES 3.00 também nunca converte int em float por conta própria: um construtor como vec2(1, 2) converte os argumentos, mas a * 2 é erro de compilação. Escreva 2.0.

Swizzles

Os componentes se chamam x y z w, r g b a ou s t p q: as mesmas quatro posições com três conjuntos de nomes. Qualquer combinação de nomes, em qualquer ordem e com repetições, monta um vetor novo. Isso é um swizzle:

vec4 v = vec4(1.0, 2.0, 3.0, 4.0);
vec2 xy  = v.xy;  // (1, 2)
vec3 bgr = v.bgr; // (3, 2, 1)
vec2 yy  = v.yy;  // (2, 2)
v.zw = vec2(0.0); // escrever também funciona, sem repetições

Um swizzle não pode misturar conjuntos: v.xg não compila.

Length, distance e normalize

length(v) é o módulo do vetor: a raiz quadrada da soma dos quadrados dos componentes. distance(a, b) é length(a - b), o espaço entre dois pontos. Num fragment shader, length(p) sobre uma UV centralizada é a distância até o centro, o ponto de partida de todo círculo e anel.

normalize(v) divide um vetor pelo próprio comprimento, o que mantém a direção e deixa o comprimento igual a 1. Direções como a normal de uma superfície, a direção da luz ou a direção de visão devem ser vetores unitários: o produto escalar de dois vetores unitários é o cosseno do ângulo entre eles, e a iluminação depende disso. Normalizar um vetor nulo divide por zero e dá um resultado indefinido, muitas vezes NaN, então proteja qualquer vetor que possa virar zero.

Produto vetorial

cross(a, b), definido só para vec3, devolve um vetor perpendicular aos dois, com comprimento |a| |b| sen θ. A direção segue a regra da mão direita, então trocar os argumentos inverte o resultado. Shaders o usam para obter uma normal a partir de duas arestas de um triângulo, ou para completar um sistema de três eixos a partir de dois:

vec3 n = normalize(cross(edge1, edge2)); // perpendicular ao triângulo

Leitura complementar