Kuinka läpikäydä 3D‑kohtausgraafi Python:ssa

Kuinka läpikäydä 3D‑kohtausgraafi Python:ssa

Kohtausgrafiikka Aspose.3D FOSS:ssä on puu, joka koostuu Node objekteista, jonka juuri on scene.root_node. Jokainen 3D‑tiedosto, ladattu olipa se OBJ-, glTF-, STL-, COLLADA- tai 3MF-muodossa, tuottaa saman puurakenteen. Tietäminen, miten sitä traversoidaan, mahdollistaa geometrian tarkastelun, polygonien laskemisen, objektien suodattamisen tyypin mukaan sekä monimutkaisen kohtauksen tiettyjen osien käsittelyn.

Vaiheittainen opas

Vaihe 1: Asenna ja tuo

Asenna Aspose.3D FOSS PyPI:stä:

pip install aspose-3d-foss

Tuo tarvitsemasi luokat:

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

Kaikki julkiset luokat sijaitsevat aspose.threed tai sen alipaketeissa (aspose.threed.entities, aspose.threed.utilities).


Vaihe 2: Lataa kohtaus tiedostosta

Käytä staattista Scene.from_file() metodia avatakseen minkä tahansa tuetun formaatin. Formaatti tunnistetaan automaattisesti tiedostopäätteestä:

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

Voit myös avata eksplisiittisillä latausasetuksilla:

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

options = ObjLoadOptions()
options.enable_materials = True

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

Latauksen jälkeen, scene.root_node on puun juuri. Kaikki tuodut solmut ovat tämän solmun lapsia tai jälkeläisiä.


Vaihe 3: Kirjoita rekursiivinen läpikäyntifunktio

Yksinkertaisin läpikäynti käy läpi jokaisen solmun syvyyssuuntaisessa järjestyksessä:

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)

Esimerkkituloste:

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

Huomaa: Juurisolmulla on tyhjä nimi (""), joten ensimmäisellä rivillä näkyy [-] ilman nimeä perässä.

node.child_nodes palauttaa lapset lisäysjärjestyksessä (järjestyksessä, jossa tuonti tai käyttäjä lisäsi ne).


Vaihe 4: Pääse käsiksi entiteettien ominaisuuksiin jokaisessa solmussa

Käytä node.entity saadaksesi ensimmäisen solmuun liitetyn entiteetin, tai node.entities iteraamaan kaikki. Tarkista tyyppi ennen kuin käytät formaattiin liittyviä ominaisuuksia:

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, ja node.transform.scaling antaa paikallisen avaruuden muunnoksen. node.global_transform antaa arvioidun maailmanavaruuden tuloksen (with global_transform.scale maailman koordinaattitilan skaalaa varten).


Vaihe 5: Suodata solmut entiteettityypin mukaan

Toimiaksesi vain tietyillä entiteettityypeillä, lisää isinstance suojauksen traversaalin sisällä:

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

Tämä malli on hyödyllinen massatoiminnoissa: muunnoksen soveltaminen jokaiselle mesh-solmulle, materiaalien korvaaminen tai alipuukkojen vienti.


Vaihe 6: Kerää kaikki mesh-objektit ja tulosta vertex-määrät

Kerää mesh-tilastot yhdellä läpikäynnillä:

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

Yleisiä ongelmia

OngelmaRatkaisu
AttributeError: 'NoneType' object has no attribute 'polygons'Suojauksen avulla if node.entity is not None tai isinstance(node.entity, Mesh) ennen kuin pääset käsiksi verkon ominaisuuksiin. Solmut ilman entiteettejä palauttavat None.
Traversaali pysähtyy varhainVarmista, että rekursio ulottuu node.child_nodes. Jos iteroit vain scene.root_node.child_nodes (ei rekursiivisesti), menetät kaikki jälkeläiset.
Verkko puuttuu kerätyistä tuloksistaTarkista, että tiedostomuoto säilyttää hierarkian. OBJ litistää kaiken geometrian yhdeksi solmutasoksi. Käytä glTF:ää tai COLLADA:a syviin hierarkioihin.
node.entity palauttaa vain ensimmäisen entiteetinKäytä node.entities (täydellinen luettelo) kun solmu sisältää useita entiteettejä. node.entity on lyhennys node.entities[0] kun entities ei ole tyhjä.
collect_meshes palauttaa 0 tulosta ladatulle STL:lleSTL-tiedostot tuottavat tyypillisesti yhden tasaisen solmun, jossa on yksi mesh-entiteetti suoraan alla root_node. Tarkista root_node.child_nodes[0].entity suoraan.
Solmun nimet ovat tyhjiä merkkijonojaJotkut formaatit (binary STL, jotkut OBJ-tiedostot) eivät tallenna objektin nimiä. Solmuilla on tyhjät name merkkijonot; käytä sen sijaan indeksiä tunnistamiseen.

Usein kysytyt kysymykset

Kuinka syväksi kohtausgrafi voi olla?

Kovaa rajaa ei ole. Python:n oletusrekursiopituus (1000 kehystä) koskee rekursiivisia traversaalifunktioita. Erittäin syville hierarkioille, muuta rekursio eksplisiittiseksi pinoksi:

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

Voinko muokata puuta sen läpikäynnin aikana?

Älä lisää tai poista solmuja child_nodes sen läpikäynnin aikana. Kerää muokattavat solmut ensimmäisessä läpikäynnissä, ja tee muutokset toisessa läpikäynnissä.

Kuinka löydän tietyn solmun nimen perusteella?

Käytä node.get_child(name) löytääksesi suoran lapsen nimen perusteella. Syvempää hakua varten, kulje puuta nimen suodattimella:

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

Palauttaako node.entity aina palauttaa Meshin?

Ei. Solmu voi sisältää minkä tahansa entiteettityypin: Mesh, Camera, Light, tai mukautetut entiteetit. Tarkista aina isinstance(node.entity, Mesh) ennen mesh-spesifisten ominaisuuksien käyttöä.

Kuinka saan solmun maailman tilan sijainnin?

Lue node.global_transform.translation. Tämä on arvioitu sijainti maailmanavaruudessa, ottaen huomioon kaikki vanhempien muunnokset. Se on vain luettavissa; muokkaa node.transform.translation solmun siirtämiseksi.

Voinko laskea kohtauksen kaikkien polygonien määrän kirjoittamatta läpikäyntiä?

Ei suoraan API:n kautta; ei ole scene.total_polygon_count ominaisuus. Käytä collect_meshes ja summaa mesh.polygon_count tulosten yli, kuten on esitetty vaiheessa 6.

 Suomi