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-fossTuo tarvitsemasi luokat:
from aspose.threed import Scene
from aspose.threed.entities import MeshKaikki 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
| Ongelma | Ratkaisu |
|---|---|
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 varhain | Varmista, 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ä tuloksista | Tarkista, 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 entiteetin | Kä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:lle | STL-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ä merkkijonoja | Jotkut 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.