Práca so scénovým grafom

Všetok 3D obsah v Aspose.3D FOSS pre TypeScript sa nachádza v Scene objekte usporiadanom ako strom Node objektov. Pochopenie tejto hierarchie je základom pre tvorbu, načítanie a spracovanie akéhokoľvek 3D súboru.

Inštalácia

Nainštalujte balík z npm pred spustením akéhokoľvek kódu v tomto sprievodcovi:

npm install @aspose/3d

Uistite sa, že váš tsconfig.json obsahuje "module": "commonjs" a "moduleResolution": "node" pre správne riešenie importu podcesty.

Koncepty scénového grafu

Scénový graf má tri úrovne:

ÚroveňTriedaÚloha
ScénaSceneKontajner najvyššej úrovne. Obsahuje rootNode, animationClips, a assetInfo.
UzolNodePomenovaný uzol stromu. Môže mať podriadené uzly, entitu, transformáciu a materiály.
EntitaMesh, Camera, Light, …Obsah pripojený k uzlu. Uzol nesie najviac jednu entitu.

Dedičný reťazec pre hlavné stavebné bloky je:

A3DObject
  └─ SceneObject
       ├─ Node          (tree structure)
       └─ Entity
            └─ Geometry
                 └─ Mesh   (polygon geometry)

scene.rootNode sa vytvára automaticky. Nevytvárate ho ručne; vytvárate pod ním podriadené uzly.

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)

Nový Scene začína s prázdnym koreňovým uzlom a žiadnymi animačnými klipmi. Obsah vytvárate pripojovaním podriadených uzlov.

Krok 2: Pridať podriadené uzly

Použiť createChildNode() na rast stromu. Metóda vracia nový Node, takže môžete reťaziť ďalšie volania z akejkoľvek úrovne:

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)

Názvy uzlov sú ľubovoľné reťazce. Názvy nemusia byť jedinečné, ale použitie zmysluplných názvov uľahčuje ladenie kódu prechádzajúceho stromom.

Krok 3: Vytvoriť sieť (Mesh) a nastaviť vrcholy

Mesh je primárna trieda geometrie. Pridajte pozície vrcholov pomocou vkladania Vector4 hodnôt do mesh.controlPoints, potom zavolajte createPolygon() na definovanie plôch podľa indexu vrchola:

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 používa homogénne súradnice: w komponent je 1 pre pozície a 0 pre smerové vektory.

Step 4: Set Node Transforms

Každý uzol má transform vlastnosť s translation, rotation, a scaling. Nastavte translation na presunutie uzla relatívne k jeho rodičovi:

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 poskytuje maticu transformácie vo svetovom priestore (iba na čítanie), vypočítanú zreťazení všetkých transformácií predkov.

Krok 5: Prejdi strom

Napíšte rekurzívnu funkciu na prechádzanie každého uzla. Skontrolujte node.entity a node.childNodes na každej úrovni:

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

Pre hierarchiu vytvorenú vyššie bude výstup:

 [none]
  parent [none]
    child [Mesh]

Názov koreňového uzla je prázdny reťazec, pretože Scene vytvára ho bez argumentu názvu.

Vždy chráňte prístup k entite kontrolou na null pred pretypovaním na konkrétny typ. Nie každý uzol nesie entitu.

Krok 6: Uložiť do glTF alebo GLB

Použite GltfSaveOptions na ovládanie výstupného formátu. Nastavte binaryMode = true na vytvorenie jedného samostatného .glb súboru; ponechajte ho false pre JSON .gltf + .bin párový sidecar:

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

Prejdite GltfFormat.getInstance() ako argument formátu, aby knižnica použila správny enkóder bez ohľadu na príponu súboru.

Tipy a osvedčené postupy

  • Použite createChildNode() namiesto konštruovania Node priamo: createChildNode() automaticky prepojí vzťah rodič-dieťa a zaregistruje uzol v strome.
  • Skontrolujte node.entity pred prístupom k vlastnostiam entity.: mnoho uzlov (skupinové uzly, kosti, lokátory) neobsahuje žiadny objekt. Vždy ich chráňte kontrolou na null alebo instanceof testom.
  • Nastaviť translation na podriadených uzloch, nie na vrcholoch siete: modifikácia transform.translation je nedestruktívny a skladateľný s rodičovskými transformáciami.
  • Preferovať binaryMode = true pre GLB: jediný .glb súbor je jednoduchší na distribúciu, načítanie v prehliadačoch a import do herných enginov než rozdelený .gltf + .bin formát.
  • Prechádzať cez for...of nad childNodes: vyhnite sa číselnému indexovaniu; použite iterovateľ priamo pre budúcu kompatibilitu.

Bežné problémy

SymptómPravdepodobná príčinaOprava
child.entity = mesh nemá žiadny vplyv na exportEntita priradená na nesprávnu úroveň uzlaPriradiť entity na listový uzol, nie na skupinový uzol
node.entity je vždy nullIba kontrola rootNode samoRekurzívne do node.childNodes; rootNode zvyčajne nemá entitu
Transformácia sa neodráža v prehliadači GLBglobalTransform neaktualizovanéglobalTransform sa vypočíta pri uložení; nastaviť transform.translation pred volaním scene.save()
GLB vytvára samostatný .bin sidecarbinaryMode predvolene je falseNastaviť saveOpts.binaryMode = true

Pozri tiež

 Slovenčina