Trilha 15 · Gráficos 2D e 3D

Projeção 3D

Como objetos tridimensionais viram imagens 2D — o pipeline MVP, a diferença entre perspectiva e ortografia, e como a profundidade cria ilusão de distância.

① Intuição

O problema da dimensão perdida

Uma tela é plana — só tem X e Y. Mas o mundo 3D tem X, Y e Z. Para renderizar geometria 3D, precisamos de uma função que projete pontos (x,y,z) em pontos (x',y') da tela. Existem dois tipos fundamentais:

Projeção perspectiva: objetos mais distantes aparecem menores — exatamente como nos nossos olhos. Linhas paralelas convergem para um ponto de fuga. Usada em jogos e cinema. A fórmula é simples: x' = f·x / (z + d).

Projeção ortográfica: sem distorção de perspectiva. Objetos têm o mesmo tamanho independente da distância. Usada em CAD, plantas baixas e jogos isométricos.

O pipeline MVP: antes de projetar, cada vértice passa por três matrizes 4×4: Model (posição/rotação do objeto no mundo) → View (posição da câmera) → Projection (perspectiva ou ortografia). O produto M×V×P aparece literalmente no vertex shader de todo jogo e aplicação 3D.
② Visualização interativa

Cubo 3D interativo

Rotacione o cubo com os sliders, alterne entre perspectiva e ortográfica. Observe como as arestas paralelas convergem (perspectiva) ou permanecem paralelas (ortográfica).

CUBO 3D — projeção perspectiva
CONTROLES
Rotação X30°
Rotação Y45°
Rotação Z0°
FOV (distância focal)200
FÓRMULA DA PROJEÇÃO
x₂D = f·x / (z + d)
y₂D = f·y / (z + d)
f=fov, d=distância
③ Explicação técnica

Pipeline MVP e projeção

// O pipeline de transformação 3D: MVP

// 1. Model matrix — posição/rotação do objeto no mundo
const M = translate(x, y, z) * rotate(rx, ry, rz) * scale(sx, sy, sz);

// 2. View matrix — câmera: inverte posição/rotação do mundo
const V = lookAt(cameraPos, target, up);

// 3. Projection matrix — 3D → 2D (perspectiva ou ortográfica)
const P_persp = perspective(fov, aspectRatio, near, far);
const P_ortho  = orthographic(left, right, top, bottom, near, far);

// Vértice final (NDC = Normalized Device Coordinates −1..1)
const clipPos = P * V * M * vec4(vertexPos, 1.0);

// No vertex shader GLSL:
void main() {
  gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);
}

Projeção perspectiva e painter's algorithm

// Projeção perspectiva manual (sem matriz)
function project(x, y, z, fov, d) {
  // Distância focal: quanto maior, menos distorção
  const f = fov / (z + d);  // d = distância câmera-tela
  return {
    x: centerX + x * f,
    y: centerY - y * f,  // Y invertido: +Y é para cima
  };
}

// Projeção ortográfica (sem perspectiva)
function projectOrtho(x, y, scale) {
  return {
    x: centerX + x * scale,
    y: centerY - y * scale,  // Z completamente ignorado
  };
}

// Painter's algorithm: draw back faces first
faces.sort((a, b) => avgZ(b) - avgZ(a)); // back-to-front
faces.forEach(face => drawFace(face));
Z-fighting: quando dois triângulos têm profundidade Z muito próxima, o Z-buffer tem precisão insuficiente para decidir qual está na frente — causando flicker. Solução: aumentar near (plano de corte próximo) para aumentar a precisão do Z-buffer nas distâncias relevantes. O Z-buffer usa representação de ponto flutuante não-linear — mais precisão perto, menos longe.
④ Projeto para programar

Renderizador 3D no Canvas 2D

Mini projeto: renderize um cubo wireframe (só arestas) no Canvas 2D usando projeção perspectiva manual (f/(z+d)). Adicione rotação controlada pelo mouse (drag).

Projeto principal: renderize um cubo com faces sólidas usando painter's algorithm: sort por Z médio, preencha polígonos com ctx.fill(). Adicione iluminação flat shading — calcule a normal de cada face e multiplique a cor pelo dot product com a direção da luz.

Desafio extra: carregue um arquivo OBJ simples (formato texto com vértices "v" e faces "f"), renderize com faces sólidas. Implemente backface culling: descarte faces cuja normal aponta para longe da câmera (dot product com view direction > 0).

⑤ Exercícios rápidos

Teste sua intuição

Qual é a fórmula da projeção perspectiva para converter X 3D em X 2D de tela?
No pipeline MVP, o que cada matriz representa?
Jogos 3D de ação usam que tipo de projeção, e por quê?
⑥ Aplicações no mundo real

Onde você encontra isso

🎮

Engines 3D (Unity, Unreal)

A câmera é uma matriz de View + Projection armazenada como UBO (Uniform Buffer Object) na GPU. Cada frame, a CPU atualiza a matriz e todos os shaders lêem o mesmo buffer. FOV ajustável e near/far planes são parâmetros da matriz Projection.

📐

CAD e engenharia

AutoCAD, SolidWorks e Blender usam projeção ortográfica para vistas técnicas (frontal, lateral, planta) porque dimensões devem ser preservadas sem distorção. A perspectiva só aparece na "viewport 3D" de visualização geral.

🗺️

Google Maps 3D / AR

Mapas com modo 3D usam projeção perspectiva com FOV estreito para minimizar distorção em vistas de cima. AR (realidade aumentada) usa a matriz de câmera do sensor do celular como View matrix — alinhando objetos virtuais ao mundo físico.

← Anterior: Transformações 2D Próxima: Rasterização →