Come convertire modelli 3D in Python
Conversione di formato con Aspose.3D FOSS per Python è un processo a due passaggi: caricare in un oggetto Scene, quindi salvare nel formato di output desiderato. Poiché tutta la geometria è mantenuta in una rappresentazione comune in memoria, non sono necessari passaggi intermedi specifici per il formato. Le sezioni seguenti mostrano le conversioni più comuni con codice funzionante.
Guida passo-passo
Passo 1: Installa il pacchetto
pip install aspose-3d-fossNon sono richieste librerie di sistema, compilatori o dipendenze di runtime aggiuntive.
Passo 2: Carica il modello di origine
Usa Scene.from_file() per il caso più semplice: il formato viene rilevato automaticamente dall’estensione del file:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")Per i file OBJ in cui è necessario controllare il sistema di coordinate o il caricamento dei materiali, usa scene.open() con 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)Entrambi gli approcci producono un oggetto Scene identico per il passaggio di salvataggio successivo.
Passo 3: Ispeziona la scena caricata
Prima di procedere con una conversione, è consigliabile verificare che la geometria sia stata caricata correttamente. Un file mancante, una funzionalità FBX non supportata o un problema di percorso con un file .mtl possono tutti generare una scena vuota.
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")Passo 4: Salva nel formato di destinazione
Chiama scene.save() con il percorso di output. Passa un oggetto di opzioni di salvataggio specifico per il formato per controllare l’output binario vs ASCII, gli assi di coordinate e la compressione.
OBJ a STL (binario)
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 a 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")Per salvare come un file binario GLB autonomo invece di un .gltf + buffer esterni, modifica l’estensione di output in .glb:
scene.save("model.glb", save_opts)OBJ in 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 a glTF 2.0
Lo stesso schema si applica indipendentemente dal formato di origine:
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")Passo 5: Verifica l’output
Dopo aver salvato, conferma che il file di output esiste e abbia una dimensione diversa da zero. Per un controllo più approfondito, ricaricalo e confronta il numero di mesh:
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")Problemi comuni e soluzioni
Il file di output è stato creato ma non contiene geometria
Il file di origine potrebbe essere stato caricato senza mesh. Aggiungi il passaggio di ispezione dal Passo 3 prima di salvare. Inoltre, verifica che l’estensione del file corrisponda al formato reale; Aspose.3D utilizza l’estensione per selezionare il parser.
L’output glTF manca di texture
Aspose.3D FOSS trasporta le proprietà di geometria e materiale durante la conversione. Se l’OBJ di origine fa riferimento a file immagine esterni nel .mtl, tali file immagine non vengono copiati automaticamente insieme al .gltf. Copia manualmente le immagini delle texture nella directory di output dopo il salvataggio.
L’output STL appare al rovescio (normali delle facce invertite)
STL non contiene metadati sull’ordine di avvolgimento. Se le normali di output sono invertite, impostare le opzioni StlSaveOptions se disponibili, oppure capovolgere il sistema di coordinate durante il caricamento: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format quando si salva
Verifica che l’estensione del file di output sia una delle .obj, .stl, .gltf, .glb, .dae, .3mf. Le estensioni sono sensibili al maiuscolo/minuscolo su Linux.
File molto grandi causano conversione lenta
Aspose.3D FOSS elabora la geometria in memoria. Per file con milioni di poligoni, assicurati di avere RAM sufficiente. Attualmente non esiste un’API di scrittura in streaming.
Domande Frequenti (FAQ)
Posso convertire un file senza prima scriverlo su disco?
Sì. Sia scene.open() che scene.save() accettano oggetti binari simili a file oltre ai percorsi dei file. Passa qualsiasi oggetto che implementa read() per il caricamento o write() per il salvataggio:
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)FBX è supportato come formato di origine per la conversione?
La tokenizzazione FBX è parzialmente implementata, ma il parser non è completo. L’input FBX può produrre scene incomplete. Usa OBJ, STL, glTF, COLLADA o 3MF come formati di origine affidabili.
Sopravviveranno i materiali a una conversione OBJ-to-glTF?
Le proprietà di base del materiale Phong/Lambert (colore diffuso) vengono trasportate attraverso il modello Scene e scritte nel blocco materiale glTF. I parametri shader procedurali o personalizzati non esprimibili nel modello materiale glTF vengono scartati.
Posso convertire più file in un ciclo?
Sì. Ogni chiamata Scene.from_file() crea un oggetto indipendente, quindi un ciclo su un elenco di percorsi è semplice:
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}")La conversione preserva la gerarchia della scena (nodi genitore/figlio)?
Sì. L’albero dei nodi viene conservato nella misura in cui il formato di destinazione lo consente. Formati come STL memorizzano solo geometria piatta senza struttura di nodi; la gerarchia viene appiattita al salvataggio. Formati come glTF e COLLADA mantengono l’intera gerarchia.