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/3dtelepí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/3dImportá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.entityaz 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-tconstructor.namehelyett típusellenőrzésekhez a logikai útvonalakon.instanceofrefaktorálásbiztos; aconstructor.name-on végzett karakterlánc-összehasonlítás a minifikálás során hibát okoz. - Navigáljon
for...of-velchildNodeshelyett: 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ünet | Ok | Javítás |
|---|---|---|
childNodes nulla hosszú a rootNode esetén | A modell nincs betöltve | Győ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 igaz | Helytelen Mesh import útvonal | Importá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ókat | Nem rekurzióval járja be az összes gyermeket | Győződjön meg róla, hogy a rekurzív hívás lefedi a node.childNodes minden elemét |
mesh.controlPoints.length 0 | A háló betöltve, de nem tartalmaz geometriát | Ellenő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én | Nagyon 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.