Wie man ein 3D‑Mesh programmgesteuert in TypeScript erstellt
Aspose.3D FOSS für TypeScript ermöglicht es Ihnen, 3D-Geometrie vollständig im Code zu erstellen, ohne eine Datei zu laden. Sie definieren Scheitelpunktpositionen als Kontrollpunkte, geben Polygonflächen über Indizes an und fügen optionale Scheitel-Elemente wie Normalen, UVs oder Scheitel-Farben hinzu. Das Ergebnis kann in jedes beschreibbare Format gespeichert werden: glTF, GLB, STL, FBX oder COLLADA.
Voraussetzungen
- Node.js 18 oder neuer
- TypeScript 5.0 oder neuer
@aspose/3dinstalliert (siehe Schritt 1)
Schritt-für-Schritt-Anleitung
Schritt 1: Installieren @aspose/3d
npm install @aspose/3dKeine nativen Add‑ons oder Systembibliotheken sind erforderlich. Das Paket enthält TypeScript‑Typdefinitionen.
Minimum tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true
}
}Schritt 2: Erstelle eine Szene und einen Knoten
Ein Scene ist der oberste Container. Alle Geometrie muss an einem Node innerhalb des Szenenbaums angehängt werden:
import { Scene } from '@aspose/3d';
const scene = new Scene();
const node = scene.rootNode.createChildNode('triangle');createChildNode(name) erstellt einen benannten Knoten und verbindet ihn als Kind des aktuellen Knotens. Das zurückgegebene Node‑Objekt ist der Ort, an dem Sie das Mesh in Schritt 7 anhängen.
Schritt 3: Mesh-Objekt erstellen
Mesh enthält Scheitelpunktpositionen und Polygon‑Definitionen. Erstelle ein solches mit einem optionalen Namen:
import { Mesh } from '@aspose/3d/entities';
const mesh = new Mesh('triangle');Das Mesh beginnt leer: keine Scheitelpunkte und keine Flächen. Sie fügen sie in den nächsten Schritten hinzu.
Schritt 4: Kontrollpunkte hinzufügen (Scheitelpunkte)
Kontrollpunkte sind die Scheitelpunktpositionen im lokalen Raum. Schieben Sie Vector4 Werte in mesh.controlPoints. Die vierte Komponente (w) ist 1 für Positionen:
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
Sie referenzieren diese Positionen über deren nullbasierten Index, wenn Sie Polygonflächen definieren.
Schritt 5: Polygonflächen erstellen
createPolygon() definiert ein Face, indem die Scheitelpunktindizes in Reihenfolge aufgelistet werden. Drei Indizes ergeben ein Dreieck:
mesh.createPolygon(0, 1, 2);Sie können auch Quads (vier Indizes) oder beliebige Polygone für Formate definieren, die sie unterstützen. Für glTF trianguliert die Bibliothek beim Export automatisch Quads und N‑Gons.
Schritt 6: Vertex‑Normalen hinzufügen
Normalen verbessern die Rendering‑Qualität. Verwenden Sie mesh.createElement(), um ein VertexElementNormal zu erstellen, sammeln Sie Normalenvektoren in einem Array und rufen Sie dann setData() auf, um sie zu speichern. Der data‑Getter gibt eine defensive Kopie zurück – das Hinzufügen zu ihr hat keine Wirkung. Verwenden Sie FVector3 (Single‑Precision‑Float) für Normaldaten, nicht 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 bedeutet ein Normal pro Scheitelpunkt. ReferenceMode.DIRECT bedeutet, dass das Datenarray direkt über den Polygon‑Scheitelpunkt‑Index indiziert wird.
Schritt 7: Mesh anhängen und als glTF speichern
Weisen Sie das Mesh dem Knoten über node.entity zu, dann speichern Sie die Szene:
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');Um stattdessen eine einzelne eigenständige .glb‑Datei zu erzeugen, setzen Sie saveOpts.binaryMode = true und ändern Sie die Ausgabedateierweiterung zu .glb.
Vollständiges Beispiel
Das Folgende ist das vollständige Skript, das alle oben genannten Schritte kombiniert:
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');Ausführen mit ts-node:
npx ts-node triangle.tsHäufige Probleme
| Issue | Cause | Fix |
|---|---|---|
mesh.controlPoints.length ist nach dem Push 0 | Mesh wird von keinem Knoten referenziert | Push vor der Zuweisung von node.entity; die Reihenfolge ist egal, aber die Referenz überprüfen |
| Export erzeugt leere Geometrie | node.entity nicht zugewiesen | Stellen Sie sicher, dass node.entity = mesh vor dem Aufruf von scene.save() vorhanden ist |
| Normalenanzahl stimmt nicht überein | Array, das an setData() übergeben wird, ist kürzer als controlPoints | Fügen Sie pro Kontrollpunkt einen FVector3‑Eintrag hinzu, wenn Sie MappingMode.CONTROL_POINT verwenden |
| glTF‑Viewer zeigt schwarzes Mesh | Normalen zeigen nach innen | Kehr die Windungsreihenfolge in createPolygon um (z. B. 0, 2, 1) oder negiere die Normalenvektoren |
| TypeScript: Eigenschaft ’normals.data’ nicht gefunden | Falscher Importpfad | Importieren Sie VertexElementNormal aus @aspose/3d/entities, nicht aus dem Wurzelverzeichnis @aspose/3d |
Häufig gestellte Fragen
Kann ich Quads anstelle von Dreiecken erstellen?
Ja. Übergeben Sie vier Indizes an createPolygon(0, 1, 2, 3). Die Bibliothek trianguliert Quads beim Export in Formate, die Dreiecke erfordern (glTF, STL).
Was ist der Unterschied zwischen MappingMode.CONTROL_POINT und MappingMode.POLYGON_VERTEX?CONTROL_POINT speichert einen Wert pro eindeutigen Scheitelpunkt. POLYGON_VERTEX speichert einen Wert pro Polygon‑Scheitelpunkt‑Paar, was unterschiedliche Normalen am selben Scheitelpunkt ermöglicht, wenn er zu mehreren Polygonen gehört (harte Kanten).
Muss ich das Mesh vor dem Speichern als STL triangulieren?
Nein. Die Bibliothek übernimmt die Triangulation automatisch beim Export in Formate, die Dreiecke erfordern. Sie können Quads und N‑Gons im Mesh definieren und direkt als STL speichern.
Wie füge ich UV-Koordinaten hinzu?
Verwenden Sie mesh.createElementUV(TextureMapping.Diffuse, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT), um ein VertexElementUV zu erstellen, und rufen Sie dann setData([...]) mit einem Array von FVector2‑ oder FVector3‑Werten auf — je einer pro Kontrollpunkt. Der data‑Getter gibt eine Kopie zurück; fügen Sie nicht direkt Elemente hinzu.
Kann ich mehrere Meshes in einer Szene erstellen?
Ja. Erstellen Sie mehrere Knoten unter scene.rootNode und weisen Sie jedem Knoten eine separate Mesh seiner entity‑Eigenschaft zu.