Rad sa grafom scene
Sav 3D sadržaj u Aspose.3D FOSS za TypeScript živi unutar Scene objekta organizovanog kao stablo Node objekata. Razumevanje ove hijerarhije je temelj za izgradnju, učitavanje i obradu bilo koje 3D datoteke.
Instalacija
Instalirajte paket sa npm pre pokretanja bilo kog koda u ovom vodiču:
npm install @aspose/3dOsigurajte da vaš tsconfig.json uključuje "module": "commonjs" i "moduleResolution": "node" za pravilno rešavanje uvoza podputanje.
Koncepti grafova scene
Graf scene ima tri nivoa:
| Nivo | Klasa | Uloga |
|---|---|---|
| Scena | Scene | Kontejner najvišeg nivoa. Sadrži rootNode, animationClips, i assetInfo. |
| Čvor | Node | Imenovani čvor stabla. Može imati podčvorove, entitet, transformaciju i materijale. |
| Entitet | Mesh, Camera, Light, … | Sadržaj prikačen čvoru. Čvor nosi najviše jedan entitet. |
Lanac nasleđivanja za glavne građevinske blokove je:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode se kreira automatski. Ne kreirate ga ručno; vi kreirate podčvorove ispod njega.
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)
Novi Scene počinje sa praznim korenskim čvorom i bez animacionih klipova. Sadržaj gradite prikačivanjem podčvorova.
Korak 2: Dodajte čvorove-dece
Koristite createChildNode() za rast drveta. Metod vraća novi Node, tako da možete lančati dalja poziva sa bilo kog nivoa:
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)
Imena čvorova su proizvoljni stringovi. Imena ne moraju biti jedinstvena, ali korišćenje smislenih imena olakšava debagovanje koda za traversiranje.
Korak 3: Kreirajte Mesh i postavite vertekse
Mesh je primarna klasa geometrije. Dodajte pozicije vrhova tako što ćete gurnuti Vector4 vrednosti u mesh.controlPoints, zatim pozovite createPolygon() da definišete površine po indeksu vrha:
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 koristi homogenе koordinate: komponenta w komponenta je 1 za pozicije i 0 za vektore pravca.
Step 4: Set Node Transforms
Svaki čvor ima transform svojstvo sa translation, rotation, i scaling. Postavi translation da pomeri čvor relativno u odnosu na njegovog roditelja:
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 pruža matricu transformacije u svetskom prostoru (samo za čitanje), izračunatu spajanjem svih transformacija pretka.
Korak 5: Prolazak kroz stablo
Napišite rekurzivnu funkciju koja posećuje svaki čvor. Proverite node.entity i node.childNodes na svakom nivou:
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);Za hijerarhiju kreiranu iznad, izlaz će biti:
[none]
parent [none]
child [Mesh]Ime korenskog čvora je prazna niska jer Scene kreira ga bez argumenta za ime.
Uvek zaštitite pristup entitetu proverom na null pre kastovanja u određeni tip. Nije svaki čvor nosi entitet.
Korak 6: Sačuvajte u glTF ili GLB
Koristite GltfSaveOptions za kontrolu formata izlaza. Postavite binaryMode = true da proizvedete jedan samostalni .glb fajl; ostavite ga false za 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');Prosledi GltfFormat.getInstance() kao argument formata kako biblioteka koristi ispravan enkoder bez obzira na ekstenziju fajla.
Saveti i najbolje prakse
- Koristi
createChildNode()umesto da konstrušešNodedirektno:createChildNode()automatski uspostavlja odnos roditelj-dete i registruje čvor u stablu. - Proveri
node.entitypre nego što pristupiš svojstvima entiteta: mnogi čvorovi (grupni čvorovi, kosti, lokatori) nemaju entitet. Uvek proveravajte null vrednost iliinstanceoftest. - Postavi
translationna podređene čvorove, a ne na vrhove mreže: modifikovanjetransform.translationje nedestruktivan i može se kombinovati sa transformacijama roditelja. - Preferirajte
binaryMode = trueza GLB: jedan.glbdatoteka je lakše distribuirati, učitavati u pregledačima i uvoziti u game engine‑ove nego podeljeni.gltf+.binformat. - Prođite putem
for...ofprekochildNodes: izbegavajte numeričko indeksiranje; koristite iterable direktno za unapređenu kompatibilnost.
Uobičajeni problemi
| Simptom | Verovatni uzrok | Ispravi |
|---|---|---|
child.entity = mesh nema efekta na izvoz | Entitet dodeljen pogrešnom nivou čvora | Dodeli entity na list čvor, a ne na grupni čvor |
node.entity je uvek null | Samo proverava rootNode sam | Rekurzija u node.childNodes; rootNode obično nema entitet |
| Transformacija se ne odražava u GLB pregledniku | globalTransform nije ažurirano | globalTransform se izračunava pri čuvanju; postavi transform.translation pre poziva scene.save() |
GLB proizvodi zaseban .bin sidecar | binaryMode podrazumevano je false | Postavi saveOpts.binaryMode = true |
Vidi takođe
- Karakteristike i funkcionalnosti: potpuna API referenca za sve oblasti funkcija.
- Podrška za formate: podržani 3D formati, mogućnost čitanja/pisanja i opcije formata.
- Kako programatski izgraditi 3D mesh.