Kaip naršyti 3D scenos grafą Python
Scenos grafas Aspose.3D FOSS yra medžio Node objektų, kurių šaknis yra scene.root_node. Kiekvienas 3D failas, nesvarbu ar jis įkeltas iš OBJ, glTF, STL, COLLADA ar 3MF, sukuria tą pačią medžio struktūrą. Žinant, kaip jį naršyti, galite peržiūrėti geometriją, suskaičiuoti daugiakampius, filtruoti objektus pagal tipą ir apdoroti konkrečias sudėtingos scenos dalis.
Žingsnis po žingsnio vadovas
1 žingsnis: Įdiegti ir importuoti
Įdiekite Aspose.3D FOSS iš PyPI:
pip install aspose-3d-fossImportuokite reikiamas klases:
from aspose.threed import Scene
from aspose.threed.entities import MeshVisos viešosios klasės yra aspose.threed arba jos subpaketuose (aspose.threed.entities, aspose.threed.utilities).
2 žingsnis: Įkelti sceną iš failo
Naudokite statinį Scene.from_file() metodą atverti bet kurį palaikomą formatą. Formatą aptinka automatiškai pagal failo plėtinį:
scene = Scene.from_file("model.gltf")Taip pat galite atidaryti su aiškiai nurodytais įkėlimo parametrais:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.enable_materials = True
scene = Scene()
scene.open("model.obj", options)Įkėlus, scene.root_node yra medžio šaknis. Visi importuoti mazgai yra šio mazgo vaikai arba palikuonys.
3 žingsnis: Parašyti rekursinę perėjimo funkciją
Paprastiausias perėjimas aplanko kiekvieną mazgą gylio pirmumo tvarka:
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)Pavyzdinis išvestis:
[-]
[-] 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>
Pastaba: Šakninis mazgas turi tuščią pavadinimą (""), todėl pirmoje eilutėje rodomas [-] be pavadinimo po jo.
node.child_nodes grąžina vaikus įterpimo tvarka (tvarka, kuria importuotojas arba naudotojas juos pridėjo).
4 žingsnis: Gauti entiteto savybes kiekviename mazge
Naudokite node.entity gauti pirmąjį mazgui priklausantį elementą, arba node.entities kad iteruotumėte visus. Patikrinkite tipą prieš prieinant prie formatui būdingų savybių:
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, ir node.transform.scaling suteikia vietinės erdvės transformaciją. node.global_transform suteikia įvertintą pasaulio erdvės rezultatą (su global_transform.scale pasaulio erdvės masteliui).
Žingsnis 5: Filtruoti mazgus pagal objekto tipą
Norėdami veikti tik su konkrečiais objektų tipais, pridėkite isinstance apsaugą traversalo viduje:
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}")Šis modelis naudingas masinėms operacijoms: taikyti transformaciją kiekvienam mesh mazgui, keisti medžiagas arba eksportuoti po-medžius.
Žingsnis 6: Surinkti visus mesh ir išspausdinti viršūnių skaičių
Sujunkite mesh statistiką vienu praeitimu:
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")Dažnos problemos
| Problema | Sprendimas |
|---|---|
AttributeError: 'NoneType' object has no attribute 'polygons' | Apsauga su if node.entity is not None arba isinstance(node.entity, Mesh) prieš prieinant prie tinklelio savybių. Mazgai be objektų grąžina None. |
| Traversalas sustoja anksti | Įsitikinkite, kad rekursija pasiekia node.child_nodes. Jei iteruojate tik scene.root_node.child_nodes (ne rekursyviai), praleidžiate visus palikuonius. |
| Tinklelis trūksta surinktų rezultatų | Patikrinkite, ar failo formatas išsaugo hierarchiją. OBJ supaprastina visą geometriją į vieną mazgo lygį. Naudokite glTF arba COLLADA gilioms hierarchijoms. |
node.entity grąžina tik pirmą objektą | Naudokite node.entities (pilnas sąrašas) kai mazgas turi kelis elementus. node.entity yra trumpinys, reiškiantis node.entities[0] kai entities nėra tuščias. |
collect_meshes grąžina 0 rezultatų įkeltam STL | STL failai paprastai sukuria vieną plokščią mazgą su viena mesh entity tiesiai po juo root_node. Patikrinkite root_node.child_nodes[0].entity tiesiogiai. |
| Mazgo pavadinimai yra tuščios eilutės | Kai kurie formatai (binary STL, kai kurie OBJ failai) neįrašo objektų pavadinimų. Mazgai turės tuščius name eilučių; vietoj to naudokite indeksą identifikavimui. |
Dažnai užduodami klausimai
Kiek gili gali būti scenos grafas?
Nėra griežto apribojimo. Python numatytoji rekursijos riba (1000 kadrų) taikoma rekursiniams perėjimo funkcijoms. Labai gilioms hierarchijoms konvertuokite rekursiją į aiškų steką:
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))Ar galiu modifikuoti medį perėjimo metu?
Nedėkite ir nepašalinkite mazgų iš child_nodes kai juos iteruojate. Surinkite mazgus, kuriuos reikia modifikuoti, pirmame etape, o tada atlikite pakeitimus antrame etape.
Kaip rasti konkretų mazgą pagal pavadinimą?
Naudokite node.get_child(name) rasti tiesioginį vaiką pagal pavadinimą. Giliau ieškant, pereikite medį su pavadinimo filtru:
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")Ar node.entity visada grąžina Mesh?
Ne. Mazgas gali turėti bet kokio tipo objektą: Mesh, Camera, Light, arba pasirinktinius objektus. Visada patikrinkite su isinstance(node.entity, Mesh) prieš naudodami tik Mesh specifines savybes.
Kaip gauti mazgo poziciją pasaulinėje erdvėje?
Skaityti node.global_transform.translation. Tai yra apskaičiuota pozicija pasaulio erdvėje, atsižvelgiant į visus tėvų transformavimus. Ji yra tik skaityti; modifikuokite node.transform.translation perkelti mazgą.
Ar galiu suskaičiuoti bendrą daugiakampių skaičių scenoje be traversalo rašymo?
Ne tiesiogiai per API; nėra scene.total_polygon_count savybė. Naudokite collect_meshes ir sumuokite mesh.polygon_count per rezultatus, kaip parodyta 6 žingsnyje.