Wie man 3D-Modelle in Python konvertiert
Formatkonvertierung mit Aspose.3D FOSS für Python ist ein zweistufiger Prozess: Laden in eine Scene Objekt, dann speichern Sie in das gewünschte Ausgabeformat. Da alle Geometrie in einer gemeinsamen In-Memory-Repräsentation gehalten wird, sind keine formatspezifischen Zwischenschritte erforderlich. Die folgenden Abschnitte zeigen die häufigsten Konvertierungen mit funktionierendem Code an.
Schritt für Schritte
Schritt 1: Installieren des Pakets
asposefoss/3d is not yet published — build from source until it ships. See the project README for build instructions.
Es sind keine Systembibliotheken, Compiler oder zusätzliche Runtime-Abhängigkeiten erforderlich.
Schritt 2: Laden Sie das Quellmodell ein
Verwendung Scene.from_file() für den einfachsten Fall: das Format wird automatisch von der Dateierweiterung erkannt:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")Bei OBJ-Dateien, bei denen die Kontrolle über das Koordinatensystem oder den Materialladen erforderlich ist, verwenden Sie scene.open() mit: ObjLoadOptions:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert to Z-up if needed
options.enable_materials = True # Load the accompanying .mtl file
options.normalize_normal = True
scene = Scene()
scene.open("model.obj", options)Beide Ansätze ergeben ein identisches Ergebnis. Scene Objekt für den folgenden Speicherschritt.
Schritt 3: Überprüfen Sie die geladene Szene
Vor der Konvertierung ist es wichtig zu überprüfen, ob die Geometrie korrekt geladen wurde. Eine fehlende Datei, eine nicht unterstützte FBX-Funktion oder ein Wegproblem mit einem .mtl Die Datei kann alle eine leere Szene erzeugen.
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
mesh_count = 0
total_vertices = 0
def count_meshes(node) -> None:
global mesh_count, total_vertices
for entity in node.entities:
if isinstance(entity, Mesh):
mesh_count += 1
total_vertices += len(entity.control_points)
for child in node.child_nodes:
count_meshes(child)
count_meshes(scene.root_node)
print(f"Loaded {mesh_count} mesh(es), {total_vertices} total vertices")
if mesh_count == 0:
raise ValueError("Scene contains no geometry: check the source file path and format")Schritt 4: Speichern in das Zielformat
Rufen Sie an . scene.save() Übergeben Sie ein formatspezifisches Speicheroptions-Objekt zur Steuerung von binärem gegen ASCII ausgang, Koordinatenachsen und Kompression.
OBJ zu STL (binär)
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
scene = Scene.from_file("model.obj")
save_opts = StlSaveOptions()
##StlSaveOptions defaults to binary output, which is more compact.
scene.save("model.stl", save_opts)
print("Saved model.stl")OBJ bis glTF 2.0
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = GltfSaveOptions()
scene.save("model.gltf", save_opts)
print("Saved model.gltf")Um als eigenständige GLB-Binärform zu speichern, anstatt eine .gltf + externe Puffer, die Ausgabe-Erweiterung auf .glb:
scene.save("model.glb", save_opts)OBJ bis 3MF
from aspose.threed import Scene
from aspose.threed.formats import ThreeMfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = ThreeMfSaveOptions()
scene.save("model.3mf", save_opts)
print("Saved model.3mf")STL bis glTF 2.0
Das gleiche Muster gilt unabhängig vom Quellformat:
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("input.stl")
scene.save("output.gltf", GltfSaveOptions())
print("Saved output.gltf")Schritt 5: Überprüfen Sie die Ausgabe
Nach dem Speichern bestätigen Sie, dass die Ausgabe-Datei existiert und eine nicht Nullgröße hat. Für einen gründlicheren Überprüfung, laden sie es neu und vergleichen Sie Mesh zählen:
import os
from aspose.threed import Scene
from aspose.threed.entities import Mesh
output_path = "model.stl"
##Basic file-system check
size = os.path.getsize(output_path)
print(f"Output file size: {size} bytes")
if size == 0:
raise RuntimeError("Output file is empty: save may have failed silently")
##Round-trip verification: reload and count geometry
def _iter_nodes(node):
yield node
for child in node.child_nodes:
yield from _iter_nodes(child)
reloaded = Scene.from_file(output_path)
mesh_count = sum(
1
for node in _iter_nodes(reloaded.root_node)
for entity in node.entities
if isinstance(entity, Mesh)
)
print(f"Round-trip check: {mesh_count} mesh(es) in output")Häufige Probleme und Lösungen
Ausgabedatei erstellt, aber keine Geometrie enthält
Die Quelldatei kann mit Null-Maschen geladen worden sein. Fügen Sie den Inspektionsschritt aus Schritt 3 vor dem Speichern hinzu. Bestätigen Sie auch, dass die Dateierweiterung dem tatsächlichen Format entspricht; Aspose.3D verwendet die Erweiderung zur Auswahl des Parser.
glTF-Ausgabe fehlt Texturen
Die 3D-FOSS überträgt die Geometrie und Materialeigenschaften durch Konvertierung. Wenn das OBJ der Quelle auf externe Bilddateien in dem Objekt verweist, wird eine neue Form von FOSs erstellt. .mtl, diese Bilddateien werden nicht automatisch neben den .gltf. Kopieren Sie Texturbilder nach dem Speichern manuell in das Ausgabeverzeichnis.
STL-Ausgabe sieht nach innen aus (Gesichtsnormale umgedreht)
Die STL enthält keine Metadaten über die Wickelreihenfolge. Wenn die Ausgangsnormale umgekehrt sind, wird auf den Satz “System” gesetzt. StlSaveOptions Optionen, falls verfügbar oder das Koordinatensystem während der Belastung umdrehen: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format bei der Sparung
Überprüfen Sie die Ausgabe-Datei Erweiterung ist eine von .obj, .stl, .gltf, .glb, .dae, .3mf. Erweiterungen sind auf Linux für Großbuchstaben empfindlich.
Sehr große Dateien verursachen eine langsame Konvertierung.
Aspose.3D FOSS verarbeitet Geometrie im Speicher. Für Dateien mit Millionen von Polygonen, stellen Sie sicher, dass ausreichend RAM verfügbar ist. Es gibt derzeit keine Streaming-Write API.
Häufig gestellte Fragen (FAQ)
Kann ich eine Datei konvertieren, ohne sie zuerst auf die Festplatte zu schreiben?
Ja, beides. scene.open() und . scene.save() Akzeptieren Sie binäre Datei-ähnliche Objekte zusätzlich zu den Pfadwegen. Übergeben Sie jedes Objekt, das implementiert read() zum Verladen oder write() für die Speicherung:
import io
from aspose.threed import Scene
# Load from an in-memory buffer
data = open('model.obj', 'rb').read()
scene = Scene()
scene.open(io.BytesIO(data))
# Save to an in-memory buffer
buf = io.BytesIO()
scene.save(buf)Wird FBX als Quellformat für die Konvertierung unterstützt?
FBX-Tokenisierung ist teilweise implementiert, aber der Parser ist nicht vollständig. FBx-Eingabe kann unvollständige Szenen erzeugen. Verwenden Sie OBJ, STL, glTF, COLLADA oder 3MF als zuverlässige Quellformate.
Überleben Materialien eine OBJ-glTF Umwandlung?
Die grundlegenden Phong/Lambert-MaterialEigenschaften (diffuse Farbe) werden durch die Scene Verfahren- oder benutzerdefinierte Shaderparameter, die nicht im glTF-Materialmodell ausgedrückt werden können, werden weggelassen.
Kann ich mehrere Dateien in einer Schleife konvertieren?
Ja, jeder von ihnen. Scene.from_file() Ein Call erstellt ein unabhängiges Objekt, also ist eine Schleife über eine Liste von Pfaden einfach:
from pathlib import Path
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
source_dir = Path("input")
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
opts = StlSaveOptions()
for obj_file in source_dir.glob("*.obj"):
scene = Scene.from_file(str(obj_file))
out_path = output_dir / obj_file.with_suffix(".stl").name
scene.save(str(out_path), opts)
print(f"Converted {obj_file.name} -> {out_path.name}")Wird die Szenenhierarchie (Elter-/Kindknoten) bei der Umwandlung erhalten?
Ja. Der Knotenbaum wird so weit wie das Zielformat zulässt erhalten. Formate wie STL speichern nur flache Geometrie ohne Knotstruktur; die Hierarchie ist beim Speicheren abgeflacht. Formate wie glTF und COLLADA behalten die volle Hierarchien.