Cum să convertești modele 3D în Python

Cum să convertești modele 3D în Python

Conversia de format cu Aspose.3D FOSS pentru Python este un proces în două etape: încărcați într-un obiect Scene, apoi salvați în formatul de ieșire dorit. Deoarece toată geometria este păstrată într-o reprezentare comună în memorie, nu sunt necesari pași intermediari specifici formatului. Secțiunile de mai jos prezintă cele mai comune conversii cu cod funcțional.

Ghid pas cu pas

Pasul 1: Instalați pachetul

pip install aspose-3d-foss

Nu sunt necesare biblioteci de sistem, compilatoare sau dependențe suplimentare de runtime.


Pasul 2: Încarcă modelul sursă

Utilizați Scene.from_file() pentru cel mai simplu caz: formatul este detectat automat din extensia fișierului:

from aspose.threed import Scene

scene = Scene.from_file("model.obj")

Pentru fișierele OBJ în care aveți nevoie de control asupra sistemului de coordonate sau încărcării materialelor, utilizați scene.open() cu 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)

Ambele abordări produc un obiect Scene identic pentru pasul ulterior de salvare.


Pasul 3: Inspectaţi scena încărcată

Înainte de a trece la conversie, merită să verificaţi că geometria a fost încărcată corect. Un fişier lipsă, o funcţionalitate FBX neacceptată sau o problemă de cale cu un fişier .mtl pot toate să producă o scenă goală.

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")

Pasul 4: Salvează în formatul țintă

Apelaţi scene.save() cu calea de ieşire. Transmiteţi un obiect de opţiuni de salvare specific formatului pentru controlul asupra ieşirii binare vs ASCII, axelor de coordonate şi compresiei.

OBJ în STL (binare)

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 la 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")

Pentru a salva ca un binar GLB autonom în loc de un .gltf + buffere externe, schimbaţi extensia de ieşire în .glb:

scene.save("model.glb", save_opts)

OBJ la 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 în glTF 2.0

Același model se aplică indiferent de formatul sursei:

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")

Pasul 5: Verificați ieșirea

După salvare, confirmați că fișierul de ieșire există și are o dimensiune diferită de zero. Pentru o verificare mai amănunțită, reîncărcați-l și comparați numărul de mesh-uri:

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")

Probleme comune și soluții

Fișierul de ieșire este creat, dar nu conține geometrie

Fișierul sursă ar fi putut fi încărcat cu zero mesh-uri. Adăugați pasul de inspecție din Pasul 3 înainte de salvare. De asemenea, confirmați că extensia fișierului corespunde formatului real; Aspose.3D folosește extensia pentru a selecta parserul.

ieșirea glTF nu are texturi

Aspose.3D FOSS transferă geometria și proprietățile materialelor în timpul conversiei. Dacă fișierul OBJ sursă face referire la fișiere de imagini externe în .mtl, aceste fișiere de imagini nu sunt copiate automat alături de .gltf. Copiați manual imaginile de textură în directorul de ieșire după salvare.

Ieșirea STL pare inversată (normalele fețelor întoarse)

STL nu conține metadate privind ordinea de înfășurare. Dacă normalele de ieșire sunt inversate, setați opțiunile StlSaveOptions dacă sunt disponibile, sau inversați sistemul de coordonate în timpul încărcării: ObjLoadOptions.flip_coordinate_system = True.

ValueError: unsupported format la salvare

Verificați că extensia fișierului de ieșire este una dintre .obj, .stl, .gltf, .glb, .dae, .3mf. Extensiile sunt sensibile la majuscule/minuscule pe Linux.

Fișiere foarte mari cauzează conversie lentă

Aspose.3D FOSS procesează geometria în memorie. Pentru fișiere cu milioane de poligoane, asigurați-vă că aveți suficient RAM. În prezent nu există o API de scriere în flux.


Întrebări frecvente (FAQ)

Pot să convertesc un fișier fără să-l scriu pe disc mai întâi?

Da. Atât scene.open(), cât și scene.save() acceptă obiecte binare asemănătoare fișierelor, pe lângă căile de fișiere. Transmite orice obiect care implementează read() pentru încărcare sau write() pentru salvare:

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)

Este FBX acceptat ca format sursă pentru conversie?

Tokenizarea FBX este implementată parțial, dar parserul nu este complet. Intrarea FBX poate produce scene incomplete. Folosiți OBJ, STL, glTF, COLLADA sau 3MF ca formate sursă fiabile.

Vor supraviețui materialele unei conversii OBJ-la-glTF?

Proprietățile de bază ale materialului Phong/Lambert (culoarea difuză) sunt transmise prin modelul Scene și scrise în blocul de material glTF. Parametrii procedurali sau shaderii personalizați care nu pot fi exprimați în modelul de material glTF sunt eliminați.

Pot converti mai multe fișiere într-o buclă?

Da. Fiecare apel Scene.from_file() creează un obiect independent, așa că o buclă peste o listă de căi este simplă:

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}")

Conversia păstrează ierarhia scenei (noduri părinte/copil)?

Da. Arborele de noduri este păstrat în măsura în care formatul țintă permite. Formatele precum STL stochează doar geometrie plată fără structură de noduri; ierarhia este aplatizată la salvare. Formatele precum glTF și COLLADA păstrează ierarhia completă.

 Română