Trilha 15 · Gráficos 2D e 3D

Transformações 2D

Como mover, rotacionar e escalar objetos usando matrizes 3×3 com coordenadas homogêneas — a base de todo motor gráfico, CSS transforms e SVG.

① Intuição

Transformações como matrizes

Para mover um sprite de jogo, você soma um offset à sua posição. Para rotacioná-lo, você aplica seno e cosseno. Para escaloná-lo, você multiplica. São três operações diferentes — mas existe um formalismo que unifica tudo: matrizes de transformação.

O truque são as coordenadas homogêneas: adicionar uma terceira coordenada w=1 ao vetor 2D (x, y) permite que translação também vire uma multiplicação de matriz 3×3. Com isso, qualquer sequência de transformações — por mais complexa que seja — se reduz a uma única multiplicação de matriz.

Impacto real: CSS transform, SVG transform, Canvas 2D, e todo motor de jogo 2D usam exatamente esse formalismo por baixo. Quando você escreve transform: rotate(45deg) scale(2), o browser calcula um produto de matrizes 3×3 e aplica ao elemento.
② Visualização interativa

Explore as transformações

Mova os sliders e veja a forma "F" ser transformada em tempo real. A forma fantasma mostra a posição original. A matriz 3×3 exibe os valores calculados.

CANVAS — forma "F" transformada (fantasma = original)
TRANSFORMAÇÕES
Translate X0
Translate Y0
Rotação (graus)0
Scale X1.00
Scale Y1.00
MATRIZ 3×3 (coords homogêneas)
1.000.000.00
0.001.000.00
0.000.001.00
③ Explicação técnica

As três matrizes e como combiná-las

// Transformações 2D com coordenadas homogêneas

// Translação: ponto (x,y) se move para (x+tx, y+ty)
const T = [
  1, 0, tx,
  0, 1, ty,
  0, 0,  1,
];

// Rotação por ângulo θ (em radianos)
const R = [
  Math.cos(θ), -Math.sin(θ), 0,
  Math.sin(θ),  Math.cos(θ), 0,
  0,           0,           1,
];

// Escala
const S = [
  sx, 0,  0,
  0,  sy, 0,
  0,  0,  1,
];

// Combinar T * R * S numa única matriz:
const M = matMul3x3(T, matMul3x3(R, S));

// Aplicar ao vértice (x, y):
const v = [x, y, 1]; // coord. homogênea
const vt = matVec3(M, v);  // → [x', y', 1]

Por que coordenadas homogêneas?

// Por que "coordenadas homogêneas"?
// Sem elas, translação NÃO é uma multiplicação de matriz.

// Com 2D puro (2×2): translação seria uma SOMA separada
const pt2D = [x + tx, y + ty]; // não é produto de matriz

// Com coordenadas homogêneas (3×3): translação VIRA produto
// → podemos combinar T, R e S numa única matriz!

// Ordem importa: T * R * S ≠ R * T * S
// "Escala, depois rotaciona, depois translada" = T * R * S
// "Translada, depois rotaciona, depois escala" = S * R * T

// Canvas 2D usa a mesma ideia:
ctx.translate(tx, ty);
ctx.rotate(angle);
ctx.scale(sx, sy);
ctx.drawImage(...); // aplica T * R * S ao drawImage
A ordem importa! Matrizes não são comutativas: T×R×S ≠ R×T×S. A convenção padrão (usada no Canvas 2D, CSS e OpenGL) é: primeiro escalonar, depois rotacionar, depois transladar — ou seja, aplicar as transformações da direita para a esquerda na matriz composta T×R×S.
④ Projeto para programar

Motor de sprites 2D

Mini projeto: implemente uma função applyTransform(vertices, tx, ty, angle, sx, sy) que transforma um array de pontos 2D com a matriz composta T×R×S. Teste com um triângulo apontado para cima.

Projeto principal: crie um sistema de hierarquia de objetos (scene graph): um objeto filho herda a transformação do pai. Por exemplo, uma roda que gira em torno de si mesma enquanto orbita o centro da tela — como a Lua ao redor da Terra. Implemente com multiplicação de matrizes acumuladas.

Desafio extra: implemente transformação de ponto fixo — rotacionar em torno de um ponto arbitrário (não a origem). Dica: translate para mover o ponto de pivot à origem, rotate, translate de volta. Verifique que isso equivale a uma única multiplicação de T×R×S cuidadosamente escolhida.

⑤ Exercícios rápidos

Teste sua intuição

Por que usamos coordenadas homogêneas (adicionar w=1) em transformações 2D?
Qual é a diferença entre rotate(45°) × translate(100,0) e translate(100,0) × rotate(45°)?
Como o browser implementa transform: rotate(45deg) scale(2)?
⑥ Aplicações no mundo real

Onde você encontra isso

🎮

Engines de jogos 2D

Unity, Godot e Phaser representam cada objeto com uma matriz de transformação. Parent-child hierarchy multiplica matrizes em cadeia. A GPU recebe a matriz final pré-calculada — transformar 10.000 sprites é só 10.000 multiplicações de matrizes.

🌐

CSS e SVG

transform: matrix(a, b, c, d, e, f) é exatamente uma matriz 3×3 em coordenadas homogêneas. Animações CSS com will-change: transform são processadas direto na GPU, bypassing o layout engine do browser.

📱

Renderização de UI

Frameworks como Flutter e SwiftUI constroem uma árvore de widgets, cada um com sua própria matriz de transformação. O "compositor" da GPU concatena as matrizes ao longo da hierarquia e renderiza tudo num único draw call quando possível.

← Anterior: Pixels e cores Próxima: Projeção 3D →