Scene Graf
A Scene Graf ist das Grunddatenmodell von Aspose.3D FOSS für Python. Jeder 3D-Datei, ob von einem Disk geladen oder in Speicher gebaut, wird als ein Baum der Node Objekte, die in Scene.root_node.Jede Knoten kann Kinderknoten und einen oder mehrere Entity Objekte (Messe, Kameras, Licht). Verständnis des Scenogramms gibt Ihnen direkten Zugang zu der Geometrie, Materialien und Raumtransformationen jedes Objekt in einer Szene.
Installation und Setup
Installieren Sie die Bibliothek von PyPI mit einem einzigen Kommandot:
asposefoss/3d is not yet published — build from source until it ships. See the project README for build instructions.Keine native Erweiterungen, Compilatoren oder zusätzliche Systempakete sind erforderlich. Für die vollständigen Installationsanweisungen, siehe Installationsguide.
Scene Graf
Das Scenografe in Aspose.3D FOSS folgt einer einfachen Containerhierarchie:
Scene
└── root_node (Node)
├── child_node_A (Node)
│ ├── entity: Mesh
│ └── transform: translation, rotation, scale
├── child_node_B (Node)
│ └── child_node_C (Node)
│ └── entity: Mesh
└── ...| Objekt | Rolle |
|---|---|
Scene | Top-Level Container - Halt root_node, asset_info, animation_clips,und sub_scenes. |
Node | Name: Baumknoten: Ein Elternteil, 0 oder mehr Kinder, 0 oder mehr Einheiten und ein lokaler Transform. |
Entity | Geometrie oder Szenenobjekt an einem Knoten angeschlossen.: Mesh, Camera, Light. |
Transform | Lokale Raumposition, Rotation und Skala für einen Knoten. global_transform. |
Schritt für Schritt: Aufbau eines Scene Graph Programmiert
Schritt 1: Erstellen eines Scen
Ein neuer Scene Beginnt immer mit einem leeren 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 ist der Eintrittspunkt für alles: Laden von Dateien, Speichern von Dateien, Erstellen von Animationsclips und Zugang zum Node-Tree.
Schritt 2: Erstellen von Kindernoten
Gebrauch create_child_node(name) Noten zu dem Baum hinzufügen:
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)) # 1Alternativ erstellen Sie eine Standalone Node und sie ausdrücklich anfügen:
from aspose.threed import Scene, Node
scene = Scene()
node = Node("standalone")
scene.root_node.add_child_node(node)Beide Ansätze erzielen das gleiche Ergebnis. create_child_node Es ist für Inline-Konstruktion noch konzentrierter.
Schritt 3: Erstellen Sie eine Mesh-Entität und fügen Sie es an
A Mesh Verteiler von Verteiler (control_pointsund die Topologie (polygonsErstellen Sie einen, fügen Sie Geometrie hinzu, fügen Sie es dann zu einem Knoten an:
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) eine homogene Koordinate darstellt. w=1 für regelmäßige Punktepositionen.
create_polygon(*indices) akzeptiert vertex-index und registriert ein geziel in der polygon-liste. pass drei index für ein dreieck, vier für ein quad.
Schritt 4: Set Node Transforms
Jede Node hat eine Transform die ihre Position, Orientierung und Größe im lokalen Raum kontrolliert:
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)Transformationen sind kumulativ: Die Weltraumposition eines Kindes Node ist die Zusammensetzung seiner eigenen Transformation mit allen Transformationen der Vorfahren. node.global_transform (Unveränderlich und nur im Lesen).
Schritt 5: Überqueren Sie den Scene Graph wiederholt
Spazieren Sie das ganze Baum durch die 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)Beispiel Ausgang für die oben erstellte Szenen (Rohnode-Name ist eine leere Zeile):
[None]
parent [None]
child [Mesh]Für Szenen mit mehreren Einheiten pro Node, iterate node.entities statt der 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)Schritt 6: Erhalten Sie die Szene
Passen Sie einen Dateiweg zum scene.save(). Das Format wird aus der Dateierweiterung abgeführt:
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") # STLFür Format-spezifische Optionen, geben Sie ein Speicherkapitalobjekt als zweites Argument:
from aspose.threed.formats import GltfSaveOptions
opts = GltfSaveOptions()
scene.save("scene.gltf", opts)Tipps und beste Praktiken
- Name für jeden Knoten. Die Gabe von noten sinnvollen Namen macht die verabreichung der durchgänge viel einfacher und sorgt dafür, dass die Namen im ausgeführten bestand beibehalten werden.
- 1 Messer pro Node. Die Aufrechterhaltung von Einheiten 1:1 mit Knoten vereinfacht Transformationen und Kollisionfragen.
- Gebrauch
create_child_nodeüber manuelle Anlagen. Es stellt die Mutterreferenz automatisch und ist weniger Fehlerfreundlich. - Lesen
global_transformNach der Herstellung der Hierarchie. Das Weltraumergebnis ist nur stabil, wenn alle Vorfahrentransformationen eingestellt sind. - Mutage das Baum nicht während der Durchfahrt. Hinzufügen oder Entfernen von Kindernoten während der Iteration
child_nodesSie werden unvorhersehbare Verhaltensweisen erzeugen. Sammeln Sie zuerst Knoten, dann ändern Sie. - Verwenden von Kontrollpunkten
Vector4,nichtVector3. immer durchw=1für die normalen Vertex-Positionen;w=0Es handelt sich um einen Richtvektor (nicht um einen Punkt). mesh.control_pointsEine Kopie zurückgibt. Diecontrol_pointsImmobilien zurückkehrenlist(self._control_points)— die Anschrift auf die zurückgegebene Liste ändert nicht die Messe.mesh._control_pointsDies ist eine bekannte Bibliothekbegrenzung; eine öffentliche Mutation API gibt es noch nicht.
Gemeinsame Probleme
| Thema | Resolution |
|---|---|
AttributeError: 'NoneType' object has no attribute 'polygons' | Die Wartung mit if node.entity is not None Vor dem Zugriff auf die Eigenschaften der Einheit. Ein Knoten ohne Einheiten hat entity = None. |
Mesh erscheint auf dem Ursprung trotz der Setup translation | transform.translation Wenn der Elternknote selbst eine nicht-identitäts-Transformation hat, kann die Weltposition unterschiedlich sein. global_transform. |
Kinderknochen verschwinden nach scene.save() / Reload | Einige Formate (OBJ) flatten die Hierarchie. Verwenden Sie GlTF oder COLLADA, um das volle Nodebäume zu bewahren. |
polygon_count 0 nach mesh.create_polygon(...) | Überprüfen Sie, ob die Vertex-Indizes übergeben sind create_polygon Sie sind innerhalb der Range (0 zu len(control_points) - 1). |
Node.get_child(name) Rückkehr None | Der Name ist Fallsensitiv. Bestätigen Sie die genaue Namestrang, die zu der Erstellung verwendet wird. |
| Reisebesuche in unerwarteter Ordnung | child_nodes Kinder in Einführung (die Bestellung add_child_node / create_child_node wurde er genannt). |