Python içinde 3D Sahne Grafiğini Nasıl Gezinilir

Python içinde 3D Sahne Grafiğini Nasıl Gezinilir

Aspose.3D FOSS içindeki sahne grafiği bir ağaçtır Node kökü scene.root_node. OBJ, glTF, STL, COLLADA veya 3MF’den yüklenmiş olsun, her 3D dosyası aynı ağaç yapısını üretir. Onu nasıl dolaşacağınızı bilmek, geometriyi incelemenizi, çokgenleri saymanızı, nesneleri türe göre filtrelemenizi ve karmaşık bir sahnenin belirli bölümlerini işlemenizi sağlar.

Adım Adım Kılavuz

Adım 1: Kurulum ve İçe Aktarma

PyPI’dan Aspose.3D FOSS’ı kurun:

pip install aspose-3d-foss

İhtiyacınız olan sınıfları içe aktarın:

from aspose.threed import Scene
from aspose.threed.entities import Mesh

Tüm public sınıflar şunun altında bulunur aspose.threed veya alt paketlerinde (aspose.threed.entities, aspose.threed.utilities).


Adım 2: Bir Dosyadan Sahne Yükleyin

Statik Scene.from_file() metodunu, desteklenen herhangi bir formatı açmak için kullanın. Format, dosya uzantısından otomatik olarak algılanır:

scene = Scene.from_file("model.gltf")

Ayrıca açık yükleme seçenekleriyle de açabilirsiniz:

from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions

options = ObjLoadOptions()
options.enable_materials = True

scene = Scene()
scene.open("model.obj", options)

Yükleme sonrası, scene.root_node ağacın köküdür. Tüm içe aktarılan düğümler bu düğümün çocuğu ya da torunudur.


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

En basit gezinme, derinlik öncelikli sırada her düğümü ziyaret eder:

from aspose.threed import Scene
from aspose.threed.entities import Mesh

def traverse(node, depth=0):
    prefix = "  " * depth
    entity_name = type(node.entity).__name__ if node.entity else "-"
    print(f"{prefix}[{entity_name}] {node.name}")
    for child in node.child_nodes:
        traverse(child, depth + 1)

scene = Scene.from_file("model.gltf")
traverse(scene.root_node)

Örnek çıktı:

[-]
  [-] Armature
    [Mesh] Body
    [Mesh] Eyes
  [-] Ground
    [Mesh] Plane

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

Not: Kök düğümün boş bir adı vardır (""), bu yüzden ilk satır gösterir [-] adından sonra bir şey yok.

node.child_nodes ekleme sırasına göre çocukları döndürür (içe aktarıcı ya da kullanıcının eklediği sıra).


Adım 4: Her Düğümde Varlık Özelliklerine Erişin

Kullan node.entity bir düğüme eklenmiş ilk varlığı almak için, ya da node.entities hepsini yinelemek için. Biçim-özel özelliklerine erişmeden önce türü kontrol edin:

from aspose.threed import Scene
from aspose.threed.entities import Mesh

def print_entity_details(node, depth=0):
    indent = "  " * depth
    for entity in node.entities:
        if isinstance(entity, Mesh):
            mesh = entity
            print(f"{indent}Mesh '{node.name}':")
            print(f"{indent}  vertices  : {len(mesh.control_points)}")
            print(f"{indent}  polygons  : {mesh.polygon_count}")
            print(f"{indent}  cast_shadows   : {mesh.cast_shadows}")
            print(f"{indent}  receive_shadows: {mesh.receive_shadows}")
    for child in node.child_nodes:
        print_entity_details(child, depth + 1)

scene = Scene.from_file("model.gltf")
print_entity_details(scene.root_node)

node.transform.translation, node.transform.rotation, ve node.transform.scaling yerel uzay dönüşümünü verir. node.global_transform değerlendirilmiş dünya-uzayı sonucunu verir (ile global_transform.scale dünya-uzayı ölçeği için).


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

Yalnızca belirli varlık türleri üzerinde çalışmak için, bir isinstance gezinme içinde bir koruma ekleyin:

from aspose.threed import Scene
from aspose.threed.entities import Mesh

def find_mesh_nodes(node, results=None):
    if results is None:
        results = []
    for entity in node.entities:
        if isinstance(entity, Mesh):
            results.append(node)
            break   # One match per node is enough
    for child in node.child_nodes:
        find_mesh_nodes(child, results)
    return results

scene = Scene.from_file("model.gltf")
mesh_nodes = find_mesh_nodes(scene.root_node)
print(f"Found {len(mesh_nodes)} mesh node(s)")
for n in mesh_nodes:
    print(f"  {n.name}")

Bu desen toplu işlemler için faydalıdır: her mesh düğümüne bir dönüşüm uygulamak, materyalleri değiştirmek veya alt ağaçları dışa aktarmak.


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

Mesh istatistiklerini tek bir geçişte toplulaştır:

from aspose.threed import Scene
from aspose.threed.entities import Mesh

def collect_meshes(node, results=None):
    if results is None:
        results = []
    if isinstance(node.entity, Mesh):
        results.append((node.name, node.entity))
    for child in node.child_nodes:
        collect_meshes(child, results)
    return results

scene = Scene.from_file("model.gltf")
meshes = collect_meshes(scene.root_node)

print(f"Total meshes: {len(meshes)}")
total_verts = 0
total_polys = 0

for name, mesh in meshes:
    verts = len(mesh.control_points)
    polys = mesh.polygon_count
    total_verts += verts
    total_polys += polys
    print(f"  {name}: {verts} vertices, {polys} polygons")

print(f"Scene totals: {total_verts} vertices, {total_polys} polygons")

Yaygın Sorunlar

SorunÇözüm
AttributeError: 'NoneType' object has no attribute 'polygons'Şununla koruma if node.entity is not None veya isinstance(node.entity, Mesh) mesh özelliklerine erişmeden önce. Varlığı olmayan düğümler şunu döndürür None.
Gezi erken dururYinelemenin şuraya ulaşmasını sağlayın node.child_nodes. Yalnızca yineleme yaparsanız scene.root_node.child_nodes (özyinelemeli değil), tüm alt öğeleri kaçırırsınız.
Toplanan sonuçlarda mesh eksikDosya formatının hiyerarşiyi koruduğunu kontrol edin. OBJ, tüm geometrileri tek bir düğüm seviyesine düzleştirir. Derin hiyerarşiler için glTF veya COLLADA kullanın.
node.entity yalnızca ilk varlığı döndürürKullan node.entities (tam liste) bir düğüm birden fazla varlık taşıdığında. node.entity kısaltmasıdır node.entities[0] ne zaman entities boş değildir.
collect_meshes yüklenmiş bir STL için 0 sonuç döndürürSTL dosyaları tipik olarak doğrudan altında tek bir mesh varlığı bulunan tek bir düz düğüm üretir root_node. Kontrol edin root_node.child_nodes[0].entity doğrudan.
Düğüm adları boş dizelerdirBazı formatlar (binary STL, bazı OBJ dosyaları) nesne adlarını saklamaz. Düğümler boş name dizelere sahip olacaktır; tanımlama için bunun yerine indeksi kullanın.

Sık Sorulan Sorular

Bir sahne grafiği ne kadar derin olabilir?

Sert bir sınır yoktur. Python’ın varsayılan özyineleme sınırı (1000 çerçeve) özyinelemeli dolaşım fonksiyonlarına uygulanır. Çok derin hiyerarşiler için, özyinelemeyi açık bir yığına dönüştürün:

from collections import deque
from aspose.threed import Scene

scene = Scene.from_file("deep.gltf")
queue = deque([(scene.root_node, 0)])

while queue:
    node, depth = queue.popleft()
    print("  " * depth + node.name)
    for child in node.child_nodes:
        queue.append((child, depth + 1))

Ağaç üzerinde dolaşırken onu değiştirebilir miyim?

Düğümleri şuradan eklemeyin veya kaldırmayın child_nodes iterasyon sırasında. Değiştirilecek düğümleri ilk geçişte toplayın, ardından ikinci geçişte değişiklikleri uygulayın.

Belirli bir düğümü isimle nasıl bulurum?

Kullan node.get_child(name) adıyla doğrudan bir çocuğu bulmak için. Derin bir arama için, adı filtreleyen bir ağaç geçişi yapın:

def find_by_name(root, name):
    if root.name == name:
        return root
    for child in root.child_nodes:
        result = find_by_name(child, name)
        if result:
            return result
    return None

target = find_by_name(scene.root_node, "Wheel_FL")

Yapıyor mu node.entity her zaman bir Mesh döndürür mü?

Hayır. Bir düğüm herhangi bir varlık türünü tutabilir: Mesh, Camera, Light, ya da özel varlıklar. Her zaman şununla kontrol edin isinstance(node.entity, Mesh) mesh’e özgü özellikleri kullanmadan önce.

Bir düğümün dünya uzayı konumunu nasıl alırım?

Oku node.global_transform.translation. Bu, tüm üst nesne dönüşümlerini hesaba katarak, dünya uzayındaki değerlendirilmiş konumdur. Salt okunurdur; değiştir node.transform.translation düğümü yeniden konumlandırmak için.

Bir sahnedeki toplam poligon sayısını bir traversal yazmadan sayabilir miyim?

API üzerinden doğrudan değil; bir scene.total_polygon_count özellik. Kullan collect_meshes ve toplam mesh.polygon_count sonuçlar arasında, Adım 6’da gösterildiği gibi.

 Türkçe