Wie man 3D-Modelle in Python lädt

Wie man 3D-Modelle in Python lädt

Aspose.3D FOSS for Python bietet eine unkomplizierte API zum Öffnen von 3D-Dateien ohne native Abhängigkeiten. Nachdem Sie eine Datei in ein Scene‑Objekt geladen haben, 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-foss

Unterstützte Python-Versionen: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Schritt 2: Importieren der Scene‑Klasse

Die Scene Klasse ist der oberste Container für alle 3D‑Daten. Importieren Sie sie zusammen mit allen Ladeoption‑Klassen, die Sie benötigen.

from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions

Alle öffentlichen Klassen befinden sich unter aspose.threed oder dessen 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 erstellen Sie eine Scene‑Instanz und rufen open() auf; 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‑Objekten, der bei scene.root_node wurzelt. Durchlaufen Sie 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)

Jedes Node kann null oder mehr Entity‑Objekte (Meshes, Kameras, Lichter) tragen. Prüfen Sie node.entities, um zu sehen, was angehängt ist.


Schritt 5: Zugriff auf Scheitel‑ und Polygon‑Daten

Wandle die Entität eines Knotens in Mesh um und lese 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‑Objekten; 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 darstellt.


Schritt 6: Format‑spezifische Ladeoptionen anwenden

Für eine feinkörnige Kontrolle darüber, wie eine OBJ-Datei interpretiert wird, übergeben Sie eine 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 Aufrufen von Scene.from_file()

Der Pfad muss absolut oder korrekt relativ zum Arbeitsverzeichnis zur Laufzeit sein. 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 Triple 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 nach dem Laden eine Rotation auf das Transform des Wurzelknotens an.

AttributeError: 'NoneType' object has no attribute 'polygons'

Die Entitätsliste eines Knotens kann Nicht‑Mesh‑Entitäten (Kameras, Lichter) enthalten. Immer mit isinstance(entity, Mesh) prüfen, bevor Sie 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 die vollständige Analyse ist noch nicht abgeschlossen.

Lädt das Laden einer OBJ-Datei auch das .mtl-Material?

Ja, wenn ObjLoadOptions.enable_materials = True (der Standard). Die Bibliothek sucht die .mtl‑Datei im selben Verzeichnis wie die .obj‑Datei. Wenn die .mtl fehlt, wird die Geometrie trotzdem geladen und es wird eine Warnung ausgegeben.

Kann ich eine Datei aus einem Bytestrom statt eines Pfads laden?

Ja. scene.open() akzeptiert jedes dateiähnliche Objekt mit einer .read()‑Methode zusätzlich zu einem Dateipfad‑String. Übergeben Sie einen offenen Binärstream (z. B. io.BytesIO) direkt. Scene.from_file() akzeptiert nur einen Dateipfad‑String.

Wie bekomme ich Oberflächennormalen?

Nach dem Laden prüfen Sie mesh.get_element(VertexElementType.NORMAL). Dies gibt ein VertexElementNormal zurück, dessen data‑Liste einen Normalenvektor pro Referenz enthält, gemappt 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 vector

Ist die Bibliothek thread‑sicher beim gleichzeitigen Laden mehrerer Dateien?

Jedes Scene‑Objekt ist unabhängig. Das Laden separater Dateien in separate Scene‑Instanzen aus separaten Threads ist sicher, solange Sie kein einzelnes Scene über Threads hinweg ohne externe Sperrung teilen.

 Deutsch