Como Construir uma Malha 3D Programaticamente em TypeScript

Como Construir uma Malha 3D Programaticamente em TypeScript

Aspose.3D FOSS for TypeScript permite que você construa geometria 3D inteiramente em código sem carregar nenhum arquivo. Você define posições de vértices como pontos de controle, especifica faces de polígonos por índice e anexa elementos de vértice opcionais, como normais, UVs ou cores de vértice. O resultado pode ser salvo em qualquer formato gravável: glTF, GLB, STL, FBX ou COLLADA.

Pré-requisitos

  • Node.js 18 ou posterior
  • TypeScript 5.0 ou posterior
  • @aspose/3d instalado (veja a Etapa 1)

Guia passo a passo

Etapa 1: Instalar @aspose/3d

npm install @aspose/3d

Nenhum addon nativo ou biblioteca do sistema é necessário. O pacote inclui definições de tipo TypeScript.

Mínimo tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true
  }
}

Passo 2: Criar uma Cena e um Nó

Um Scene é o contêiner de nível superior. Toda a geometria deve ser anexada a um Node dentro da árvore de cena:

import { Scene } from '@aspose/3d';

const scene = new Scene();
const node = scene.rootNode.createChildNode('triangle');

createChildNode(name) cria um nó nomeado e o conecta como filho do nó atual. O objeto Node retornado é onde você anexará a malha na Etapa 7.


Etapa 3: Criar um Objeto Mesh

Mesh contém posições de vértices e definições de polígonos. Construa um com um nome opcional:

import { Mesh } from '@aspose/3d/entities';

const mesh = new Mesh('triangle');

A mesh começa vazia: sem vértices e sem faces. Você os adiciona nas próximas etapas.


Etapa 4: Adicionar Pontos de Controle (Vértices)

Pontos de controle são as posições dos vértices no espaço local. Envie os valores Vector4 para mesh.controlPoints. O quarto componente (w) é 1 para posições:

import { Vector4 } from '@aspose/3d/utilities';

mesh.controlPoints.push(new Vector4(0.0, 0.0, 0.0, 1.0)); // index 0
mesh.controlPoints.push(new Vector4(1.0, 0.0, 0.0, 1.0)); // index 1
mesh.controlPoints.push(new Vector4(0.5, 1.0, 0.0, 1.0)); // index 2

Você referencia essas posições pelo índice baseado em zero ao definir faces de polígonos.


Etapa 5: Criar Faces de Polígono

createPolygon() define uma face listando os índices dos vértices em ordem. Três índices formam um triângulo:

mesh.createPolygon(0, 1, 2);

Você também pode definir quads (quatro índices) ou polígonos arbitrários para formatos que os suportam. Para glTF, a biblioteca triangulará automaticamente quads e n-gons na exportação.


Etapa 6: Adicionar Normais de Vértice

Normais melhoram a qualidade da renderização. Use mesh.createElement() para criar um VertexElementNormal, coletar vetores normais em um array, então chame setData() para armazená‑los. O getter data retorna uma cópia defensiva — adicionar a ele não tem efeito. Use FVector3 (float de precisão simples) para dados de normais, não Vector4.

import { VertexElementNormal } from '@aspose/3d/entities';
import { VertexElementType, MappingMode, ReferenceMode } from '@aspose/3d/entities';
import { FVector3 } from '@aspose/3d/utilities';

const normals = mesh.createElement(
    VertexElementType.NORMAL,
    MappingMode.CONTROL_POINT,
    ReferenceMode.DIRECT
) as VertexElementNormal;

// Build the normal array, then call setData() — do NOT push to normals.data
normals.setData([
    new FVector3(0, 0, 1), // normal for vertex 0 (pointing +Z)
    new FVector3(0, 0, 1), // normal for vertex 1
    new FVector3(0, 0, 1), // normal for vertex 2
]);

MappingMode.CONTROL_POINT significa uma normal por vértice. ReferenceMode.DIRECT significa que o array de dados é indexado diretamente pelo índice do vértice do polígono.


Passo 7: Anexar a Malha e Salvar como glTF

Atribua a malha ao nó via node.entity, então salve a cena:

import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

node.entity = mesh;

const saveOpts = new GltfSaveOptions();
scene.save('triangle.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Triangle mesh saved to triangle.gltf');

Para produzir um único arquivo .glb autocontido, defina saveOpts.binaryMode = true e altere a extensão do arquivo de saída para .glb.

Exemplo completo

O seguinte é o script completo combinando todas as etapas acima:

import { Scene } from '@aspose/3d';
import { Mesh, VertexElementNormal } from '@aspose/3d/entities';
import { VertexElementType, MappingMode, ReferenceMode } from '@aspose/3d/entities';
import { Vector4, FVector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('triangle');

const mesh = new Mesh('triangle');

mesh.controlPoints.push(new Vector4(0.0, 0.0, 0.0, 1.0));
mesh.controlPoints.push(new Vector4(1.0, 0.0, 0.0, 1.0));
mesh.controlPoints.push(new Vector4(0.5, 1.0, 0.0, 1.0));

mesh.createPolygon(0, 1, 2);

const normals = mesh.createElement(
    VertexElementType.NORMAL,
    MappingMode.CONTROL_POINT,
    ReferenceMode.DIRECT
) as VertexElementNormal;

// setData() is the correct API — normals.data returns a defensive copy; pushing to it has no effect
normals.setData([
    new FVector3(0, 0, 1),
    new FVector3(0, 0, 1),
    new FVector3(0, 0, 1),
]);

node.entity = mesh;

const saveOpts = new GltfSaveOptions();
scene.save('triangle.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Triangle mesh saved to triangle.gltf');

Execute com ts-node:

npx ts-node triangle.ts

Problemas Comuns

IssueCauseFix
mesh.controlPoints.length é 0 após o pushMalha não referenciada por nenhum nóFaça o push antes de atribuir node.entity; a ordem não importa, mas verifique a referência
Exportação produz geometria vazianode.entity não atribuídoGaranta node.entity = mesh antes de chamar scene.save()
Incompatibilidade na contagem de normaisArray passado para setData() é mais curto que controlPointsAdicione uma entrada FVector3 por ponto de controle ao usar MappingMode.CONTROL_POINT
Visualizador glTF mostra malha pretaNormais apontando para dentroInverta a ordem de winding em createPolygon (por exemplo, 0, 2, 1) ou negue os vetores normais
TypeScript: propriedade ’normals.data’ não encontradaCaminho de importação erradoImporte VertexElementNormal de @aspose/3d/entities, não da raiz @aspose/3d

Perguntas Frequentes

Posso criar quads em vez de triângulos?
Sim. Passe quatro índices para createPolygon(0, 1, 2, 3). A biblioteca triangula quads durante a exportação para formatos que exigem triângulos (glTF, STL).

Qual é a diferença entre MappingMode.CONTROL_POINT e MappingMode.POLYGON_VERTEX?
CONTROL_POINT armazena um valor por vértice único. POLYGON_VERTEX armazena um valor por par polígono‑vértice, o que permite normais diferentes no mesmo vértice quando ele pertence a múltiplos polígonos (bordas duras).

Preciso triangular a malha antes de salvar em STL?
Não. A biblioteca lida com a triangulação automaticamente ao exportar para formatos que exigem triângulos. Você pode definir quads e n‑gons na malha e salvar diretamente em STL.

Como adiciono coordenadas UV? Use mesh.createElementUV(TextureMapping.Diffuse, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT) para criar um VertexElementUV, então chame setData([...]) com um array de valores FVector2 ou FVector3 — um por ponto de controle. O getter data retorna uma cópia; não faça push diretamente nele.

Posso criar várias malhas em uma única cena? Sim. Crie vários nós sob scene.rootNode e atribua um Mesh separado à propriedade entity de cada nó.

Veja Também

 Português