Ako prechádzať 3D graf scén v Python
Scénový graf v Aspose.3D FOSS je stromom Node objektov zakorenených v scene.root_node. Každý 3D súbor, či už načítaný z OBJ, glTF, STL, COLLADA alebo 3MF, vytvára rovnakú stromovú štruktúru. Poznanie spôsobu jej prechádzania vám umožní skúmať geometriu, počítať polygóny, filtrovať objekty podľa typu a spracovávať konkrétne časti zložitej scény.
Postupný návod
Krok 1: Inštalácia a import
Nainštalujte Aspose.3D FOSS z PyPI:
pip install aspose-3d-fossImportujte triedy, ktoré potrebujete:
from aspose.threed import Scene
from aspose.threed.entities import MeshVšetky verejné triedy sa nachádzajú pod aspose.threed alebo v jeho podbalíčkoch (aspose.threed.entities, aspose.threed.utilities).
Krok 2: Načítanie scény zo súboru
Použite statickú Scene.from_file() metódu na otvorenie akéhokoľvek podporovaného formátu. Formát sa detekuje automaticky z prípony súboru:
scene = Scene.from_file("model.gltf")Môžete tiež otvoriť s explicitnými možnosťami načítania:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.enable_materials = True
scene = Scene()
scene.open("model.obj", options)Po načítaní, scene.root_node je koreňom stromu. Všetky importované uzly sú potomkami alebo potomkami tohto uzla.
Krok 3: Napíšte rekurzívnu funkciu prechodu
Najjednoduchší prechod navštevuje každý uzol v poradí hĺbkového prehľadávania:
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)Príklad výstupu:
[-]
[-] 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>
Poznámka: Koreňový uzol má prázdny názov (""), takže prvý riadok zobrazuje [-] bez nasledujúceho názvu.
node.child_nodes vracia deti v poradí vkladania (v poradí, v akom ich importér alebo používateľ pridal).
Krok 4: Prístup k vlastnostiam entít na každom uzle
Použite node.entity na získanie prvej entity pripojenej k uzlu, alebo node.entities pre iteráciu všetkých. Skontrolujte typ pred prístupom k vlastnostiam špecifickým pre formát:
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, a node.transform.scaling poskytuje transformáciu v lokálnom priestore. node.global_transform poskytuje vyhodnotený výsledok vo svetovom priestore (s global_transform.scale pre mierku vo svetovom priestore).
Krok 5: Filtrovať uzly podľa typu entity
Ak chcete pracovať iba s konkrétnymi typmi entít, pridajte isinstance ochranu vo vnútri prechodu:
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}")Tento vzor je užitočný pre hromadné operácie: aplikovanie transformácie na každý uzol s mesh, výmenu materiálov alebo export podstromov.
Krok 6: Zozbierať všetky mesh a vypísať počty vrcholov
Zhrnúť štatistiky mesh v jednom prechode:
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")Bežné problémy
| Problém | Riešenie |
|---|---|
AttributeError: 'NoneType' object has no attribute 'polygons' | Ochrana s if node.entity is not None alebo isinstance(node.entity, Mesh) pred prístupom k vlastnostiam siete. Uzly bez entít vracajú None. |
| Prechod sa predčasne zastaví | Zabezpečte, aby rekurzia zasiahla node.child_nodes. Ak iterujete iba scene.root_node.child_nodes (nie rekurzívne), vymeškáte všetky potomky. |
| Mesh chýba v zozbieraných výsledkoch | Skontrolujte, či formát súboru zachováva hierarchiu. OBJ sploští všetku geometriu do jednej úrovne uzlov. Použite glTF alebo COLLADA pre hlboké hierarchie. |
node.entity vracia iba prvú entitu | Použite node.entities (úplný zoznam) keď uzol nesie viacero entít. node.entity je skratka pre node.entities[0] keď entities nie je prázdny. |
collect_meshes vracia 0 výsledkov pre načítaný STL | Súbory STL zvyčajne vytvárajú jeden plochý uzol s jednou entitou siete priamo pod root_node. Skontrolovať root_node.child_nodes[0].entity priamo. |
| Názvy uzlov sú prázdne reťazce | Niektoré formáty (binárny STL, niektoré OBJ súbory) neukladajú názvy objektov. Uzly budú mať prázdne name reťazce; namiesto toho použite index na identifikáciu. |
Často kladené otázky
Ako hlboký môže byť graf scény?
Neexistuje pevný limit. Predvolený limit rekurzie Python (1000 snímok) sa vzťahuje na rekurzívne funkcie prechodu. Pre veľmi hlboké hierarchie preveďte rekurziu na explicitný zásobník:
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ôžem meniť strom počas jeho prechodu?
Nepridávajte ani neodstraňujte uzly z child_nodes počas ich iterácie. Zozbierajte uzly na úpravu v prvom prechode a potom aplikujte zmeny v druhom prechode.
Ako nájdem konkrétny uzol podľa názvu?
Použite node.get_child(name) na nájdenie priameho dieťaťa podľa názvu. Pre hlbšie vyhľadávanie prechádzajte strom s filtrom názvu:
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")Vráti node.entity vždy vracia Mesh?
Nie. Uzol môže obsahovať akýkoľvek typ entity: Mesh, Camera, Light, alebo vlastné entity. Vždy skontrolujte pomocou isinstance(node.entity, Mesh) pred použitím špecifických vlastností siete.
Ako získam pozíciu uzla vo svetovom priestore?
Čítať node.global_transform.translation. Toto je vyhodnotená pozícia vo svetovom priestore, pričom sa zohľadňujú všetky transformácie predkov. Je to len na čítanie; upravte node.transform.translation na presunutie uzla.
Môžem spočítať celkový počet polygonov v scéne bez písania prechodu?
Nie priamo cez API; neexistuje scene.total_polygon_count vlastnosť. Použite collect_meshes a sčítajte mesh.polygon_count naprieč výsledkami, ako je uvedené v kroku 6.