› IntroduçãoComputação Gráfica • Prof. Pedro Ximenes
Transformações Geométricas 2D — Parte 3
Computação Gráfica — Mudança entre Sistemas de Coordenadas 2D & Pipeline no Canvas 2D, WebGL e Three.js
Prof. Pedro Ximenes
Universidade Católica de Pernambuco (UNICAP)
Sumário
Visão Geral
1
Transformações entre Sistemas de Coordenadas 2D: Motivação, formulação do problema e conexão direta com o futuro assunto de Viewing 3D.
2
Método 1 — Usando o Ângulo de Rotação $\theta$: Decomposição em translação e rotação horária $R(-\theta)$, dedução matricial e exemplo numérico completo.
3
Propriedade Ortonormal & Método 2 (Sem Ângulo): Especificação de orientação por vetor diretor $\vec{V} = P_1 - P_0$, normalização e construção da base ortogonal $\vec{u}$.
4
Transformações 2D em JavaScript/Canvas: Funções nativas (`translate`, `rotate`, `scale`, `setTransform`, `save/restore`) e convenção do eixo $Y$ para baixo.
5
Ordem de Execução, Pipeline, WebGL & Three.js: Execução de baixo para cima, não-comutatividade, reset de matriz e transição para shaders WebGL e Three.js.
Por que Transformar entre Sistemas de Coordenadas?
Motivação
Contexto
Em Computação Gráfica, muitas vezes precisamos converter as coordenadas de um ponto de um sistema de coordenadas para outro.
Mais adiante no curso, vamos aprender Transformações entre Sistemas de Coordenadas 3D, essencial para o assunto de Viewing 3D (câmeras sintéticas, sistemas de coordenadas do mundo, da câmera e da tela).
Antes disso, é muito mais fácil, intuitivo e didático aprender a versão 2D!
A álgebra linear, a ortonormalidade e a ordem de composição de matrizes que você dominar aqui em 2D serão exatamente as mesmas aplicadas em 3D.
Enunciado do Problema
Enunciado
Imagine dois sistemas de coordenadas:
Sistema original $XY$ (em preto), com origem canônica em $(0,0)$.
Sistema destino $X'Y'$ (em azul/ciano), cuja origem está localizada em $(x_0, y_0)$ do sistema $XY$ e rotacionado por um ângulo $\theta$.
Pergunta: Dado um ponto com coordenadas $(x, y)$ no sistema $XY$, quais são suas coordenadas no sistema $X'Y'$?
Visualização do Problema
Objetivo
Objetivo Fundamental
Encontrar as coordenadas de $P$ no sistema $X'Y'$, ou seja:
$$\mathbf{P}' = (x', y')$$
Os dois sistemas representam a mesma cena física, com exatamente os mesmos objetos. Não estamos movendo o ponto no espaço real! Estamos apenas “reindexando” suas coordenadas para expressá-las em relação a uma nova origem e novos eixos de referência.
Princípio Geométrico da Transformação
Para expressar o ponto $P$ no sistema $X'Y'$, devemos descobrir qual sequência de operações move o sistema $X'Y'$ de volta para coincidir perfeitamente com a origem e a orientação do sistema canônico $XY$.
Método 1 — Usando o Ângulo $\theta$
Método 1
Para transformar de $XY$ para $X'Y'$, usamos duas operações consecutivas:
Transladar a origem de $X'Y'$ (que está em $(x_0, y_0)$) para coincidir com a origem de $XY$: $\mathbf{T(-x_0, -y_0)}$
Rotacionar por $-\theta$ para alinhar os eixos: $\mathbf{R(-\theta)}$
Lembre-se sempre: de trás para frente! A translação é a 1ª operação aplicada geometricamente ao ponto e, portanto, aparece por último na multiplicação de matrizes à esquerda.
Aplicando ao ponto
$$P' = M_{XY \to X'Y'} \cdot P = R(-\theta) \cdot T(-x_0, -y_0) \cdot \begin{pmatrix} x \\ y \\ 1 \end{pmatrix}$$
O vetor resultante $P' = (x', y', 1)^T$ contém as coordenadas do ponto expressas no sistema destino $X'Y'$.
Exemplo — Método 1
Exemplo Completo
Calcular a matriz de transformação de $XY$ para $X'Y'$ e as coordenadas finais do ponto $P$ no sistema destino ($P'$). Dados: $x_0 = 3$, $y_0 = 2$, $\theta = 45^\circ$, $P = (4, 5)$. Sabendo que $\cos 45^\circ = \sin 45^\circ = \frac{\sqrt{2}}{2} \approx 0{,}7071$.
Sistema $XY$ (preto), $X'Y'$ a $45^\circ$, ponto $P(4,5)$ e projeções ortogonais $P' \approx (2{,}83, \; 1{,}41)$
Exemplo — Método 1 (Notas sobre a Rotação $R(-\theta)$)
Análise Teórica
Por que $-\theta$ e não $+\theta$?
Os dois sistemas estão desalinhados por um ângulo $\theta$ no sentido anti-horário. Para alinhar os eixos de volta ao sistema canônico, precisamos rotacionar no sentido horário, o que na convenção matemática padrão significa ângulo negativo: $-\theta$.
Lembrete Algébrico: $R(-\theta)$
$$R(-\theta) = \begin{pmatrix}
\cos(-\theta) & -\sin(-\theta) & 0 \\
\sin(-\theta) & \cos(-\theta) & 0 \\
0 & 0 & 1
\end{pmatrix} = \begin{pmatrix}
\cos\theta & \sin\theta & 0 \\
-\sin\theta & \cos\theta & 0 \\
0 & 0 & 1
\end{pmatrix}$$
Como o cosseno é função par ($\cos(-\theta) = \cos\theta$) e o seno é função ímpar ($\sin(-\theta) = -\sin\theta$), o sinal do seno “troca de posição” na matriz de rotação.
Problema Fundamental deste Método
Na prática profissional de Computação Gráfica, o ângulo $\theta$ geralmente não é informado diretamente!
Nas aplicações reais (câmeras virtuais, robótica, engines de jogos), conhecemos a posição da origem $(x_0, y_0)$ e as coordenadas de um segundo ponto de mira, mas calcular $\theta$ exigiria funções trigonométricas caras ($\arctan$).
$\Rightarrow$ O Método 2 resolve exatamente esse problema!
Ou seja, os dois vetores formam ângulo reto perfeito ($90^\circ$) entre si e possuem comprimento exatamente unitário.
Para que serve isso?
Essa propriedade geométrica permite construir a matriz de rotação sem conhecer previamente o ângulo $\theta$ — é a base matemática do Método 2!
Método 2 — Orientação pelo Vetor $\vec{V}$ ($P_0$ e $P_1$)
Método 2
Direção do eixo $Y'$ determinada pelo vetor $\vec{V} = P_1 - P_0$
Orientação por Vetor Direcional
Usando a propriedade de ortonormalidade, descrevemos a orientação do sistema de coordenadas $X'Y'$ por meio de um vetor $\vec{V}$ indicando a direção positiva do eixo $y'$.
$P_0 = (x_0, y_0)$: define a posição da origem do sistema de destino $X'Y'$.
$P_1 = (x_1, y_1)$: qualquer ponto arbitrário sobre a parte positiva do eixo $Y'$.
Grande Vantagem Prática
Dispensa o cálculo de $\theta$ via $\arctan$, eliminando ambiguidades de quadrante e divisões por zero!
Método 2 — Vetor Diretor e Normalização (Passos 1 e 2)
Passos 1 e 2
Ideia Central
Ao invés do ângulo $\theta$, usamos dois pontos para definir a orientação do sistema $X'Y'$: a origem $P_0 = (x_0, y_0)$ e um ponto $P_1 = (x_1, y_1)$ na direção positiva do eixo $Y'$.
Passo 1: Obter o Vetor Diretor de $Y'$
Calcular o vetor que liga a origem $P_0$ ao ponto de alinhamento $P_1$:
$$\vec{V} = P_1 - P_0 = (x_1 - x_0, \; y_1 - y_0) = (V_x, V_y) \quad \text{(não normalizado)}$$
Passo 2: Normalizar o Vetor (Comprimento Unitário)
Dividir o vetor pela sua norma euclidiana para obter um vetor unitário ($\|\vec{v}\| = 1$):
$$\|\vec{V}\| = \sqrt{V_x^2 + V_y^2}, \qquad
\vec{v} = \left(\frac{V_x}{\|\vec{V}\|}, \; \frac{V_y}{\|\vec{V}\|}\right) = (v_x, v_y)$$
Regra de Ouro: Vetores Unitários Sempre!
Em Computação Gráfica, sempre normalize seus vetores direcionais! Se um vetor não tem norma 1, ele causará distorções involuntárias de escala nos objetos. Convenção: Maiúsculas $(V_x, V_y)$ = vetor bruto não normalizado. Minúsculas $(v_x, v_y)$ = vetor unitário normalizado.
Método 2 — Construindo a Matriz de Rotação (Passos 3 a 5)
Passos 3 a 5
Construção Geométrica: $\vec{u} \perp \vec{v}$ formando a base ortonormal de $X'Y'$ ($90^\circ$)
Passo 3: Vetor Ortogonal $\vec{u}$ no Eixo $X'$
Um vetor perpendicular a $\vec{v} = (v_x, v_y)$ apontando para $X'$ é obtido trocando as componentes e invertendo o sinal:
$$\vec{u} = (u_x, \; u_y) = (v_y, \; -v_x)$$
Calcular a matriz de transformação de $XY$ para $X'Y'$ e as coordenadas finais do ponto $P$ no sistema destino ($P'$). Dados: $P_0 = (x_0, y_0) = (4, 3)$, $P_1 = (x_1, y_1) = (3, 4)$, $P = (3, 6)$.
Pontos $P_0(4,3)$, $P_1(3,4)$, vetor $\vec{V} = (-1, 1)$ e ponto $P(3,6)$
Mais eficiente, robusto e prático em motores gráficos reais.
Usado quando $\theta$ não é conhecido (ex.: câmeras virtuais).
Quando usar cada método?
Se o ângulo de rotação $\theta$ for fornecido $\Rightarrow$ Método 1
Se dois pontos de alinhamento do eixo forem dados (sem ângulo) $\Rightarrow$ Método 2
Ambos os métodos produzem rigorosamente o mesmo resultado numérico! A única distinção é a forma matemática como a rotação é formulada (trigonometria direta vs. vetores ortonormais).
Laboratório Interativo — Método 2 (Dois Pontos e Vetor $\vec{V}$)
Simulação 2D
4
3
3
4
3
6
Dedução Matricial Instantânea
Observações do Experimento
Vetor vermelho $\vec{V}$: aponta de $P_0$ para $P_1$, definindo a direção positiva de $Y'$.
Eixos ciano ($X'Y'$): construídos automaticamente através dos vetores ortonormais $(\vec{v}, \vec{u})$.
Arraste $P_1$ para observar a matriz $R$ se recalculando sem qualquer chamada a $\sin$ ou $\cos$!
Transformações no Canvas 2D — Introdução
HTML5 Canvas
Canvas 2D do HTML5
O elemento <canvas> do HTML5 oferece um contexto 2D (ctx) com funções nativas de transformação que aplicam matrizes afins $3\times 3$ internamente no pipeline de renderização.
Três funções principais
ctx.translate(tx, ty) — Translação de eixos
ctx.rotate(angulo) — Rotação (ângulo fornecido em radianos!)
ctx.scale(sx, sy) — Escala a partir da origem
Atenção Crítica: Ângulo em Radianos!
A função nativa ctx.rotate() recebe obrigatoriamente o ângulo em radianos, nunca em graus!
$$\text{rad} = \text{graus} \times \frac{\pi}{180}$$
Exemplo: $90^\circ = 90 \times \pi / 180 = \pi/2 \approx 1{,}5708 \text{ rad}$.
ctx.translate — Translação
Canvas 2D
Sintaxe
ctx.translate(tx, ty);
Translada a origem do sistema de coordenadas do canvas em $(t_x, t_y)$ pixels.
Exemplo de Código
// Move o sistema de coordenadas 100px para a direita e 50px para baixoctx.translate(100, 50);
// Tudo desenhado a seguir estará posicionado em relação à nova origemctx.fillRect(0, 0, 40, 30); // O retângulo surge fisicamente em (100, 50)
Observação Importante: Convenção do Canvas ($Y$ para baixo)
No Canvas 2D, o eixo $Y$ cresce para baixo (oposto à convenção cartesiana matemática). Isso afeta diretamente o sentido visual das translações verticais e das rotações!
ctx.rotate e ctx.scale
Canvas 2D
ctx.rotate(angulo)
Aplica uma rotação ao redor da origem atual $(0,0)$ do sistema de coordenadas. O ângulo deve ser passado em radianos. ctx.rotate(Math.PI / 4); // rotação de $45^\circ$
ctx.scale(sx, sy)
Multiplica as distâncias a partir da origem atual. Pode deslocar o objeto como efeito colateral indesejado! ctx.scale(2, 0.5); // duplica a largura em $x$ e reduz à metade em $y$
Cuidados com a Escala sem Ponto Fixo
Essa é a escala padrão a partir da origem (se o objeto não estiver na origem, ele se moverá!).
Para escala com ponto fixo: requer composição (translate $\to$ scale $\to$ translate).
O Canvas 2D não possui uma função direta ctx.shear(). Para cisalhar, utiliza-se ctx.transform(a, b, c, d, e, f) passando a matriz afim $3\times 3$ completa.
ctx.setTransform e ctx.save / restore
Gerenciamento de Estado
Reset da Matriz de Transformação
ctx.setTransform(1, 0, 0, 1, 0, 0);
Substitui imediatamente a matriz de transformação atual pela matriz identidade (reseta qualquer escala, rotação ou translação anterior).
Salvando e Restaurando o Estado Gráfico
ctx.save(); // empilha o estado atual (matriz, cores, estilos)ctx.translate(100, 100);
ctx.rotate(Math.PI / 4);
// ... renderiza o objeto transformado ...ctx.restore(); // desempilha e restaura o estado anterior sem afetar o resto
Resumo das Equivalências Teóricas
Conceito Teórico
Equivalente no Canvas 2D
Translação $T(t_x, t_y)$
ctx.translate(tx, ty)
Rotação $R(\theta)$
ctx.rotate(rad)
Escala $S(s_x, s_y)$
ctx.scale(sx, sy)
Carregar Identidade $I$
ctx.setTransform(1, 0, 0, 1, 0, 0)
Pilha de Matrizes (Push/Pop)
ctx.save() / ctx.restore()
A Importância do Reset da Matriz
Ordem & Acumulação
O Problema da Acumulação Descontrolada
Se você estiver redesenhando repetidamente a tela (por exemplo, em loops de animação com requestAnimationFrame), as funções de transformação se multiplicam e se acumulam a cada quadro!
❌ SEM Reset (Incorreto)
functiondraw() {
ctx.clearRect(0, 0, w, h);
// SEM reset da matriz!ctx.scale(2, 2);
desenhaCasa();
requestAnimationFrame(draw);
}
A escala acumula exponencialmente: $2\times, 4\times, 8\times, 16\times\dots$ e o objeto desaparece da tela!
A matriz é limpa a cada quadro e a escala $2\times$ é aplicada de forma estável e consistente.
Regra de Ouro
Sempre resete a matriz de transformação (via ctx.setTransform(1,0,0,1,0,0) ou ctx.save()/ctx.restore()) antes de aplicar novas transformações a cada quadro de animação!
Ordem das Transformações — De Baixo para Cima
Ordem das Matrizes
Leitura do Pipeline: De Baixo para Cima!
No Canvas 2D, exatamente como aprendemos na teoria matricial, a primeira transformação geométrica aplicada ao objeto é a última linha de código escrita imediatamente antes da função de desenho. As matrizes afins são pós-multiplicadas no contexto gráfico.
Exemplo: Escala com Ponto Fixo em $(110, 50)$
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.translate(110, 50); // 3ª operacao (volta do ponto fixo)ctx.scale(2, 2); // 2ª operacao (aplica o fator de escala)ctx.translate(-110, -50); // 1ª operacao (leva ponto fixo p/ origem)desenhaCasa(); // Geometria do objeto
Sequência de Execução Geométrica
3ª: ctx.translate(110, 50)
▲
2ª: ctx.scale(2, 2)
▲
1ª: ctx.translate(-110, -50)
▲
desenhaCasa()
Exemplo: Rotação com Ponto Arbitrário + Translação
Composição Complexa
Rotação de $90^\circ$ ao redor de $(110, 50)$ + Translação $t_x = 50$
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.translate(50, 0); // 4ª op: translada em x no finalctx.translate(110, 50); // 3ª op: volta do ponto de rotacaoctx.rotate(Math.PI / 2); // 2ª op: rotacao de 90 graus (PI/2 rad)ctx.translate(-110, -50); // 1ª op: leva o ponto pivô para a origemdesenhaCasa();
A Ordem Importa Absolutamente!
Se você mover ctx.translate(50, 0) para depois dos três comandos de rotação (ou seja, imediatamente antes de desenhaCasa()), o resultado gráfico final será completamente diferente!
Trocar a posição de uma única linha de código altera todo o desenho na tela porque a multiplicação de matrizes não é comutativa ($A \cdot B \neq B \cdot A$).
Exemplo Completo — Escala com Ponto Fixo
Código Completo
Escala com ponto fixo $(110, 50)$, fator 2
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
functiondesenhaCasa() {
ctx.beginPath();
ctx.moveTo(100, 100); ctx.lineTo(120, 100);
ctx.lineTo(120, 50); ctx.lineTo(110, 30); // telhado
ctx.lineTo(100, 50); ctx.closePath();
ctx.fillStyle = 'red'; ctx.fill();
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset// Escala com ponto fixo (110, 50) - lida de BAIXO para CIMA:
ctx.translate(110, 50); // 3ª op: translada de volta
ctx.scale(2, 2); // 2ª op: aplica a escala
ctx.translate(-110, -50); // 1ª op: leva o ponto fixo para a origemdesenhaCasa();
Laboratório Interativo — Pipeline Canvas 2D
Simulação 2D
Testar Casos Clássicos do Slide:
Pipeline JavaScript Equivalente Executado
O que Observar na Tela
Casinha tracejada (cinza): geometria original sem nenhuma transformação.
Casinha vermelha: geometria resultante após as matrizes afins do pipeline.
Ponto rosa: ponto de ancoragem / pivô fixo $(110, 50)$.
Ao selecionar “Ordem Invertida”, veja como a translação é rotacionada pelo ângulo de $90^\circ$, arremessando a casinha para uma posição completamente errada!
Composição com Matrizes no WebGL
WebGL Shaders
Do Canvas 2D ao WebGL
Em aplicações WebGL, combinamos as transformações afins em uma única matriz de modelo e visão (ModelView) que é repassada via uniform para o vertex shader na GPU.
A ordem da composição algébrica segue exatamente a mesma lógica:
$$gl\_Position = \underbrace{projection}_{\text{4ª}} \cdot \underbrace{T}_{\text{3ª}} \cdot \underbrace{R}_{\text{2ª}} \cdot \underbrace{S}_{\text{1ª}} \cdot Position$$
Primeira transformação aplicada = última na equação
Escala primeiro, depois rotação, depois translação e, por fim, a matriz de projeção em perspectiva ou ortogonal.
Transformações 3D com Three.js
Three.js
Do Canvas 2D ao 3D Moderno
Em aplicações 3D industriais, utilizamos bibliotecas de alto nível como o Three.js, que encapsulam os shaders do WebGL. Cada objeto tridimensional (Mesh) possui propriedades intuitivas de transformação.
Transformações em um objeto Three.js
// 1. Escala
mesh.scale.set(2, 2, 1);
// 2. Rotacao (em radianos ao redor do eixo Z)
mesh.rotation.z = Math.PI / 4;
// 3. Translacao
mesh.position.set(110, 50, 0);
O Three.js compõe automaticamente a matriz local mesh.matrix na ordem padrão:
$$M = \underbrace{T}_{\text{position}} \cdot \underbrace{R}_{\text{rotation}} \cdot \underbrace{S}_{\text{scale}}$$
Mesma Lógica Universal de Composição
Escala primeiro, depois rotação, depois translação — a mesmíssima ordem que deduzimos e provamos no Canvas 2D!
Resumo Geral & Tabela Comparativa de Sintaxe
Síntese
Conceito
Expressão Algébrica
HTML5 Canvas 2D
WebGL / Three.js
Translação
$T(t_x, t_y)$
ctx.translate(tx, ty)
mesh.position.set(x, y, z)
Rotação
$R(\theta)$
ctx.rotate(rad)
mesh.rotation.z = rad
Escala
$S(s_x, s_y)$
ctx.scale(sx, sy)
mesh.scale.set(sx, sy, sz)
Mudança de Base
$M = R \cdot T(-x_0, -y_0)$
Translação $\to$ Rotação
Matriz de Câmera / View Matrix
Identidade / Reset
Matriz Identidade $I$
ctx.setTransform(1,0,0,1,0,0)
matrix.identity()
Ordem na Geometria
De trás para frente ($A \cdot B \cdot P$)
De baixo para cima
$T \cdot R \cdot S \cdot \mathbf{v}$
Conclusão Fundamental da Parte 3
Com as Partes 1, 2 e 3 de Transformações 2D concluídas, você dominou a base matemática completa de coordenadas homogêneas, transformações inversas, composição de matrizes, mudança de sistemas de coordenadas e pipelines gráficos modernos. Esses conceitos são idênticos em 3D, adicionando apenas a terceira dimensão $Z$!
Referências Bibliográficas
Material Complementar
Livros-Texto Recomendados
1. Angel, E.; Shreiner, D.Interactive Computer Graphics: A Top-Down Approach with WebGL. 8th edition. Pearson. Capítulo 5 (Geometric Objects and Transformations).
2. Mount, D.CMSC 427 — Computer Graphics Lecture Notes. University of Maryland. Aulas 6 a 9 (Coordinate Systems & Viewing).
Material Digital & Dicas de Estudo
1. Material de Introdução à Computação Gráfica — IME-USP. Disponível em: https://panda.ime.usp.br/introcg/static/introcg
2. Dica Prática: Pratique montando as matrizes de rotação usando Método 1 (com $\theta$) e Método 2 (com vetores unitários) e conferindo nos simuladores desta página para consolidar a fixação!