Arbeide med Scene‑grafen
Alt 3D-innhold i Aspose.3D FOSS for TypeScript ligger inne i en Scene objekt organisert som et tre av Node objekter. Å forstå dette hierarkiet er grunnlaget for å bygge, laste inn og behandle enhver 3D-fil.
Installasjon
Installer pakken fra npm før du kjører noen av kodene i denne veiledningen:
npm install @aspose/3dSørg for at din tsconfig.json inkluderer "module": "commonjs" og "moduleResolution": "node" for korrekt understi-importoppløsning.
Konsepter for Scene‑grafen
Scene‑grafen har tre nivåer:
| Nivå | Klasse | Rolle |
|---|---|---|
| Scene | Scene | Toppnivå-beholder. Inneholder rootNode, animationClips, og assetInfo. |
| Node | Node | Navngitt tre-node. Kan ha undernoder, en enhet, en transformasjon og materialer. |
| Entitet | Mesh, Camera, Light, … | Innhold festet til en node. En node bærer maksimalt én enhet. |
Arvekjeden for hovedbyggesteinene er:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode opprettes automatisk. Du oppretter den ikke manuelt; du oppretter undernoder under den.
Step 1: Create a 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)
En ny Scene starter med en tom rotnode og ingen animasjonsklipp. Du bygger innhold ved å feste undernoder.
Steg 2: Legg til under‑noder
Bruk createChildNode() for å vokse treet. Metoden returnerer den nye Node, så du kan kjede videre kall fra ethvert nivå:
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)
Node‑navn er vilkårlige strenger. Navn trenger ikke være unike, men å bruke meningsfulle navn gjør traverseringskoden lettere å feilsøke.
Steg 3: Opprett et Mesh og angi vertex‑ene
Mesh er den primære geometriklassen. Legg til vertex‑posisjoner ved å skyve Vector4 verdier til mesh.controlPoints, så kall createPolygon() for å definere flater etter vertex‑indeks:
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 bruker homogene koordinater: den w komponent er 1 for posisjoner og 0 for retningsvektorer.
Step 4: Set Node Transforms
Hver node har en transform egenskap med translation, rotation, og scaling. Sett translation for å flytte noden relativt til sin forelder:
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 gir verdensromtransformasjonsmatrisen (kun lesbar), beregnet ved å sammenkjedet alle foreldertransformasjonene.
Steg 5: Gå gjennom treet
Skriv en rekursiv funksjon for å besøke hver node. Sjekk node.entity og node.childNodes på hvert nivå:
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);For hierarkiet som ble opprettet ovenfor, vil utdataene være:
[none]
parent [none]
child [Mesh]Rotnodens navn er en tom streng fordi Scene oppretter den uten navneargument.
Alltid beskytt tilgang til entiteten med en null‑sjekk før du kaster til en spesifikk type. Ikke hver node har en entitet.
Steg 6: Lagre til glTF eller GLB
Bruk GltfSaveOptions for å kontrollere utdataformatet. Sett binaryMode = true for å lage en enkelt selvstendig .glb fil; la den false for JSON .gltf + .bin sidecar-par:
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');Send GltfFormat.getInstance() som formatargument slik at biblioteket bruker riktig enkoder uavhengig av filendelsen.
Tips og beste praksis
- Bruk
createChildNode()i stedet for å konstruereNodedirekte:createChildNode()kobler automatisk sammen foreldre‑barn‑forholdet og registrerer noden i treet. - Sjekk
node.entityfør du får tilgang til entitetsegenskaper: mange noder (gruppenoder, bein, lokatorer) har ingen enhet. Sørg alltid for en null‑sjekk ellerinstanceoftest. - Sett
translationpå underordnede noder, ikke på mesh vertices: endrertransform.translationer ikke-destruktiv og kan komponeres med overordnede transformasjoner. - Foretrekk
binaryMode = truefor GLB: en enkelt.glbfil er lettere å distribuere, laste inn i nettlesere og importere til spillmotorer enn den splittede.gltf+.binformat. - Traverser via
for...ofoverchildNodes: unngå numerisk indeksering; bruk den iterable direkte for fremoverkompatibilitet.
Vanlige problemer
| Symptom | Sannsynlig årsak | Løsning |
|---|---|---|
child.entity = mesh har ingen effekt på eksport | Entitet tilordnet feil nodenivå | Tildel entity til bladnoden, ikke til en gruppenode |
node.entity er alltid null | Kun sjekker rootNode seg selv | Gå rekursivt inn i node.childNodes; rootNode har vanligvis ingen enhet |
| Transformasjon reflekteres ikke i GLB-viseren | globalTransform ikke oppdatert | globalTransform beregnes ved lagring; sett transform.translation før du kaller scene.save() |
GLB lager en separat .bin sidecar | binaryMode standard er false | Angi saveOpts.binaryMode = true |
Se også
- Funksjoner og funksjonalitet: full API-referanse for alle funksjonsområder.
- Formatstøtte: støttede 3D-formater, lese-/skriveevne og formatalternativer.
- Hvordan bygge et 3D-mesh programmatisk