TypeScript'te 3B Sahne Grafiğini Nasıl Gezinilir

TypeScript'te 3B Sahne Grafiğini Nasıl Gezinilir

TypeScript için Aspose.3D FOSS’taki sahne grafiği bir ağaçtır Node kökü scene.rootNode. Traversal özyinelemelidir: her düğüm bir childNodes iterable ve isteğe bağlı bir entity özellik. Bu kılavuz, tüm ağacı nasıl dolaşacağınızı, varlık türlerini tanımlamayı ve mesh istatistiklerini toplamayı gösterir.

Önkoşullar

  • Node.js 18 veya daha yeni bir sürüm
  • TypeScript 5.0 veya daha yeni bir sürüm
  • @aspose/3d kuruldu

Adım Adım Kılavuz

Adım 1: Kurulum ve İçe Aktarma

Paketi kurun:

npm install @aspose/3d

Bu kılavuzda kullanılan sınıfları içe aktarın:

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

Scene ve Mesh temel sınıflardır. ObjLoadOptions yükleme örneğinde kullanılır; diğer formatlar için eşleşen seçenek sınıfını değiştirin.


Adım 2: Bir Dosyadan Sahne Yükleyin

Bir oluşturun Scene ve çağırın scene.open() bir dosya yolu ile. Biçim algılaması ikili sihirli sayılardan otomatik olarak yapılır, bu yüzden GLB, STL veya 3MF dosyaları için biçimi belirtmeniz gerekmez:

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

Ayrıca birinden yükleyebilirsiniz Buffer bellekte kullanarak scene.openFromBuffer(buffer, options); disk I/O’nun mevcut olmadığı sunucusuz boru hatlarında faydalıdır.


Adım 3: Rekürsif Bir Gezinme Fonksiyonu Yazın

Özyineleme tamamlandı childNodes standart bir desendir. Fonksiyon her düğümü derinlik öncelikli olarak ziyaret eder:

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

Bir mesh adıyla bir sahne için Cube, çıktı şu şekilde görünecek:

[-] 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 dır null grup düğümleri, kemikler ve konumlandırıcılar için. Bu constructor.name kontrol, herhangi bir varlık türü için çalışır: Mesh, Camera, Light, vb.


Adım 4: Her Düğümdeki Varlık Türüne Erişme

Varlık türüne göre işlem yapmak için, bir instanceof null korumasından sonra kontrol et:

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 erişmeden önce entity’nin bir polygon mesh olduğunu doğrulamanın en güvenli yoludur controlPoints, polygonCount, ya da vertex elemanları.


Adım 5: Düğümleri Varlık Türüne Göre Filtrele

Tam ağacı yazdırmadan yalnızca ağ (mesh) içeren düğümleri toplamak için, özyinelemeli bir biriktirici kullanın:

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

Fonksiyon isteğe bağlı bir results array, çağırıcıların birden fazla alt ağaçta sonuçları birleştirmek amacıyla önceden doldurabilmesi için.


Adım 6: Tüm Mesh’leri Topla ve Vertex Sayılarını Yazdır

Toplayıcıyı, her ağ (mesh) için istatistikleri yazdıracak şekilde genişletin:

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

İki ağ (mesh) içeren bir sahne için örnek çıktı:

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>

İpuçları ve En İyi Uygulamalar

  • Her zaman null kontrolü yap node.entity entity-özgü özelliklere erişmeden önce. Birçok düğüm, hiçbir entity taşımayan saf grup düğümüdür.
  • Kullan instanceof yerine constructor.name mantıksal yollar içinde type kontrolleri için. instanceof refactor-safe’dir; string karşılaştırması constructor.name minification ile bozulur.
  • Şu yöntemle dolaş for...of üzerinde childNodes: iterable tüm dizi boyutlarını güvenli bir şekilde işler. İleri uyumluluk için sayısal indekslemeyi önleyin.
  • Geçiş sırasında ağacı değiştirmekten kaçının: özyinelemeli çağrı içinde düğüm eklemeyin veya kaldırmayın. Önce sonuçları toplayın, ardından değiştirin.
  • Sonuçlar dizisini bir parametre olarak geçirin: bu, her özyinelemeli çağrıda yeni bir dizi tahsis edilmesini önler ve alt ağaç sonuçlarını birleştirmeyi kolaylaştırır.

Yaygın Sorunlar

SemptomNedenDüzeltme
childNodes şu üzerinde uzunluğu sıfır rootNodeModel yüklenmediGarantile scene.open() gezinmeden önce hatasız tamamlanmış
node.entity instanceof Mesh asla doğru değilYanlış Mesh import yoluİçe Aktar Mesh den @aspose/3d/entities, den değil @aspose/3d kök
Gezi, iç içe ağları kaçırıyorTüm alt öğelere yineleme yapılmıyorYinelemeli çağrının her öğeyi kapsadığından emin olun node.childNodes
mesh.controlPoints.length 0’dırMesh yüklendi ancak geometri içermiyorBoş gruplar için OBJ kaynağını kontrol edin; kullanın mesh.polygonCount ikincil bir kontrol olarak
Derin hiyerarşilerde yığın taşmasıÇok derin sahne ağacı (yüzlerce seviye)Özyinelemeyi, kullanarak açık bir yığınla değiştirin Array.push / Array.pop

Sık Sorulan Sorular

Yapıyor mu scene.rootNode kendi içinde bir varlık taşıyor mu? Hayır. Kök düğüm, kütüphane tarafından otomatik olarak oluşturulan bir kapsayıcıdır. Bir varlığı yoktur. Geometriniz ve diğer sahne nesneleriniz, bir veya daha fazla seviye aşağıdaki alt düğümlerde bulunur. rootNode.

Arasındaki fark nedir node.entity ve node.entities? node.entity tek bir birincil varlığı tutar (yaygın durum). Bazı eski FBX ve COLLADA dosyaları, birden fazla ekli varlık içeren düğümler üretebilir; bu durumda node.entities (çoğul) tam listeyi sağlar.

Derinlik öncelikli yerine genişlik öncelikli olarak dolaşabilir miyim? Evet. Özyinelemeli çağrı yerine bir kuyruk kullanın: push scene.rootNode bir diziye, ardından shift yaparak ve düğümleri işlerken her düğümün childNodes kuyruk kuyruğunun sonuna ekleyin.

Bu scene.open() senkron mu? Evet. scene.open() ve scene.openFromBuffer() her ikisi de dosya tamamen ayrıştırılana kadar çağıran iş parçacığını engeller. Olay döngüsünün yanıt vermesini sürdürmeniz gerekiyorsa, bunları bir işçi iş parçacığında sarın.

Bir düğümden dünya uzayı konumlarını nasıl alabilirim? Oku node.globalTransform; yalnızca okuma izni döndürür GlobalTransform tüm ata dönüşümlerinden oluşan dünya-uzayı matrisiniyle. Açık matris hesaplamaları için, şu fonksiyonu çağırın node.evaluateGlobalTransform(false).

Hangi varlık türleri mümkündür, şunların dışında Mesh? Camera, Light, ve özel iskelet/kemik varlıkları. Kontrol edin node.entity.constructor.name ya da kullan instanceof belirli sınıfı şu kaynaktan içe aktararak @aspose/3d.

Ayrıca Bakınız

 Türkçe