Darbas su scenos grafu

Visas 3D turinys Aspose.3D FOSS TypeScript kalbai yra viduje vieno Scene objektas, organizuotas kaip medžio Node objektų. Šios hierarchijos supratimas yra pagrindas bet kokio 3D failo kūrimui, įkėlimui ir apdorojimui.

Įdiegimas

Įdiekite paketą iš npm prieš paleisdami bet kurį šio vadovo kodą:

npm install @aspose/3d

Įsitikinkite, kad jūsų tsconfig.json įtraukia "module": "commonjs" ir "moduleResolution": "node" teisingam subkelio importų sprendimui.

Scenos grafo koncepcijos

Scenos grafas turi tris lygius:

LygmuoKlasėVaidmuo
ScenaSceneAukščiausio lygio konteineris. Laiko rootNode, animationClips, ir assetInfo.
MazgasNodePavadintas medžio mazgas. Gali turėti vaikų mazgus, entitetą, transformaciją ir medžiagas.
EntitetasMesh, Camera, Light, …Turinis, prisegtas prie mazgo. Mazgas nešioja ne daugiau kaip vieną objektą.

Paveldėjimo grandinė pagrindiniams statybiniams blokams yra:

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

scene.rootNode sukuriamas automatiškai. Jūs jo nesukuriate rankiniu būdu; jūs kuriate vaikų mazgus po jo.

Žingsnis 1: Sukurti sceną

import { Scene } from '@aspose/3d';

const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)

Naujas Scene prasideda su tuščiu šakniniu mazgu ir be animacijos klipų. Jūs kuriate turinį prisegdami vaikų mazgus.

Žingsnis 2: Pridėti vaikų mazgus

Naudokite createChildNode() auginti medį. Metodas grąžina naują Node, todėl galite grandinti tolesnius kvietimus iš bet kurio lygio:

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)

Mazgo pavadinimai yra bet kokios eilutės. Pavadinimai neturi būti unikalūs, tačiau prasmingų pavadinimų naudojimas palengvina keliaujančio kodo derinimą.

Žingsnis 3: Sukurti Mesh ir nustatyti viršūnes

Mesh yra pagrindinė geometrijos klasė. Pridėkite viršūnių pozicijas stumdami Vector4 reikšmes į mesh.controlPoints, tada iškvieskite createPolygon() apibrėžti paviršius pagal viršūnių 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 naudoja homogenines koordinates: šio w komponentas yra 1 pozicijoms ir 0 krypties vektoriams.

Žingsnis 4: Nustatyti mazgo transformacijas

Kiekvienas mazgas turi transform savybę su translation, rotation, ir scaling. Nustatyti translation perkelti mazgą santykinai su jo tėvu:

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 pateikia pasaulio erdvės transformacijos matricą (tik skaitymui), apskaičiuotą sujungiant visas tėvų transformacijas.

Žingsnis 5: Pereiti medį

Parašykite rekursinę funkciją, kuri aplankytų kiekvieną mazgą. Patikrinkite node.entity ir node.childNodes kiekviename lygyje:

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

Aukščiau sukurtai hierarchijai išvestis bus:

 [none]
  parent [none]
    child [Mesh]

Šaknies mazgo pavadinimas yra tuščia eilutė, nes Scene jį sukuria be pavadinimo argumento.

Visada apsaugokite prieigą prie entiteto patikrinimu, ar jis nėra null, prieš konvertuojant į konkretų tipą. Ne kiekvienas mazgas turi entitetą.

Žingsnis 6: Išsaugoti į glTF arba GLB

Naudokite GltfSaveOptions norėdami valdyti išvesties formatą. Nustatykite binaryMode = true kad sukurtumėte vieną savarankišką .glb failą; palikite jį false JSON .gltf + .bin sidecar pora:

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

Paduokite GltfFormat.getInstance() kaip formato argumentą, kad biblioteka naudotų teisingą koduotuvą, nepriklausomai nuo failo plėtinio.

Patarimai ir geriausia praktika

  • Naudokite createChildNode() vietoj konstruojimo Node tiesiogiai: createChildNode() automatiškai sukuria tėvo-vaiko ryšį ir registruoja mazgą medyje.
  • Patikrinkite node.entity prieš prieinant prie objekto savybių: daugelis mazgų (grupės mazgai, kaulai, lokatoriai) neturi jokio objekto. Visada apsaugokite naudodami null patikrinimą arba instanceof testą.
  • Nustatyti translation vaikų mazguose, o ne tinklelio viršūnėse:modifikavimas transform.translation yra nekenksmingas ir suderinamas su tėvų transformacijomis.
  • Pirmenybę teikite binaryMode = true GLB formatui: vienas .glb failas yra lengviau platinti, įkelti į naršykles ir importuoti į žaidimų variklius nei suskaidytas .gltf + .bin formatas.
  • Naršyti per for...of virš childNodes: venkite skaitmeninio indeksavimo; naudokite iteruojamąjį tiesiogiai, kad išlaikytumėte suderinamumą ateityje.

Dažnos problemos

SimptomasTikėtina priežastisPataisa
child.entity = mesh neturi įtakos eksportoEntitetas priskirtas neteisingam mazgo lygiuiPriskirti entity į lapo mazgą, o ne į grupės mazgą
node.entity visada nullTik tikrinama rootNode patsRekursuoti į node.childNodes; rootNode paprastai neturi objekto
Transformacija neatsispindi GLB peržiūros programojeglobalTransform neatnaujintaglobalTransform apskaičiuojama išsaugojant; nustatyti transform.translation prieš iškviečiant scene.save()
GLB sukuria atskirą .bin šoninis failasbinaryMode numatytasis yra falseNustatyti saveOpts.binaryMode = true

Žr. taip pat

 Lietuvių