Як конвертувати 3D‑моделі у Python
Конвертація форматів за допомогою Aspose.3D FOSS для Python — це двоетапний процес: завантажити в об’єкт Scene, а потім зберегти в потрібний вихідний формат. Оскільки вся геометрія зберігається в спільному представленні в пам’яті, немає потреби у форматно‑специфічних проміжних кроках. Нижче наведено розділи з найпоширенішими конвертаціями та робочим кодом.
Покроковий посібник
Крок 1: Встановити пакет
pip install aspose-3d-fossСистемні бібліотеки, компілятори або додаткові залежності під час виконання не потрібні.
Крок 2: Завантажити вихідну модель
Використовуйте Scene.from_file() для найпростішого випадку: формат визначається автоматично за розширенням файлу:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")Для файлів OBJ, коли потрібен контроль над системою координат або завантаженням матеріалів, використовуйте scene.open() разом з 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)Обидва підходи створюють ідентичний Scene об’єкт для наступного кроку збереження.
Крок 3: Перегляньте завантажену сцену
Перш ніж приступати до конвертації, варто перевірити, чи геометрія завантажилася правильно. Відсутній файл, непідтримувана функція FBX або проблема з шляхом до файлу .mtl можуть призвести до порожньої сцени.
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")Крок 4: Зберегти у цільовий формат
Викличте scene.save() з шляхом виводу. Передайте об’єкт параметрів збереження, специфічний для формату, щоб керувати бінарним чи ASCII виводом, координатними осями та стисканням.
OBJ у STL (бінарний)
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 у 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")Щоб зберегти у вигляді самодостатнього бінарного GLB замість .gltf + зовнішніх буферів, змініть розширення вихідного файлу на .glb:
scene.save("model.glb", save_opts)OBJ у 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 у glTF 2.0
Той самий шаблон застосовується незалежно від формату джерела:
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")Крок 5: Перевірте вивід
Після збереження переконайтеся, що вихідний файл існує і має ненульовий розмір. Для більш ретельної перевірки перезавантажте його та порівняйте кількість мешів:
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")Поширені проблеми та виправлення
Файл виводу створено, але не містить геометрії
Вихідний файл міг бути завантажений без мешів. Додайте крок перевірки з Кроку 3 перед збереженням. Також переконайтеся, що розширення файлу відповідає фактичному формату; Aspose.3D використовує розширення для вибору парсера.
Вивід glTF не містить текстур
Aspose.3D FOSS переносить геометрію та властивості матеріалів під час конвертації. Якщо вихідний OBJ посилається на зовнішні файли зображень у .mtl, ці файли зображень не копіюються автоматично разом з .gltf. Скопіюйте текстурні зображення у вихідний каталог вручну після збереження.
Вивід STL виглядає всередині назовні (нормалі граней перевернуті)
STL не містить метаданих про порядок обертання. Якщо вихідні нормалі інвертовані, встановіть параметри StlSaveOptions, якщо вони доступні, або змініть систему координат під час завантаження: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format при збереженні
Перевірте, чи розширення вихідного файлу є одним із .obj, .stl, .gltf, .glb, .dae, .3mf. Розширення чутливі до регістру в Linux.
Дуже великі файли спричиняють повільне перетворення
Aspose.3D FOSS обробляє геометрію в пам’яті. Для файлів з мільйонами полігонів забезпечте достатню оперативну пам’ять. Наразі немає streaming-write API.
Часті запитання (FAQ)
Чи можу я конвертувати файл, не записуючи його спочатку на диск?
Так. Обидва scene.open() і scene.save() приймають бінарні об’єкти, схожі на файли, крім шляхів до файлів. Передайте будь‑який об’єкт, який реалізує read() для завантаження або write() для збереження:
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 як вихідний формат для конвертації?
Токенізація FBX частково реалізована, але парсер не завершений. Вхід FBX може створювати неповні сцени. Використовуйте OBJ, STL, glTF, COLLADA або 3MF як надійні вихідні формати.
Чи збережуться матеріали при конвертації OBJ у glTF?
Базові властивості матеріалу Phong/Lambert (diffuse colour) передаються через модель Scene і записуються у блок матеріалу glTF. Процедурні або користувацькі параметри шейдера, які не можна виразити в моделі матеріалу glTF, відкидаються.
Чи можна конвертувати кілька файлів у циклі?
Так. Кожен виклик Scene.from_file() створює незалежний об’єкт, тому цикл по списку шляхів є простим:
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}")Чи зберігає конвертація ієрархію сцени (батьківські/дочірні вузли)?
Так. Дерево вузлів зберігається настільки, наскільки це дозволяє цільовий формат. Формати, такі як STL, зберігають лише плоску геометрію без структури вузлів; ієрархія сплющується під час збереження. Формати, такі як glTF і COLLADA, зберігають повну ієрархію.