Rad s grafom scene

Sav 3D sadržaj u Aspose.3D FOSS za TypeScript nalazi se unutar Scene objekt organiziran kao stablo Node objekata. Razumijevanje ove hijerarhije temelj je za izgradnju, učitavanje i obradu bilo koje 3D datoteke.

Instalacija

Instalirajte paket s npm-a prije pokretanja bilo kojeg koda u ovom vodiču:

npm install @aspose/3d

Osigurajte da vaš tsconfig.json uključuje "module": "commonjs" i "moduleResolution": "node" za ispravno rješavanje podputeva uvoza.

Pojmovi grafova scene

Graf scene ima tri razine:

RazinaKlasaUloga
ScenaSceneKontejner najviše razine. Sadrži rootNode, animationClips, i assetInfo.
ČvorNodeImenovani čvor stabla. Može imati podčvorove, entitet, transformaciju i materijale.
EntitetMesh, Camera, Light, …Sadržaj priložen čvoru. Čvor nosi najviše jedan entitet.

Lanac nasljeđivanja za glavne građevne blokove je:

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

scene.rootNode se automatski stvara. Ne stvarate ga ručno; stvarate podčvorove pod njim.

Korak 1: Stvaranje 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 započinje s praznim korijenskim čvorom i bez animacijskih isječaka. Sadržaj gradite spajanjem podčvorova.

Korak 2: Dodajte čvorove djece

Koristite createChildNode() za rast stabla. Metoda vraća novi Node, tako da možete lančati daljnje pozive s bilo koje razine:

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štenje smislenih imena olakšava otklanjanje grešaka u kodu za traversiranje.

Korak 3: Stvorite mrežu i postavite vrhove

Mesh je primarna geometrijska klasa. Dodajte položaje vrhova gurajući Vector4 vrijednosti u mesh.controlPoints, zatim pozovite createPolygon() za definiranje površina 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 homogenog koordinatni sustav: the w komponenta je 1 za položaje i 0 za vektore smjera.

Korak 4: Postavite transformacije čvora

Svaki čvor ima transform svojstvo s translation, rotation, i scaling. Postavite translation za pomicanje čvora relativno 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 svjetskog prostora (samo za čitanje), izračunatu spajanjem svih transformacija pretka.

Korak 5: Prolazak kroz stablo

Napišite rekurzivnu funkciju koja posjećuje svaki čvor. Provjerite node.entity i node.childNodes na svakoj razini:

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]

Naziv korijenskog čvora je prazan niz jer Scene ga stvara bez argumenta za ime.

Uvijek zaštitite pristup entitetu provjerom na null prije kastanja u određeni tip. Nije svaki čvor nositelj entiteta.

Korak 6: Spremi u glTF ili GLB

Koristite GltfSaveOptions za kontrolu izlaznog formata. Postavite binaryMode = true za stvaranje jedne samostalne .glb datoteke; ostavite ga false za JSON .gltf + .bin par bočnog dodatka:

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

Proslijedite GltfFormat.getInstance() kao argument formata kako bi biblioteka koristila ispravan enkoder neovisno o ekstenziji datoteke.

Savjeti i najbolje prakse

  • Koristite createChildNode() umjesto izgradnje Node izravno: createChildNode() automatski uspostavlja odnos roditelj-dijete i registrira čvor u stablu.
  • Provjerite node.entity prije pristupa svojstvima entiteta: mnogo čvorova (grupni čvorovi, kosti, lokatori) ne nosi entitet. Uvijek zaštitite provjerom null vrijednosti ili instanceof test.
  • Postavi translation na podređenim čvorovima, a ne na vrhovima mreže: modificiranje transform.translation je nedestruktivan i sastavljiv s roditeljskim transformacijama.
  • Preferiraj binaryMode = true za GLB: jedan .glb datoteka je lakša za distribuciju, učitavanje u preglednicima i uvoz u game engineove od podijeljenog .gltf + .bin format.
  • Prođi putem for...of preko childNodes: izbjegavaj numeričko indeksiranje; koristi iterable izravno za buduću kompatibilnost.

Uobičajeni problemi

SimptomVjerojatni uzrokPopravi
child.entity = mesh nema učinka na izvozEntitet dodijeljen na pogrešnoj razini čvoraDodijeli entity do listnog čvora, a ne do grupnog čvora
node.entity je uvijek nullSamo provjeravanje rootNode samRekurzija u node.childNodes; rootNode obično nema entitet
Transformacija nije prikazana u GLB preglednikuglobalTransform nije ažuriranoglobalTransform se izračunava pri spremanju; postavi transform.translation prije poziva scene.save()
GLB generira zasebni .bin sidecarbinaryMode zadano je falsePostavi saveOpts.binaryMode = true

Vidi također

 Hrvatski