Jak przekształcić modele 3D w Python

Jak przekształcić modele 3D w Python

Konwersja formatów z Aspose.3D FOSS dla Pythona jest dwustronnym procesem: ładowanie do Scene Obiekt, a następnie przechowywać do pożądanej formatu wyjścia. Ponieważ cała geometria jest utrzymywana w wspólnej reprezentacji pamięci, nie są potrzebne środkowe kroki określone formatem. sekcje poniżej pokazują najczęstsze konwersje z kodem roboczym.

Przewodnik krok po kroku

Krok 1: Instalacja pakietu

asposefoss/3d is not yet published — build from source until it ships. See the project README for build instructions.

Nie wymagane są biblioteki systemowe, kompilatorzy ani dodatkowe zależności czasów pracy.


Krok 2: Pobierz model źródłowy

Używanie Scene.from_file() w najprostszym przypadku: format jest automatycznie wykryty z rozszerzenia pliku:

from aspose.threed import Scene

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

W przypadku plików OBJ, w których potrzebujesz kontroli nad systemem koordynatowym lub ładowaniem materiału, użyj scene.open() z 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)

Obie metody tworzą identyczną Scene Obiekt na następny krok do oszczędzania.


Krok 3: Sprawdź nagrany scenę

Przed dokonaniem konwersji warto sprawdzić, czy geometria jest prawidłowo ładowana. brakuje pliku, nie obsługiwana funkcja FBX lub problem ścieżki z .mtl Każdy z nich może stworzyć pustą scenę.

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

Krok 4: Zapisz do formatu docelowego

Wzywaj scene.save() Przejdź do obiektu opcji zapasowych określonych w formacie, aby kontrolować wyjście binarne vs ASCII, osi koordynacyjne i kompresję.

OBJ do STL (binary)

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

Aby zaoszczędzić jako samokontentowany GLB binary zamiast .gltf + zewnętrzne bufery, zmieniają rozszerzenie wyjścia do .glb:

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

Wzrost do 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 do GLTF 2.0

Ten sam wzór jest stosowany niezależnie od formatu źródłowego:

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

Krok 5: Sprawdź wyjście

Po oszczędzeniu potwierdź, że plik wyjściowy istnieje i ma rozmiar nie-zero. Aby dokładniej sprawdzić, ponownie pobrać go i porównać liczbę zbiorników:

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

Wspólne problemy i rozwiązania

Plik wyjściowy jest utworzony, ale nie zawiera geometrii

Plik źródłowy może być załadowany z zero map. Dodaj krok kontroli od kroku 3 przed oszczędzaniem. Potwierdź również, że rozszerzenie pliku odpowiada rzeczywistemu formatowi; Aspose.3D używa rozciągania do wyboru parseru.

GTA brakuje tekstur

Aspose.3D FOSS przynosi geometrii i właściwości materiałowe poprzez konwersję. jeśli źródło OBJ odwoła się do zewnętrznych plików obrazu w .mtl,pliki nie są automatycznie kopiowane obok .gltf.Kopiuj obrazy tekstury do katalogu wyjścia ręcznie po przechowywaniu.

STL wyjście wygląda wewnątrz (na twarzy normalne flipped)

STL nie przynosi metadanych porządku windingu.Jeśli normy wyjścia są odwrócone, ustaw StlSaveOptions opcje, jeśli są dostępne lub flip system koordynat podczas ładowania: ObjLoadOptions.flip_coordinate_system = True.

ValueError: unsupported format Kiedy oszczędność

Sprawdź, czy rozszerzenie pliku wyjściowego jest jednym z .obj, .stl, .gltf, .glb, .dae, .3mf.Rozszerzenia są przypadkowo wrażliwe na Linux.

Bardzo duże pliki powodują powolną konwersję

Aspose.3D FOSS przetwarza geometrii w pamięci. Dla plików z milionami poligonów zapewnia wystarczającą ilość RAM. Obecnie nie ma API do pisania strumieniowego.


Często zadawane pytania (FAQ)

Czy mogę konwertować plik bez pisania go na dyski?

Tak, obie scene.open() i scene.save() akceptuj obiekty binarne podobne do pliku oprócz ścieżek plików. przejdź przez każdy obiekt, który implemente read() do ładowania lub write() Dla oszczędności:

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)

Czy FBX jest obsługiwany jako format źródłowy do konwersji?

Wprowadzenie FBX może wytwarzać niekompletne sceny. Użyj OBJ, STL, glTF, COLLADA lub 3MF jako wiarygodnych formatów źródłowych.

Czy materiały przeżyją konwersję OBJ-glTF?

Podstawowe właściwości materiału Phong/Lambert (kolor difuzji) są przewożone przez Scene Wzorce i napisane w bloku materiału glTF. Przepisy proceduralne lub przystosowane niewyrażalne w modelu materiałowym gl TF są wyłączone.

Czy mogę konwertować kilka plików w jednym kręgu?

Tak, każdy Scene.from_file() Call tworzy niezależny obiekt, więc przepływ na liście ścieżek jest prosty:

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

Czy konwersja zachowuje hierarchię sceny (rodziny / węzły dziecka)?

Tak. Drzewo węzła jest zachowane tak daleko, jak pozwala format docelowy. formaty takie jak STL przechowują tylko płaską geometrię bez struktury wązłów; hierarchia jest wypełniona na zapasie.

 Polski