Kā pārlūkot 3D ainas grafu TypeScript valodā

Kā pārlūkot 3D ainas grafu TypeScript valodā

Scēnas grafiks Aspose.3D FOSS priekš TypeScript ir koks no Node objektu, kura sakne ir scene.rootNode. Traversēšana ir rekursīva: katrs mezgls atklāj childNodes iterējamu un pēc izvēles entity īpašību. Šis ceļvedis parāda, kā pāriet cauri visam kokam, identificēt vienību tipus un savākt tīklu statistiku.

Priekšnosacījumi

  • Node.js 18 vai jaunāks
  • TypeScript 5.0 vai jaunāks
  • @aspose/3d instalēts

Solī pa solim ceļvedis

1. solis: Instalēt un importēt

Instalējiet paketi:

npm install @aspose/3d

Importējiet šajā ceļvedī izmantotās klases:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { Mesh } from '@aspose/3d/entities';

Scene un Mesh ir galvenās klases. ObjLoadOptions tiek izmantots ielādes piemērā; citām formām aizstājiet atbilstošo opciju klasi.


2. solis: Ielādēt ainu no faila

Izveidojiet Scene un izsauciet scene.open() ar faila ceļu. Formāta noteikšana ir automātiska, balstoties uz bināriem maģiskajiem skaitļiem, tāpēc jums nav jānorāda formāts GLB, STL vai 3MF failiem:

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

const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());

console.log(`Root node: "${scene.rootNode.name}"`);
console.log(`Top-level children: ${scene.rootNode.childNodes.length}`);

Jūs varat arī ielādēt no Buffer atmiņā, izmantojot scene.openFromBuffer(buffer, options); tas ir noderīgi serverless cauruļvados, kur nav pieejama diska I/O.


3. solis: rakstīt rekursīvu pārlūkošanas funkciju

Rekursija pār childNodes ir standarta paraugs. Funkcija apmeklē katru mezglu dziļuma pirmajā kārtībā:

function traverse(node: any, depth = 0): void {
    const indent = '  '.repeat(depth);
    const entityType = node.entity ? node.entity.constructor.name : '-';
    console.log(`${indent}[${entityType}] ${node.name}`);
    for (const child of node.childNodes) {
        traverse(child, depth + 1);
    }
}

traverse(scene.rootNode);

Scenā ar vienu mesh, kura nosaukums ir Cube, izvade izskatīsies šādi:

[-] RootNode
  [Mesh] Cube

<button class=“hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50” title=“Copy code”

<div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
<div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>

node.entity ir null grupas mezgliem, kauliem un lokatoriem. constructor.name pārbaude darbojas ar jebkuru vienību tipu: Mesh, Camera, Light utt.


Solis 4: Piekļūt vienības tipam katrā mezglā

Lai veiktu darbību, pamatojoties uz vienuma tipu, izmantojiet instanceof pārbaudi pēc nulles aizsargāšanas:

import { Mesh } from '@aspose/3d/entities';

function visitWithTypeCheck(node: any, depth = 0): void {
    const indent = '  '.repeat(depth);
    if (node.entity instanceof Mesh) {
        const mesh = node.entity as Mesh;
        console.log(`${indent}MESH "${node.name}": ${mesh.controlPoints.length} vertices`);
    } else if (node.entity) {
        console.log(`${indent}${node.entity.constructor.name} "${node.name}"`);
    } else {
        console.log(`${indent}GROUP "${node.name}"`);
    }
    for (const child of node.childNodes) {
        visitWithTypeCheck(child, depth + 1);
    }
}

visitWithTypeCheck(scene.rootNode);

instanceof Mesh ir drošākais veids, kā pārliecināties, ka vienība ir daudzstūra režģis, pirms piekļūt controlPoints, polygonCount vai virsotnes elementiem.


5. solis: Filtrēt mezglus pēc vienības tipa

Lai savāktu tikai mesh‑bearing nodes bez pilna koka izdrukāšanas, izmantojiet rekursīvu akumulatoru:

import { Mesh } from '@aspose/3d/entities';

function collectMeshes(
    node: any,
    results: Array<{ name: string; mesh: Mesh }> = []
): Array<{ name: string; mesh: Mesh }> {
    if (node.entity instanceof Mesh) {
        results.push({ name: node.name, mesh: node.entity as Mesh });
    }
    for (const child of node.childNodes) {
        collectMeshes(child, results);
    }
    return results;
}

const meshNodes = collectMeshes(scene.rootNode);
console.log(`Found ${meshNodes.length} mesh node(s)`);

Funkcija pieņem izvēles results masīvu, lai izsaucēji var to iepriekš aizpildīt, apvienojot rezultātus vairākos apakškokos.


Solis 6: Savākt visus režģus un izdrukāt virsotņu skaitus

Paplašiniet kolektoru, lai izdrukātu statistiku katram tīklam:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { Mesh } from '@aspose/3d/entities';

function collectMeshes(node: any, results: Array<{name: string, mesh: Mesh}> = []) {
    if (node.entity instanceof Mesh) {
        results.push({ name: node.name, mesh: node.entity as Mesh });
    }
    for (const child of node.childNodes) {
        collectMeshes(child, results);
    }
    return results;
}

const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());

const meshes = collectMeshes(scene.rootNode);
for (const { name, mesh } of meshes) {
    console.log(`${name}: ${mesh.controlPoints.length} vertices, ${mesh.polygonCount} polygons`);
}

Piemēra izvade divu režģu ainas gadījumā:

Cube: 8 vertices, 6 polygons
Sphere: 482 vertices, 480 polygons

<button class=“hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50” title=“Copy code”

<div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
<div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>

Padomi un labākās prakses

  • Vienmēr pārbaudiet null node.entity pirms piekļūstat entītijas specifiskām īpašībām. Daudzi mezgli ir tīri grupas mezgli, kas nesatur entītiju.
  • Izmantojiet instanceof pār constructor.name tipa pārbaudēm loģikas ceļos. instanceof ir drošs pārveidošanai; virknes salīdzinājums ar constructor.name sabrūk, ja tiek minificēts.
  • Iziet caur for...of pār childNodes: iterējams objekts droši apstrādā visus masīvu izmērus. Izvairieties no skaitliskās indeksēšanas, lai nodrošinātu nākotnes saderību.
  • Izvairieties no koka mutācijas traversēšanas laikā: nepievienojiet vai noņemiet mezglus rekursīvā izsaukumā. Vispirms savāciet rezultātus, pēc tam modificējiet.
  • Padodiet rezultātu masīvu kā parametru: tas novērš jauna masīva piešķiršanu katrā rekursīvajā izsaukumā un atvieglo apakškoka rezultātu apvienošanu.

Bieži sastopamās problēmas

SimptomsIemeslsRisinājums
childNodes ir nulles garuma uz rootNodeModelis nav ielādētsPārliecinieties, ka scene.open() ir pabeigts bez kļūdām pirms pārlūkošanas
node.entity instanceof Mesh nekad nav patiesiNekorekta Mesh importēšanas ceļšImportējiet Mesh no @aspose/3d/entities, nevis no @aspose/3d saknes
Pārlūkošana izlaida ligzdotus režģusNav rekursijas visos bērnosPārliecinieties, ka rekursīvā izsaukuma ietver katru elementu node.childNodes
mesh.controlPoints.length ir 0Režģis ielādēts, bet nesatur ģeometrijuPārbaudiet OBJ avotu tukšām grupām; kā sekundāru pārbaudi izmantojiet mesh.polygonCount
Steka pārplūde dziļās hierarhijāsĻoti dziļa ainas koks (simti līmeņu)Aizstājiet rekursiju ar eksplīcītu steku, izmantojot Array.push / Array.pop

Biežāk uzdotie jautājumi

Vai scene.rootNode pats nesatur objektu?
Nē. Saknes mezgls ir konteineris, kas izveidots automātiski bibliotēkas. Tam nav objekta. Jūsu ģeometrija un citi ainas objekti atrodas bērnu mezglos vienu vai vairākus līmeņus zem rootNode.

Kāda ir atšķirība starp node.entity un node.entities? node.entity satur vienu galveno vienību (parasti). Daži vecāki FBX un COLLADA faili var radīt mezglus ar vairākām pievienotām vienībām; šādā gadījumā node.entities (daudzskaitlis) nodrošina pilnu sarakstu.

Vai es varu pāriet platuma kārtībā, nevis dziļuma kārtībā?
Jā. Izmantojiet rindu nevis rekursīvu izsaukumu: push scene.rootNode masīvā, pēc tam shift un apstrādājiet mezglus, vienlaikus push katra mezgla childNodes rindas galā.

Vai scene.open() ir sinhronais?
Jā. scene.open() un scene.openFromBuffer() abi bloķē izsaucošo pavedienu, līdz fails ir pilnībā parsēts. Ievietojiet tos darbinieka pavedienā, ja jums jāuztur notikumu cilpa reaģējoša.

Kā es varu iegūt pasaules‑telpas pozīcijas no mezgla? Lasiet node.globalTransform; tas atgriež tikai lasāmu GlobalTransform ar pasaules‑telpas matricu, kas sastāv no visām priekšgājēju transformācijām. Lai veiktu tiešu matricas matemātiku, izsauciet node.evaluateGlobalTransform(false).

Kādi vienību veidi ir iespējamie, izņemot Mesh?
Camera, Light un pielāgotas skeleta/kaulu vienības. Pārbaudiet node.entity.constructor.name vai izmantojiet instanceof ar konkrēto klasi, importētu no @aspose/3d.

Skatīt arī

 Latviešu