Hogyan bejárni egy 3D jelenetgráfot a Python használatával

Hogyan bejárni egy 3D jelenetgráfot a Python használatával

A Aspose.3D FOSS-ben a jelenetgrafikon egy fa, amely Node objektumok, amelyek gyökere scene.root_node. Minden 3D fájl, legyen az OBJ, glTF, STL, COLLADA vagy 3MF, ugyanazt a fa struktúrát hozza létre. Ha tudod, hogyan kell bejárni, akkor ellenőrizheted a geometriát, megszámolhatod a poligonokat, szűrheted az objektumokat típus szerint, és feldolgozhatod egy összetett jelenet konkrét részeit.

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

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

Telepítsd a Aspose.3D FOSS-t a PyPI-ról:

pip install aspose-3d-foss

Importáld a szükséges osztályokat:

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

Minden nyilvános osztály a aspose.threed vagy annak alcsomagjaiban (aspose.threed.entities, aspose.threed.utilities).


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

Használd a statikus Scene.from_file() metódust bármely támogatott formátum megnyitásához. A formátum automatikusan felismerésre kerül a fájlkiterjesztés alapján:

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

Kifejezett betöltési beállításokkal is megnyithatod:

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

options = ObjLoadOptions()
options.enable_materials = True

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

Betöltés után, scene.root_node a fa gyökere. Minden importált csomópont ennek a csomópontnak a gyermeke vagy leszármazottja.


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

A legegyszerűbb bejárás minden csomópontot meglátogat mélységi sorrendben:

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)

Példa kimenet:

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

Megjegyzés: A gyökércsomópont üres névvel rendelkezik (""), ezért az első sor [-] nincs név után.

node.child_nodes a gyermekeket beszúrási sorrendben adja vissza (az a sorrend, ahogy az importáló vagy a felhasználó hozzáadta őket).


4. lépés: Entitás tulajdonságok elérése minden csomóponton

Használd node.entity az első, egy csomóponthoz csatolt entitás lekéréséhez, vagy node.entities az összes iterálásához. Ellenőrizze a típust, mielőtt a formátum-specifikus tulajdonságokhoz férne hozzá:

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, és node.transform.scaling adja meg a helyi térbeli transzformációt. node.global_transform adja a kiértékelt világ-térbeli eredményt (val global_transform.scale a világkoordináta-méretezéshez).


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

Csak bizonyos entitástípusokon való működéshez adj hozzá egy isinstance védelmet a bejárásban:

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}")

Ez a minta hasznos tömeges műveletekhez: transzformáció alkalmazása minden háló (mesh) csomópontra, anyagok cseréje vagy részfák exportálása.


6. lépés: Az összes háló (mesh) összegyűjtése és a csúcspontok számának kiírása

Háló (mesh) statisztikák összegyűjtése egyetlen átfutásban:

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

Gyakori problémák

ProblémaMegoldás
AttributeError: 'NoneType' object has no attribute 'polygons'Védelem ezzel if node.entity is not None vagy isinstance(node.entity, Mesh) mielőtt a háló tulajdonságaihoz férnél hozzá. Az entitás nélküli csomópontok visszaadják None.
A bejárás korán leállBiztosítsd, hogy a rekurzió bejusson node.child_nodes. Ha csak iterálsz scene.root_node.child_nodes (nem rekurzívan), minden leszármazottat kihagysz.
A háló hiányzik a gyűjtött eredményekbőlEllenőrizd, hogy a fájlformátum megőrzi-e a hierarchiát. Az OBJ minden geometriát egyetlen csomópont szintre laposít. Használj glTF-et vagy COLLADA-t a mély hierarchiákhoz.
node.entity csak az első entitást adja visszaHasználd node.entities (a teljes lista) amikor egy csomópont több entitást tartalmaz. node.entity rövidítése a node.entities[0] amikor entities nem üres.
collect_meshes 0 eredményt ad vissza egy betöltött STL eseténAz STL fájlok általában egyetlen lapos csomópontot hoznak létre, amelynek közvetlenül alatta egy mesh entitás található root_node. Ellenőrizze root_node.child_nodes[0].entity közvetlenül.
A csomópontnevek üres karakterláncokNéhány formátum (bináris STL, egyes OBJ fájlok) nem tárol objektumneveket. A csomópontok üres name karakterláncokat; helyette az indexet használja az azonosításhoz.

Gyakran Ismételt Kérdések

Milyen mély lehet egy jelenetgrafikon?

Nincs szigorú korlát. A Python alapértelmezett rekurziós korlátja (1000 keret) vonatkozik a rekurzív bejáró függvényekre. Nagyon mély hierarchiák esetén alakítsd át a rekurziót egy explicit verembe:

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

Módosíthatom a fát a bejárás közben?

Ne adjon hozzá vagy távolítson el csomópontokat a child_nodes iterálás közben. Gyűjtse össze a módosítandó csomópontokat egy első lépésben, majd a második lépésben alkalmazza a változtatásokat.

Hogyan találhatok meg egy adott csomópontot név alapján?

Használja node.get_child(name) a közvetlen gyermek megtalálásához név alapján. Mélyebb kereséshez járja be a fát egy névszűrővel:

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

Visszaadja node.entity mindig egy Mesh-et?

Nem. Egy csomópont bármilyen entitástípus tárolhat: Mesh, Camera, Light, vagy egyedi entitásokat. Mindig ellenőrizze a isinstance(node.entity, Mesh) a mesh-specifikus tulajdonságok használata előtt.

Hogyan kapom meg egy csomópont világ-térbeli pozícióját?

Olvasás node.global_transform.translation. Ez a kiértékelt pozíció a világkoordinátarendszerben, figyelembe véve az összes ős transzformációt. Csak olvasható; módosítsa node.transform.translation a csomópont áthelyezéséhez.

Meg tudom számolni a teljes poligonok számát egy jelenetben anélkül, hogy bejárást írnám?

Nem közvetlenül az API-n keresztül; nincs scene.total_polygon_count tulajdonság. Használja collect_meshes és összege mesh.polygon_count az eredmények között, ahogy a 6. lépésben látható.

 Magyar