PerfectVector
Por Irene Kim10 min de leitura

SVGLoader no Three.js: transforme arte plana em malha 3D

Carregue traçados SVG no Three.js, preserve uma abertura real, corrija a orientação vertical e dimensione uma malha extrudada com um exemplo reproduzível no navegador.

Nesta página

Para transformar uma arte SVG plana em uma malha do Three.js, carregue o SVG, converta seus traçados em formas e passe essas formas para ExtrudeGeometry. Confira os vazados, a orientação vertical e as dimensões antes de adicionar efeitos. Uma silhueta reconhecível ainda pode ter um espaço interno preenchido ou um canto de cabeça para baixo.

Este passo a passo usa um emblema original feito manualmente, com uma abertura quadrada e o canto superior direito cortado. A assimetria torna visível um erro de orientação. É um exemplo de geometria no navegador, não um resultado de conversão do PerfectVector nem um teste de fabricação.

Comece com as formas às quais você quer dar profundidade

Use um SVG pequeno com contornos fechados e preenchidos na primeira tentativa. Salve isto como badge.svg:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 180">
  <path fill="#e64b35" fill-rule="evenodd"
    d="M20 20H160L220 80V160H20Z M65 60H115V110H65Z"/>
</svg>

Há dois subtraçados fechados dentro de um elemento path: um limite externo e um quadrado interno. A regra de preenchimento evenodd torna essa região interna uma abertura. Um retângulo branco separado apenas cobriria a face em uma imagem plana; não descreveria a mesma região vazia.

A arte ocupa 200 por 140 unidades de coordenadas dentro de um viewBox de 240 por 180. Tenha essa diferença em mente ao dimensionar a malha. Margens vazias fazem parte da área de visualização SVG, não da silhueta extrudada.

Se você já tem um original vetorial editável, use-o. Se um PNG ou JPG é seu único arquivo original, o fluxo de imagem para vetor do PerfectVector pode ajudar a preparar uma arte com traçados SVG. Inspecione a prévia e os contornos baixados, especialmente os espaços negativos, antes de carregar o arquivo no Three.js. A vetorização fornece a arte 2D; o código abaixo fornece profundidade, materiais, iluminação e posicionamento.

Carregue o SVG e renderize a malha

O exemplo foi testado com Three.js 0.186.0. Mantenha a biblioteca principal e o complemento na mesma versão. Em um projeto para navegador com importações de pacotes, instale three@0.186.0, sirva os arquivos por HTTP e crie um contêiner:

<div id="viewer"></div>
<script type="module" src="./main.js"></script>

Sua ferramenta de build precisa resolver as importações de three. Para uma página simples de navegador sem ferramenta de build, coloque este mapa de importação antes do script de módulo, usando os arquivos do mesmo pacote instalado:

<script type="importmap">
{
  "imports": {
    "three": "./node_modules/three/build/three.module.js",
    "three/addons/": "./node_modules/three/examples/jsm/"
  }
}
</script>

Coloque badge.svg ao lado da página HTML. A URL relativa de carregamento abaixo é resolvida em relação à URL dessa página. Depois, salve isto como main.js:

import * as THREE from 'three';
import { SVGLoader } from 'three/addons/loaders/SVGLoader.js';
 
const data = await new SVGLoader().loadAsync('./badge.svg');
const artwork = new THREE.Group();
for (const path of data.paths) {
  if (path.userData.style.fill === 'none') continue;
  for (const shape of path.toShapes()) {
    const geometry = new THREE.ExtrudeGeometry(shape, {
      depth: 20, bevelEnabled: false, steps: 1
    });
    const material = new THREE.MeshStandardMaterial({
      color: path.color, roughness: 0.65, metalness: 0
    });
    artwork.add(new THREE.Mesh(geometry, material));
  }
}
if (!artwork.children.length) throw new Error('No filled shapes found');
 
// SVG y grows down; this scene uses y up.
artwork.scale.y = -1;
const bounds = new THREE.Box3().setFromObject(artwork);
const size = bounds.getSize(new THREE.Vector3());
const center = bounds.getCenter(new THREE.Vector3());
const scale = 4 / size.x;
artwork.scale.multiplyScalar(scale);
artwork.position.copy(center).multiplyScalar(-scale);
 
const scene = new THREE.Scene();
scene.background = new THREE.Color('#f1f3f5');
scene.add(artwork);
scene.add(new THREE.HemisphereLight(0xffffff, 0x596477, 2));
const light = new THREE.DirectionalLight(0xffffff, 3);
light.position.set(-3, 5, 7);
scene.add(light);
const camera = new THREE.PerspectiveCamera(35, 800 / 600, 0.1, 100);
camera.position.set(4, 3, 9);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(800, 600);
document.querySelector('#viewer').append(renderer.domElement);
renderer.render(scene, camera);

SVGLoader é um complemento importado separadamente. loadAsync() lê o arquivo; parse(svgText) é a alternativa quando você já tem a marcação SVG como string.

Na r186, use path.toShapes(). Exemplos mais antigos costumam chamar SVGLoader.createShapes(path). Essa função auxiliar foi marcada como obsoleta na r185 e delega a toShapes() na versão testada. Confira a versão instalada antes de misturar trechos de tutoriais diferentes.

O laço ignora deliberadamente fill="none". Ele trata os preenchimentos sólidos deste exemplo; não é um renderizador SVG completo. Gradientes, máscaras, imagens incorporadas, contornos, opacidade e camadas de cor sobrepostas exigem suas próprias decisões, em vez de supor que a aparência plana se tornará uma geometria 3D idêntica.

Captura real no navegador que compara um emblema SVG original com abertura quadrada e canto superior direito cortado à sua malha extrudada no Three.js
Renderização WebGL real do exemplo feito manualmente no Three.js r186. A abertura continua vazia, o canto cortado permanece no alto à direita e a escala uniforme produz uma malha de 4 por 2.8 por 0.4.

Defina a orientação antes de medir e centralizar

As coordenadas verticais do SVG aumentam para baixo. Esta cena olha para a arte com y positivo apontando para cima, então artwork.scale.y = -1 restaura a orientação esperada. O canto cortado é a verificação: ele deve ficar no alto à direita.

Essa mudança de sinal pertence a esta configuração de coordenadas. Não adicione uma segunda inversão porque a malha ainda parece errada depois de girar uma câmera ou um objeto pai. Compare primeiro uma característica assimétrica conhecida da arte original com a cena renderizada.

As próximas linhas medem o grupo invertido, calculam uma escala uniforme e deslocam seu centro escalado para a origem. Box3.setFromObject() mede os limites incluindo objetos filhos e suas transformações. Aqui, o grupo não tem um pai transformado e a arte não está girada no momento da medição.

A extrusão original mede 200 por 140 por 20. Definir a largura como 4 resulta em uma escala de 4 / 200, ou 0.02. Como essa escala se aplica aos três eixos, os limites resultantes são 4 por 2.8 por 0.4. Uma profundidade de 20 no construtor não permanece 20 após a escala do grupo.

Essas são unidades da cena. O exemplo não afirma que uma unidade equivale a um milímetro. Se seu aplicativo precisa de uma interpretação física específica, defina-a explicitamente e valide-a pelo fluxo de destino.

Confirme o vazado antes de decorar a superfície

O teste produziu um traçado carregado, uma forma e um vazado. Também lançamos um raio através da abertura quadrada e outro através da área sólida: a abertura não retornou nenhuma interseção com a malha, enquanto a área sólida retornou uma. Raios através do canto superior direito cortado e do canto inferior direito sólido confirmaram a orientação vertical independentemente da vista inclinada.

Você pode começar com uma verificação visual mais simples na sua cena: veja a face de frente e depois em ângulo contra um fundo contrastante. A abertura deve revelar o fundo, e suas paredes laterais devem aparecer quando a câmera se move. Uma face branca cobrindo a área é um resultado diferente.

Se um espaço interno é preenchido, isole essa forma. Inspecione se o SVG original usa subtraçados, objetos preenchidos separados, um traçado de recorte ou uma máscara. Não tente esconder o problema com a cor do material. O guia de vazados SVG que são preenchidos explica as diferenças no arquivo de origem; o diagnóstico de extrusão aborda o reparo de contornos quando a arte subjacente está danificada.

Adicione efeitos de profundidade somente depois que a extrusão simples funcionar

O exemplo desativa os chanfros para facilitar a inspeção das dimensões iniciais. As opções de ExtrudeGeometry controlam separadamente a profundidade, o tamanho do chanfro, sua espessura e a amostragem das curvas. Confira novamente as pequenas aberturas e os limites ao ativar chanfros. Uma borda decorativa altera a geometria que você acabou de medir.

Para uma arte curva, inspecione a silhueta da malha no tamanho e na distância de câmera que seu aplicativo usará. Aumente a amostragem das curvas somente quando as facetas exigirem; reduzir nós desnecessários da entrada é uma tarefa de edição separada. Nenhuma dessas configurações restaura detalhes ausentes na arte original.

Um desenho feito apenas de contornos também precisa de outra decisão. O carregador expõe pointsToStroke() para geometria de contorno, mas o laço de formas preenchidas acima omite intencionalmente esses traçados. Se a linha visível deve se tornar uma faixa extrudada, decida primeiro qual contorno fechado define essa faixa. Se ela deve continuar como linha na cena, construa uma representação de linha ou contorno.

Para um aplicativo React, execute o carregamento e o trabalho do renderizador exclusivos do navegador no cliente e libere as geometrias, os materiais e o renderizador sob sua responsabilidade quando a visualização for removida. O exemplo compacto renderiza uma vez em tamanho fixo; um visualizador de produção também precisa tratar redimensionamento e ter seu próprio ciclo de vida de recursos.

Mantenha separadas as verificações de origem e destino

Uma malha no navegador é útil para um emblema interativo, uma prévia de logo ou uma decoração de cena. Ela não comprova que o resultado é uma peça estanque e dimensionalmente adequada. Se o destino é fabricação, use o fluxo separado de imagem para SVG para impressão 3D e inspecione o modelo importado ali.

Para o fluxo de tela, mantenha distintos três arquivos ou estágios: o SVG de origem editável, a malha derivada e a apresentação da cena. Isso facilita identificar se um resultado ruim veio da geometria dos traçados, da construção da malha ou da câmera e iluminação. Outros guias de fluxos SVG abordam a preparação do arquivo original quando a arte precisa de reparos antes do carregamento.

Perguntas frequentes

Por que meu SVG está de cabeça para baixo no Three.js? As coordenadas verticais SVG aumentam para baixo. Em uma cena que usa y positivo para cima e vê a frente da arte, inverter a escala y do grupo da arte pode restaurar a orientação da arte original. Confira uma característica assimétrica antes de adicionar outra inversão ou rotação.

Devo usar createShapes ou toShapes? Este exemplo usa path.toShapes() com Three.js 0.186.0. SVGLoader.createShapes() foi marcado como obsoleto na r185. Use a API documentada para a versão instalada no seu projeto, com o pacote principal e o complemento na mesma versão.

SVGLoader transforma um PNG dentro de um SVG em uma malha? Uma imagem raster incorporada não fornece os contornos preenchidos usados por este exemplo. Obtenha primeiro uma arte com traçados adequados ou use a imagem como textura quando preservar sua aparência for o objetivo real.

A extrusão preserva a largura do contorno SVG? Este exemplo extruda formas preenchidas e ignora traçados com fill definido como none. A geometria de contorno precisa de um fluxo separado; uma linha grossa pintada não é automaticamente o contorno fechado de uma faixa extrudada.

Fontes

  1. Three.js — SVGLoader — Documenta a importação do complemento, os métodos de interpretação e carregamento, a função auxiliar de contorno e a marcação de createShapes como obsoleto.
  2. Three.js — ShapePath — Documenta a conversão de conjuntos de traçados em formas com toShapes.
  3. Three.js — ExtrudeGeometry — Define a extrusão de formas e as opções de profundidade, chanfro e amostragem de curvas.
  4. Three.js — Box3 — Documenta a medição dos limites de objetos transformados e a obtenção de seu tamanho e centro.

Você está trabalhando com um emblema disponível somente em raster? Prepare uma versão candidata em SVG, inspecione seus contornos preenchidos e aberturas e teste esse arquivo nesta pequena cena antes de construir o visualizador completo.

Mais do blog

Recomece com um SVG mais limpo
e fácil de editar