Arbeide med Scene‑grafen

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/3d

Sø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åKlasseRolle
SceneSceneToppnivå-beholder. Inneholder rootNode, animationClips, og assetInfo.
NodeNodeNavngitt tre-node. Kan ha undernoder, en enhet, en transformasjon og materialer.
EntitetMesh, 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 å konstruere Node direkte: createChildNode() kobler automatisk sammen foreldre‑barn‑forholdet og registrerer noden i treet.
  • Sjekk node.entity før du får tilgang til entitetsegenskaper: mange noder (gruppenoder, bein, lokatorer) har ingen enhet. Sørg alltid for en null‑sjekk eller instanceof test.
  • Sett translation på underordnede noder, ikke på mesh vertices: endrer transform.translation er ikke-destruktiv og kan komponeres med overordnede transformasjoner.
  • Foretrekk binaryMode = true for GLB: en enkelt .glb fil er lettere å distribuere, laste inn i nettlesere og importere til spillmotorer enn den splittede .gltf + .bin format.
  • Traverser via for...of over childNodes: unngå numerisk indeksering; bruk den iterable direkte for fremoverkompatibilitet.

Vanlige problemer

SymptomSannsynlig årsakLøsning
child.entity = mesh har ingen effekt på eksportEntitet tilordnet feil nodenivåTildel entity til bladnoden, ikke til en gruppenode
node.entity er alltid nullKun sjekker rootNode seg selvGå rekursivt inn i node.childNodes; rootNode har vanligvis ingen enhet
Transformasjon reflekteres ikke i GLB-viserenglobalTransform ikke oppdatertglobalTransform beregnes ved lagring; sett transform.translation før du kaller scene.save()
GLB lager en separat .bin sidecarbinaryMode standard er falseAngi saveOpts.binaryMode = true

Se også

 Norsk