Hogyan bejárjuk a 3D jelenet gráfot TypeScript-ben

Hogyan bejárjuk a 3D jelenet gráfot TypeScript-ben

A TypeScript-hez készült Aspose.3D FOSS jelenetgrafikonja egy Node objektumokból álló fa, amelynek gyökere scene.rootNode. A bejárás rekurzív: minden csomópont egy childNodes iterálható elemet és egy opcionális entity tulajdonságot tesz elérhetővé. Ez az útmutató bemutatja, hogyan lehet bejárni az egész fát, azonosítani az entitástípusokat, és összegyűjteni a hálózati statisztikákat.

Előfeltételek

  • Node.js 18 vagy újabb
  • TypeScript 5.0 vagy újabb
  • @aspose/3d telepítve

Lépésről‑lépésre útmutató

1. lépés: Telepítés és importálás

Telepítse a csomagot:

npm install @aspose/3d

Importáld a útmutatóban használt osztályokat:

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

Scene és Mesh a fő osztályok. ObjLoadOptions a betöltési példában használatos; cserélje le a megfelelő opciók osztályra más formátumok esetén.


2. lépés: Jelenet betöltése fájlból

Hozzon létre egy Scene-t, és hívja meg a scene.open()-t egy fájl útvonallal. A formátumdetektálás automatikus a bináris varázsszámok alapján, így nem kell megadnia a formátumot a GLB, STL vagy 3MF fájlokhoz:

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

Memóriában is betöltheti a Buffer-t a scene.openFromBuffer(buffer, options) használatával; hasznos szerver nélküli csővezetékekben, ahol a lemez I/O nem áll rendelkezésre.


3. lépés: Rekurzív bejárási függvény írása

A childNodes feletti rekurzió a szabványos minta. A függvény mélységi bejárással látogatja meg minden csomópontot:

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

Egy Cube nevű hálóval rendelkező jelenet esetén a kimenet a következőképpen néz ki:

[-] 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 null a csoportcsomópontok, csontok és lokátorok számára. A constructor.name ellenőrzés bármely entitástípusra működik: Mesh, Camera, Light, stb.


4. lépés: Az entitástípus elérése minden csomóponton

Az entitás típusa alapján történő művelethez használjon egy instanceof ellenőrzést a null-ellenőrzés után:

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 a legbiztonságosabb módja annak, hogy megerősítsük, hogy az entitás poligon háló, mielőtt hozzáférnénk controlPoints, polygonCount vagy a csúcs elemekhez.


5. lépés: Csomópontok szűrése entitástípus szerint

A teljes fa kiírása nélkül csak a hálót tartalmazó csomópontok összegyűjtéséhez használjon rekurzív akkumulátort:

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

A függvény opcionális results tömböt fogad, hogy a hívók előre feltölthessék azt a több alkönyvtár eredményeinek egyesítéséhez.


6. lépés: Gyűjtse össze az összes hálót és írja ki a csúcsok számát

Bővítse a gyűjtőt, hogy minden hálózatra vonatkozó statisztikákat nyomtasson:

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

Példa kimenet egy két háló jelenethez:

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>

Tippek és legjobb gyakorlatok

  • Mindig végezzen null-ellenőrzést node.entity az entitás-specifikus tulajdonságok elérése előtt. Sok csomópont tisztán csoportcsomópont, amely nem hordoz entitást.
  • Használja instanceof-t constructor.name helyett típusellenőrzésekhez a logikai útvonalakon. instanceof refaktorálásbiztos; a constructor.name-on végzett karakterlánc-összehasonlítás a minifikálás során hibát okoz.
  • Navigáljon for...of-vel childNodes helyett: az iterálható biztonságosan kezeli az összes tömbméretet. Kerülje a numerikus indexelést a jövőbeli kompatibilitás érdekében.
  • Kerülje a fa módosítását a bejárás során: ne adjon hozzá vagy távolítson el csomópontokat a rekurzív híváson belül. Először gyűjtse össze az eredményeket, majd módosítson.
  • Adjon át egy eredmény tömböt paraméterként: ez megakadályozza, hogy minden rekurzív hívásnál új tömböt foglaljon le, és megkönnyíti az alfa eredmények egyesítését.

Gyakori problémák

TünetOkJavítás
childNodes nulla hosszú a rootNode eseténA modell nincs betöltveGyőződjön meg róla, hogy a scene.open() hiba nélkül befejeződött a bejárás előtt
node.entity instanceof Mesh soha nem igazHelytelen Mesh import útvonalImportálja a Mesh-t a @aspose/3d/entities-ből, ne a @aspose/3d gyökeréből
A bejárás kihagyja a beágyazott hálókatNem rekurzióval járja be az összes gyermeketGyőződjön meg róla, hogy a rekurzív hívás lefedi a node.childNodes minden elemét
mesh.controlPoints.length 0A háló betöltve, de nem tartalmaz geometriátEllenőrizze az OBJ forrást üres csoportokért; használja a mesh.polygonCount-t másodlagos ellenőrzésként
Verem túlcsordulás mély hierarchiák eseténNagyon mély jelenetfa (száz szint)Cserélje le a rekurziót egy explicit veremre a Array.push / Array.pop használatával

Gyakran Ismételt Kérdések

A scene.rootNode maga hordoz-e entitást?
Nem. A gyökércsomópont egy a könyvtár által automatikusan létrehozott tároló. Nincs entitása. A geometria és egyéb jelenetobjektumok gyermekcsomópontokon élnek, egy vagy több szinttel a rootNode alatt.

Mi a különbség a node.entity és a node.entities között? node.entity tartalmazza az egyetlen elsődleges entitást (a gyakori eset). Néhány régebbi FBX és COLLADA fájl több csatolt entitással rendelkező csomópontokat hozhat létre; ebben az esetben a node.entities (többes szám) biztosítja a teljes listát.

Bejárhatok szélességi sorrendben a mélységi helyett?
Igen. Használjon queue-t a rekurzív hívás helyett: push scene.rootNode egy tömbbe, majd shiftelje és dolgozza fel a csomópontokat, miközben minden csomópont childNodes‑jét a queue végére push‑olja.

Szinkronos-e scene.open()?
Igen. scene.open() és scene.openFromBuffer() is blokkolják a hívó szálat, amíg a fájl teljesen be nem olvasásra kerül. Csomagold őket egy munkaszálba, ha az eseményciklust responszívnek kell tartani.

Hogyan kapok világtérbeli pozíciókat egy csomópontból?
Olvassa el node.globalTransform; ez egy csak olvasható GlobalTransform‑t ad vissza a világtér mátrixszal, amely az összes ős transzformációból áll össze. Kifejezett mátrix számításhoz hívja meg a node.evaluateGlobalTransform(false)‑t.

Milyen entitástípusok lehetségesek a Mesh mellett?
Camera, Light, és egyedi skeleton/bone entitások. Ellenőrizd a node.entity.constructor.name vagy használd a instanceof a @aspose/3d‑ből importált konkrét osztállyal.

Lásd még

 Magyar