Com crear una malla 3D programàticament amb TypeScript

Com crear una malla 3D programàticament amb TypeScript

Aspose.3D FOSS per a TypeScript et permet crear geometria 3D completament en codi sense carregar cap fitxer. Definixes les posicions dels vèrtexs com a punts de control, especifiques les cares dels polígons per índex i adjuntes elements opcionals del vèrtex com ara normals, UVs o colors del vèrtex. El resultat es pot desar a qualsevol format d’escriptura: glTF, GLB, STL, FBX o COLLADA.

Requisits previs

  • Node.js 18 o posterior
  • TypeScript 5.0 o posterior
  • @aspose/3d instal·lat (vegeu el Pas 1)

Guia pas a pas

Pas 1: Instal·la @aspose/3d

npm install @aspose/3d

No es requereixen complements natius ni biblioteques del sistema. El paquet inclou definicions de tipus TypeScript.

Mínim tsconfig.json:

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

Pas 2: Crea una Escena i un Node

Un Scene és el contenidor de nivell superior. Tota la geometria ha d’estar adjunta a un Node dins de l’arbre d’escena:

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

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

createChildNode(name) crea un node anomenat i el connecta com a fill del node actual. L’objecte Node retornat és on adjuntareu la malla al pas 7.


Pas 3: Crea un objecte Mesh

Mesh conté posicions de vèrtex i definicions de polígons. Construeix-ne un amb un nom opcional:

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

const mesh = new Mesh('triangle');

La malla comença buida: sense vèrtexs i sense cares. Els afegeixes en els passos següents.


Pas 4: Afegeix punts de control (Vèrtexs)

Els punts de control són les posicions dels vèrtexs en l’espai local. Empenyeu els valors Vector4 a mesh.controlPoints. El quart component (w) és 1 per a les posicions:

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

Feu referència a aquestes posicions pel seu índex basat en zero en definir les cares del polígon.


Pas 5: Crear cares de polígon

createPolygon() defineix una cara enumerant els índexs dels vèrtexs en ordre. Tres índexs formen un triangle:

mesh.createPolygon(0, 1, 2);

També podeu definir quads (quatre índexs) o polígons arbitràris per a formats que els admeten. Per a glTF, la biblioteca triangul·larà automàticament els quads i els n‑gons en exportar.


Pas 6: Afegir normals de vèrtex

Les normals milloren la qualitat del renderitzat. Utilitzeu mesh.createElement() per crear una VertexElementNormal, recolliu vectors normals en una matriu i, a continuació, crideu setData() per emmagatzemar‑los. El getter data retorna una còpia defensiva — afegir elements a ella no té cap efecte. Utilitzeu FVector3 (float de precisió simple) per a les dades normals, no 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 una normal per vèrtex. ReferenceMode.DIRECT significa que la matriu de dades està indexada directament per l’índex del vèrtex del polígon.


Pas 7: Adjunta la malla i desa a glTF

Assigna la malla al node mitjançant node.entity, i després desa l’escena:

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');

Per generar un únic fitxer .glb autocontingut, estableix saveOpts.binaryMode = true i canvia l’extensió del fitxer de sortida a .glb.

Exemple complet

El següent és l’script complet que combina tots els passos anteriors:

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');

Executa amb ts-node:

npx ts-node triangle.ts

Problemes comuns

IssueCauseFix
mesh.controlPoints.length és 0 després del pushMalla no referenciada per cap nodeFes el push abans d’assignar node.entity; l’ordre no importa, però verifica la referència
L’exportació produeix geometria buidanode.entity no assignatAssegura’t que node.entity = mesh estigui present abans de cridar scene.save()
Desajust del recompte de normalsL’array passat a setData() és més curt que controlPointsAfegeix una entrada FVector3 per punt de control quan s’utilitza MappingMode.CONTROL_POINT
El visualitzador glTF mostra una malla negraNormals apuntant cap a l’interiorInverteix l’ordre de winding a createPolygon (p. ex., 0, 2, 1) o nega els vectors normals
TypeScript: propietat ’normals.data’ no trobadaCamí d’importació incorrecteImporta VertexElementNormal des de @aspose/3d/entities, no des de l’arrel @aspose/3d

Preguntes freqüents

Puc crear quads en lloc de triangles? Sí. Passeu quatre índexs a createPolygon(0, 1, 2, 3). La biblioteca triangula els quads durant l’exportació a formats que requereixen triangles (glTF, STL).

Quina és la diferència entre MappingMode.CONTROL_POINT i MappingMode.POLYGON_VERTEX?
CONTROL_POINT emmagatzema un valor per vèrtex únic. POLYGON_VERTEX emmagatzema un valor per parella polígon‑vèrtex, la qual cosa permet normals diferents al mateix vèrtex quan pertany a diversos polígons (vores dures).

Cal que trianguli la malla abans de desar a STL?
No. La biblioteca gestiona la triangulació automàticament quan s’exporta a formats que requereixen triangles. Podeu definir quads i n-gons a la malla i desar a STL directament.

Com afegir coordenades UV?
Utilitzeu mesh.createElementUV(TextureMapping.Diffuse, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT) per crear un VertexElementUV, després crideu setData([...]) amb una matriu de valors FVector2 o FVector3 — un per punt de control. El getter data retorna una còpia; no hi afegiu elements directament.

Puc crear diverses malles en una escena?
Sí. Creeu diversos nodes sota scene.rootNode i assigneu un Mesh separat a la propietat entity de cada node.

Vegeu també

 Català