Wie man 3D-Modelle in Python lädt
Aspose.3D FOSS für Python bietet eine unkomplizierte API zum Öffnen von 3D-Dateien ohne native Abhängigkeiten. Nach dem Laden einer Datei in ein Scene Objekt können Sie die Knotenhierarchie durchlaufen und Rohgeometriedaten für jedes Mesh in der Szene lesen.
Schritt-für-Schritt-Anleitung
Schritt 1: Paket installieren
Installieren Sie Aspose.3D FOSS von PyPI. Es werden keine zusätzlichen Systembibliotheken benötigt.
pip install aspose-3d-fossUnterstützte Python-Versionen: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Schritt 2: Scene‑Klasse importieren
Der Scene Klasse ist der oberste Container für alle 3D-Daten. Importieren Sie sie zusammen mit allen benötigten Ladeoption‑Klassen.
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptionsAlle öffentlichen Klassen befinden sich unter aspose.threed oder in seinen Unterpaketen (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).
Schritt 3: Datei laden
Verwenden Sie die statische Scene.from_file() Methode, um ein beliebiges unterstütztes Format zu öffnen. Die Bibliothek erkennt das Format automatisch anhand der Dateierweiterung.
##Automatic format detection
scene = Scene.from_file("model.obj")Alternativ können Sie ein Scene Instanz erstellen und aufrufen open(); nützlich, wenn Sie Ladeoptionen übergeben oder Fehler explizit behandeln möchten:
scene = Scene()
scene.open("model.obj")Beide Methoden unterstützen OBJ, STL (binär und ASCII), glTF 2.0 / GLB, COLLADA (DAE) und 3MF‑Dateien.
Schritt 4: Szenenknoten durchlaufen
Eine geladene Szene ist ein Baum von Node Objekte, die verwurzelt sind bei scene.root_node. Iteriere rekursiv, um alle Knoten zu finden:
from aspose.threed import Scene, Node
scene = Scene.from_file("model.obj")
def walk(node: Node, depth: int = 0) -> None:
indent = " " * depth
print(f"{indent}Node: {node.name!r}")
for child in node.child_nodes:
walk(child, depth + 1)
walk(scene.root_node)Jeder Node kann null oder mehr tragen Entity Objekte (meshes, cameras, lights). Prüfen node.entities um zu sehen, was angehängt ist.
Schritt 5: Zugriff auf Vertex‑ und Polygon‑Daten
Typumwandlung der Entität eines Knotens zu Mesh und lesen Sie seine Kontrollpunkte (Scheitelpositionen) und Polygone (Flächenindexlisten):
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
for node in scene.root_node.child_nodes:
for entity in node.entities:
if isinstance(entity, Mesh):
mesh: Mesh = entity
print(f"Mesh '{node.name}': "
f"{len(mesh.control_points)} vertices, "
f"{len(mesh.polygons)} polygons")
# First vertex position
if mesh.control_points:
v = mesh.control_points[0]
print(f" First vertex: ({v.x:.4f}, {v.y:.4f}, {v.z:.4f})")
# First polygon face (list of control-point indices)
if mesh.polygons:
print(f" First polygon: {mesh.polygons[0]}")mesh.control_points ist eine Liste von Vector4 Objekte; x, y, z tragen die Position und w ist die homogene Koordinate (normalerweise 1,0).
mesh.polygons ist eine Liste von Listen von Ganzzahlen, wobei jede innere Liste die geordnete Menge von Kontrollpunkt-Indizes für ein Gesicht ist.
Schritt 6: Format‑spezifische Ladeoptionen anwenden
Für eine feinkörnige Kontrolle darüber, wie eine OBJ-Datei interpretiert wird, übergeben Sie ein ObjLoadOptions Instanz an scene.open():
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert right-hand Y-up to Z-up
options.scale = 0.01 # Convert centimetres to metres
options.enable_materials = True # Load .mtl material file
options.normalize_normal = True # Normalize all normals to unit length
scene = Scene()
scene.open("model.obj", options)Für STL-Dateien ist die entsprechende Klasse StlLoadOptions. Für glTF verwenden Sie GltfLoadOptions. Siehe die API-Referenz für eine vollständige Liste.
Häufige Probleme und Lösungen
FileNotFoundError beim Aufruf Scene.from_file()
Der Pfad muss absolut sein oder zur Laufzeit korrekt relativ zum Arbeitsverzeichnis. Verwenden Sie pathlib.Path um zuverlässige Pfade zu erstellen:
from pathlib import Path
from aspose.threed import Scene
path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))mesh.polygons ist nach dem Laden einer STL-Datei leer
STL-Dateien speichern Dreiecke als rohe Facetten, nicht als indiziertes Mesh. Nach dem Laden werden Polygone aus diesen Facetten synthetisiert. Wenn polygons leer erscheint, prüfen Sie len(mesh.control_points); ist die Anzahl ein Vielfaches von 3, wird die Geometrie in unindizierter Form gespeichert und jedes aufeinanderfolgende Dreier‑Paar von Scheitelpunkten bildet ein Dreieck.
Koordinatensystem-Fehlanpassung (Modell erscheint rotiert oder gespiegelt)
Verschiedene Werkzeuge verwenden unterschiedliche Konventionen (Y-up vs Z-up, linkshändig vs rechtshändig). Setzen Sie ObjLoadOptions.flip_coordinate_system = True oder wenden Sie eine Rotation auf den Wurzelknoten Transform nach dem Laden.
AttributeError: 'NoneType' object has no attribute 'polygons'
Die Entitätsliste eines Knotens kann Nicht-Mesh-Entitäten (Kameras, Lichter) enthalten. Schützen Sie immer mit isinstance(entity, Mesh) vor dem Casten.
Häufig gestellte Fragen (FAQ)
Welche 3D‑Formate kann ich laden?
OBJ (Wavefront), STL (binär und ASCII), glTF 2.0 / GLB, COLLADA (DAE) und 3MF. Die Tokenisierung von FBX‑Dateien wird teilweise unterstützt, aber das vollständige Parsen ist noch nicht abgeschlossen.
Lädt das Laden einer OBJ-Datei auch das .mtl Material?
Ja, wenn ObjLoadOptions.enable_materials = True (standardmäßig). Die Bibliothek sucht nach dem .mtl Datei im selben Verzeichnis wie die .obj Datei. Wenn die .mtl fehlt, wird die Geometrie trotzdem geladen und eine Warnung ausgegeben.
Kann ich eine Datei aus einem Bytestrom statt aus einem Pfad laden?
Ja. scene.open() akzeptiert jedes dateiähnliche Objekt mit einem .read() Methode zusätzlich zu einem Dateipfad-String. Übergeben Sie einen offenen Binär-Stream (z. B., io.BytesIO) direkt. Scene.from_file() akzeptiert nur einen Dateipfad-String.
Wie erhalte ich Oberflächennormalen?
Nach dem Laden prüfen mesh.get_element(VertexElementType.NORMAL). Dies gibt ein VertexElementNormal dessen data Liste enthält einen Normalenvektor pro Referenz, abgebildet gemäß mapping_mode und reference_mode.
from aspose.threed.entities import Mesh, VertexElementType
normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
print(normals.data[0]) # First normal vectorIst die Bibliothek thread‑sicher für das gleichzeitige Laden mehrerer Dateien?
Jeder Scene Objekt ist unabhängig. Das Laden separater Dateien in separate Scene Instanzen aus separaten Threads ist sicher, solange Sie nicht ein einzelnes Scene über Threads hinweg ohne externe Sperrung.