Graf scene
Scene graph je temeljni podatkovni model Aspose.3D FOSS za Python. Svaka 3D datoteka, bilo da je učitana s diska ili konstruirana u memoriji, prikazana je kao stablo Node objekata s korijenom u Scene.root_node. Svaki čvor može sadržavati podčvorove i jedan ili više Entity objekata (mreže, kamere, svjetla). Razumijevanje scene grafa daje vam izravan pristup geometriji, materijalima i prostornim transformacijama svakog objekta u sceni.
Instalacija i postavljanje
Instalirajte biblioteku s PyPI-a:
pip install aspose-3d-fossNisu potrebna izvorna proširenja, kompajleri ili dodatni sustavni paketi. Za potpune upute za instalaciju pogledajte Installation Guide.
Pregled: Koncepti grafova scene
Graf scena u Aspose.3D FOSS slijedi jednostavnu hijerarhiju sadržavanja:
Scene
└── root_node (Node)
├── child_node_A (Node)
│ ├── entity: Mesh
│ └── transform: translation, rotation, scale
├── child_node_B (Node)
│ └── child_node_C (Node)
│ └── entity: Mesh
└── ...| Object | Role |
|---|---|
Scene | Kontejner najviše razine. Sadrži root_node, asset_info, animation_clips i sub_scenes. |
Node | Imenovani čvor stabla. Ima roditelja, nula ili više potomaka, nula ili više entiteta i lokalni Transform. |
Entity | Geometrijski ili scenični objekt pričvršćen uz čvor. Uobičajene vrste entiteta: Mesh, Camera, Light. |
Transform | Lokalni položaj, rotacija i skaliranje za čvor. Rezultat u svjetskom prostoru čita se iz global_transform. |
Korak po korak: Izgradnja grafova scene programatski
Korak 1: Stvori scenu
Novi Scene uvijek počinje s praznim root_node:
from aspose.threed import Scene
scene = Scene()
print(scene.root_node.name) # "" (empty string — root node has no name by default)
print(len(scene.root_node.child_nodes)) # 0Scene je ulazna točka za sve: učitavanje datoteka, spremanje datoteka, stvaranje animacijskih isječaka i pristupanje stablu čvorova.
Korak 2: Stvaranje podčvorova
Koristite create_child_node(name) za dodavanje imenovanih čvorova u stablo:
from aspose.threed import Scene
scene = Scene()
parent = scene.root_node.create_child_node("parent")
child = parent.create_child_node("child")
print(parent.name) # "parent"
print(child.parent_node.name) # "parent"
print(len(scene.root_node.child_nodes)) # 1Alternativno, izradite samostalni Node i izričito ga priložite:
from aspose.threed import Scene, Node
scene = Scene()
node = Node("standalone")
scene.root_node.add_child_node(node)Oba pristupa daju isti rezultat. create_child_node je sažetiji za inline konstrukciju.
Korak 3: Stvori Mesh Entity i priloži ga
Mesh pohranjuje podatke o vrhovima (control_points) i topologiju lica (polygons). Stvori jedan, dodaj geometriju, a zatim ga prikači na čvor:
from aspose.threed import Scene, Node
from aspose.threed.entities import Mesh
from aspose.threed.utilities import Vector3, Vector4
scene = Scene()
parent = scene.root_node.create_child_node("parent")
child = parent.create_child_node("child")
##Create a quad mesh (four vertices, one polygon)
# Note: control_points returns a copy of the internal list; append to
# _control_points directly to actually add vertices. This is a known
# library limitation — a public add_control_point() API is not yet available.
mesh = Mesh("cube")
mesh._control_points.append(Vector4(0, 0, 0, 1))
mesh._control_points.append(Vector4(1, 0, 0, 1))
mesh._control_points.append(Vector4(1, 1, 0, 1))
mesh._control_points.append(Vector4(0, 1, 0, 1))
mesh.create_polygon(0, 1, 2, 3)
child.add_entity(mesh)
print(f"Mesh name: {mesh.name}")
print(f"Vertex count: {len(mesh.control_points)}")
print(f"Polygon count: {mesh.polygon_count}")Vector4(x, y, z, w) predstavlja homogenu koordinatu. Koristite w=1 za regularne položaje točaka.
create_polygon(*indices) prihvaća indekse vrhova i registrira jedno lice u popisu poligona. Proslijedite tri indeksa za trokut, četiri za četverokut.
Korak 4: Postavite transformacije čvora
Svaki čvor ima Transform koji kontrolira njegov položaj, orijentaciju i veličinu u lokalnom prostoru:
from aspose.threed.utilities import Vector3, Quaternion
##Translate the node 2 units along the X axis
child.transform.translation = Vector3(2.0, 0.0, 0.0)
##Scale the node to half its natural size
child.transform.scaling = Vector3(0.5, 0.5, 0.5)
##Rotate 45 degrees around the Y axis using Euler angles
child.transform.euler_angles = Vector3(0.0, 45.0, 0.0)Transformacije su kumulativne: položaj djetetovog čvora u svjetskom prostoru je sastav njegove vlastite transformacije sa svim transformacijama pretka. Pročitajte evaluirani rezultat u svjetskom prostoru iz node.global_transform (nepromjenjiv, samo za čitanje).
Korak 5: Rekurzivno prođite kroz graf scene
Prođite cijelo stablo rekurzivno kroz node.child_nodes:
def traverse(node, depth=0):
indent = " " * depth
entity_type = type(node.entity).__name__ if node.entity else "None"
print(f"{indent}{node.name} [{entity_type}]")
for child in node.child_nodes:
traverse(child, depth + 1)
traverse(scene.root_node)Primjer izlaza za scenu izgrađenu iznad (ime korijenskog čvora je prazan niz):
[None]
parent [None]
child [Mesh]Za scene s više entiteta po čvoru, iterirajte node.entities umjesto node.entity:
def traverse_full(node, depth=0):
indent = " " * depth
entity_names = [type(e).__name__ for e in node.entities] or ["None"]
print(f"{indent}{node.name} [{', '.join(entity_names)}]")
for child in node.child_nodes:
traverse_full(child, depth + 1)
traverse_full(scene.root_node)Korak 6: Spremi scenu
Proslijedite putanju datoteke u scene.save(). Format se određuje prema ekstenziji datoteke:
scene.save("scene.gltf") # JSON glTF 2.0
scene.save("scene.glb") # Binary GLB container
scene.save("scene.obj") # Wavefront OBJ
scene.save("scene.stl") # STLZa opcije specifične za format, proslijedite objekt save-options kao drugi argument:
from aspose.threed.formats import GltfSaveOptions
opts = GltfSaveOptions()
scene.save("scene.gltf", opts)Savjeti i najbolje prakse
- Imenujte svaki čvor. Davanje čvorovima smislenih imena znatno olakšava otklanjanje pogrešaka pri prolazima i osigurava da se imena zadrže u izvezenoj datoteci.
- Jedan mrežni objekt po čvoru. Održavanje entiteta 1:1 s čvorovima pojednostavljuje transformacije i upite o sudaru.
- Koristite
create_child_nodeumjesto ručnog pričvršćivanja. Automatski postavlja referencu na roditelja i manje je sklon pogreškama. - Pročitajte
global_transformnakon izgradnje hijerarhije. Rezultat u svjetskom prostoru stabilan je tek nakon što su postavljene sve transformacije pretka. - Ne mijenjajte stablo tijekom prolaza. Dodavanje ili uklanjanje podčvorova tijekom iteracije
child_nodesizazvat će nepredvidivo ponašanje. Prvo sakupite čvorove, zatim modificirajte. - Kontrolne točke koriste
Vector4, a neVector3. Uvijek proslijeditew=1za obične položaje vrhova;w=0predstavlja vektorski smjer (nije točka). mesh.control_pointsvraća kopiju. Svojstvocontrol_pointsvraćalist(self._control_points)— dodavanje elemenata u vraćeni popis ne mijenja mrežu. Uvijek izravno dodajte umesh._control_pointsprilikom programskog izgradnje geometrije. Ovo je poznato ograničenje biblioteke; javni API za mutacije još ne postoji.
Uobičajeni problemi
| Issue | Resolution |
|---|---|
AttributeError: 'NoneType' object has no attribute 'polygons' | Zaštitite s if node.entity is not None prije pristupa svojstvima entiteta. Čvor bez entiteta ima entity = None. |
Mesh appears at the origin despite setting translation | transform.translation primjenjuje lokalni pomak. Ako roditeljski čvor sam ima transformaciju koja nije identitet, svjetska pozicija može biti drugačija. Provjerite global_transform. |
Child nodes missing after scene.save() / reload | Neki formati (OBJ) izravnavaju hijerarhiju. Koristite glTF ili COLLADA za očuvanje cijelog stabla čvorova. |
polygon_count is 0 after mesh.create_polygon(...) | Provjerite jesu li indeksi vrhova proslijeđeni u create_polygon unutar raspona (0 do len(control_points) - 1). |
Node.get_child(name) returns None | Ime je osjetljivo na veličinu slova. Potvrdite točan niz imena koji je korišten prilikom stvaranja. |
| Traversal visits nodes in unexpected order | child_nodes vraća djecu redoslijedom umetanja (redoslijed u kojem je add_child_node / create_child_node pozvan). |