Hoe 3D-modellen te converteren in Python
Formaatconversie met Aspose.3D FOSS for Python is een twee‑stappenproces: laad in een Scene object, sla vervolgens op naar het gewenste uitvoerformaat. Omdat alle geometrie wordt vastgehouden in een gemeenschappelijke in‑memory representatie, zijn er geen formaat‑specifieke tussenstappen nodig. De onderstaande secties tonen de meest voorkomende conversies met werkende code.
Stapsgewijze handleiding
Stap 1: Installeer het pakket
pip install aspose-3d-fossEr zijn geen systeembibliotheken, compilers of extra runtime‑afhankelijkheden vereist.
Stap 2: Laad het bronmodel
Gebruik Scene.from_file() voor het eenvoudigste geval: het formaat wordt automatisch gedetecteerd op basis van de bestandsextensie:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")Voor OBJ‑bestanden waarbij u controle over het coördinatensysteem of het laden van materialen nodig heeft, gebruikt u scene.open() met 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 benaderingen produceren een identiek Scene object voor de daaropvolgende opslaanstap.
Stap 3: Inspecteer de geladen scène
Voordat u zich aan een conversie verbindt, is het de moeite waard te controleren of de geometrie correct is geladen. Een ontbrekend bestand, een niet‑ondersteunde FBX‑functie, of een padprobleem met een .mtl‑bestand kan allemaal een lege scène veroorzaken.
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")Stap 4: Opslaan naar het Doelformaat
Roep scene.save() aan met het uitvoerpad. Geef een format‑specifiek save‑options‑object door voor controle over binaire versus ASCII‑output, coördinaatassen en compressie.
OBJ naar STL (binair)
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 naar 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")Om op te slaan als een zelfstandige GLB-binaire in plaats van een .gltf + externe buffers, wijzig de uitvoerextensie naar .glb:
scene.save("model.glb", save_opts)OBJ naar 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 naar glTF 2.0
Hetzelfde patroon is van toepassing, ongeacht het bronformaat:
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")Stap 5: Verifieer de uitvoer
Na het opslaan, bevestig dat het uitvoerbestand bestaat en een grootte groter dan nul heeft. Voor een grondigere controle, laad het opnieuw en vergelijk het aantal meshes:
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")Veelvoorkomende problemen en oplossingen
Uitvoerbestand is aangemaakt maar bevat geen geometrie
Het bronbestand kan zijn geladen met nul meshes. Voeg de inspectiestap uit Stap 3 toe vóór het opslaan. Controleer ook of de bestandsextensie overeenkomt met het daadwerkelijke formaat; Aspose.3D gebruikt de extensie om de parser te selecteren.
glTF-uitvoer mist texturen
Aspose.3D FOSS draagt geometrie- en materiaaleigenschappen over bij conversie. Als de bron-OBJ naar externe afbeeldingsbestanden verwijst in de .mtl, worden die afbeeldingsbestanden niet automatisch gekopieerd naast de .gltf. Kopieer textuurafbeeldingen handmatig naar de uitvoermap na het opslaan.
STL-uitvoer ziet er binnenstebuiten uit (face normals flipped)
STL bevat geen winding-order metadata. Als de uitvoernormals omgekeerd zijn, stel StlSaveOptions opties in indien beschikbaar, of draai het coördinatensysteem om tijdens het laden: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format bij het opslaan
Controleer of de extensie van het uitvoerbestand een van .obj, .stl, .gltf, .glb, .dae, .3mf is. Extensies zijn hoofdlettergevoelig op Linux.
Zeer grote bestanden veroorzaken trage conversie
Aspose.3D FOSS verwerkt geometrie in het geheugen. Voor bestanden met miljoenen polygonen, zorg voor voldoende RAM. Er is momenteel geen streaming‑write API.
Veelgestelde vragen (FAQ)
Kan ik een bestand converteren zonder het eerst naar schijf te schrijven?
Ja. Zowel scene.open() als scene.save() accepteren binaire bestandsachtige objecten naast bestandspaden. Geef elk object door dat read() implementeert voor het laden of write() voor het opslaan:
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)Is FBX ondersteund als bronformaat voor conversie?
FBX-tokenisatie is gedeeltelijk geïmplementeerd, maar de parser is niet compleet. FBX-invoer kan onvolledige scènes opleveren. Gebruik OBJ, STL, glTF, COLLADA of 3MF als betrouwbare bronformaten.
Zullen materialen een OBJ-naar-glTF-conversie overleven?
Basis Phong/Lambert materiaaleigenschappen (diffuse kleur) worden doorgegeven via het Scene-model en geschreven in het glTF-materiaalblok. Procedurele of aangepaste shaderparameters die niet uit te drukken zijn in het glTF-materiaalmodel, worden weggelaten.
Kan ik meerdere bestanden in een lus converteren?
Ja. Elke Scene.from_file()‑aanroep maakt een onafhankelijk object aan, dus een lus over een lijst met paden is eenvoudig:
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}")Behoudt de conversie de scènehiërarchie (ouder/kind knooppunten)?
Ja. De knoopstructuur wordt behouden voor zover het doelformaat dit toestaat. Formaten zoals STL slaan alleen platte geometrie op zonder knoopstructuur; de hiërarchie wordt bij het opslaan afgevlakt. Formaten zoals glTF en COLLADA behouden de volledige hiërarchie.