Werken met de Scene Graph
Alle 3D-inhoud in Aspose.3D FOSS voor TypeScript bevindt zich binnen een Scene object georganiseerd als een boom van Node objecten. Het begrijpen van deze hiërarchie is de basis voor het bouwen, laden en verwerken van elk 3D‑bestand.
Installatie
Installeer het pakket van npm voordat je enige code in deze gids uitvoert:
npm install @aspose/3dZorg ervoor dat uw tsconfig.json bevat "module": "commonjs" en "moduleResolution": "node" voor correcte subpad‑importresolutie.
Concepten van de Scene Graph
De scene graph heeft drie lagen:
| Niveau | Klasse | Rol |
|---|---|---|
| Scène | Scene | Top‑niveau container. Bevat rootNode, animationClips, en assetInfo. |
| Knooppunt | Node | Naamgegeven boomknooppunt. Kan kindknooppunten, een entiteit, een transformatie en materialen hebben. |
| Entiteit | Mesh, Camera, Light, … | Inhoud gekoppeld aan een node. Een node bevat maximaal één entiteit. |
De overervingsketen voor de belangrijkste bouwblokken is:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode wordt automatisch aangemaakt. Je maakt het niet handmatig aan; je maakt onderliggende nodes aan.
Stap 1: Maak een Scene
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
Een nieuwe Scene begint met een lege rootnode en geen animatieclips. Je bouwt inhoud door onderliggende nodes te koppelen.
Stap 2: Voeg kind‑knooppunten toe
Gebruik createChildNode() om de boom te laten groeien. De methode retourneert de nieuwe Node, zodat je verdere aanroepen kunt ketenen vanaf elk niveau:
import { Scene } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
console.log(scene.rootNode.childNodes.length); // 1 (parent)
console.log(parent.childNodes.length); // 1 (child)
Knooppuntnamen zijn willekeurige strings. Namen hoeven niet uniek te zijn, maar het gebruik van betekenisvolle namen maakt de traversalcodes makkelijker te debuggen.
Stap 3: Maak een Mesh aan en stel vertices in
Mesh is de primaire geometrieklasse. Voeg vertex positions toe door te pushen Vector4 waarden in mesh.controlPoints, roep dan createPolygon() om vlakken te definiëren op basis van vertex-index:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4 } from '@aspose/3d/utilities';
const scene = new Scene();
const child = scene.rootNode.createChildNode('parent').createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3); // quad face using all four vertices
child.entity = mesh;
console.log(mesh.controlPoints.length); // 4
console.log(mesh.polygonCount); // 1
Vector4 gebruikt homogene coördinaten: de w component is 1 voor posities en 0 voor richtingsvectoren.
Stap 4: Stel knooptransformaties in
Elke knoop heeft een transform eigenschap met translation, rotation, en scaling. Stel translation om de knoop te verplaatsen ten opzichte van zijn ouder:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);globalTransform biedt de world-space transformatie-matrix (alleen-lezen), berekend door alle vooroudertransformaties te concatenaten.
Stap 5: Doorloop de boom
Schrijf een recursieve functie om elk knooppunt te bezoeken. Controleer node.entity en node.childNodes op elk niveau:
function traverse(node: any, depth = 0): void {
const indent = ' '.repeat(depth);
const entityType = node.entity ? node.entity.constructor.name : 'none';
console.log(`${indent}${node.name} [${entityType}]`);
for (const child of node.childNodes) {
traverse(child, depth + 1);
}
}
traverse(scene.rootNode);Voor de hierboven gemaakte hiërarchie zal de output zijn:
[none]
parent [none]
child [Mesh]De naam van de rootknooppunt is een lege string omdat Scene maakt het aan zonder naamargument.
Bescherm altijd de toegang tot een entity met een null‑check voordat je cast naar een specifiek type. Niet elk knooppunt bevat een entity.
Stap 6: Opslaan naar glTF of GLB
Gebruik GltfSaveOptions om het uitvoerformaat te regelen. Stel binaryMode = true in om een enkel zelfvoorzienend .glb bestand; laat het false voor de JSON .gltf + .bin sidecar-paar:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write a single .glb file
scene.save('scene.glb', GltfFormat.getInstance(), saveOpts);
console.log('Scene saved to scene.glb');Geef GltfFormat.getInstance() op als format-argument zodat de bibliotheek de juiste encoder gebruikt, ongeacht de bestandsextensie.
Tips en best practices
- Gebruik
createChildNode()in plaats van het construeren vanNodedirect:createChildNode()verbindt automatisch de ouder‑kindrelatie en registreert het knooppunt in de boom. - Controleer
node.entityvoordat u entiteitseigenschappen benadert: veel knooppunten (groepsknooppunten, botten, locators) hebben geen entiteit. Bescherm altijd met een null-controle ofinstanceoftest. - Instellen
translationop kindknooppunten, niet op mesh vertices:wijzigentransform.translationis niet-destructief en samenstelbaar met bovenliggende transformaties. - Voorkeur
binaryMode = truevoor GLB: een enkele.glbbestand is gemakkelijker te distribueren, te laden in browsers en te importeren in game-engines dan de gesplitste.gltf+.binformaat. - Doorloop via
for...ofoverchildNodes: vermijd numerieke indexering; gebruik de iterable direct voor toekomstige compatibiliteit.
Veelvoorkomende problemen
| Symptoom | Waarschijnlijke oorzaak | Oplossing |
|---|---|---|
child.entity = mesh heeft geen effect op export | Entiteit toegewezen aan verkeerd knooppuntniveau | Toewijzen entity naar het bladknooppunt, niet naar een groepsknooppunt |
node.entity is altijd null | Alleen controleren rootNode zichzelf | Recursief in node.childNodes; rootNode heeft meestal geen entiteit |
| Transformatie niet weergegeven in GLB-viewer | globalTransform niet bijgewerkt | globalTransform wordt berekend bij opslaan; stel transform.translation voor het aanroepen scene.save() |
GLB produceert een aparte .bin sidecar | binaryMode standaard op false | Instellen saveOpts.binaryMode = true |
Zie ook
- Functies en functionaliteiten: volledige API-referentie voor alle functiegebieden.
- Formaatondersteuning: ondersteunde 3D-formaten, lees-/schrijfmogelijkheden en formatopties.
- Hoe je een 3D-mesh programmeermatig bouwt.