Як завантажити 3D‑моделі у Python
Aspose.3D FOSS для Python надає простий API для відкриття 3D‑файлів без будь‑яких нативних залежностей. Після завантаження файлу у Scene об’єкт, ви можете пройти ієрархію вузлів і прочитати необроблені дані геометрії для кожної сітки в сцені.
Покроковий посібник
Крок 1: Встановіть пакет
Встановіть Aspose.3D FOSS з PyPI. Додаткові системні бібліотеки не потрібні.
pip install aspose-3d-fossПідтримувані версії Python: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Крок 2: Імпортуйте клас Scene
Клас Scene class є контейнером верхнього рівня для всіх 3D даних. Імпортуйте його разом із будь‑якими класами параметрів завантаження, які вам потрібні.
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptionsУсі публічні класи розташовані в aspose.threed або в його підпакетах (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).
Крок 3: Завантажте файл
Використовуйте статичний Scene.from_file() метод для відкриття будь‑якого підтримуваного формату. Бібліотека автоматично визначає формат за розширенням файлу.
##Automatic format detection
scene = Scene.from_file("model.obj")Альтернативно створіть Scene екземпляр і викличте open(); корисно, коли ви хочете передати параметри завантаження або явно обробляти помилки:
scene = Scene()
scene.open("model.obj")Обидва методи підтримують файли OBJ, STL (бінарний та ASCII), glTF 2.0 / GLB, COLLADA (DAE) та 3MF.
Крок 4: Обійдіть вузли сцени
Завантажена сцена — це дерево Node об’єктів, коренем яких є scene.root_node. Рекурсивно ітеруйте, щоб знайти всі вузли:
from aspose.threed import Scene, Node
scene = Scene.from_file("model.obj")
def walk(node: Node, depth: int = 0) -> None:
indent = " " * depth
print(f"{indent}Node: {node.name!r}")
for child in node.child_nodes:
walk(child, depth + 1)
walk(scene.root_node)Кожен Node може містити нуль або більше Entity об’єкти (меші, камери, світильники). Перевірте node.entities щоб побачити, що приєднано.
Крок 5: Доступ до даних вершин та полігонів
Перетворіть сутність вузла на Mesh і прочитайте його контрольні точки (позиції вершин) та полігони (списки індексів граней):
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
for node in scene.root_node.child_nodes:
for entity in node.entities:
if isinstance(entity, Mesh):
mesh: Mesh = entity
print(f"Mesh '{node.name}': "
f"{len(mesh.control_points)} vertices, "
f"{len(mesh.polygons)} polygons")
# First vertex position
if mesh.control_points:
v = mesh.control_points[0]
print(f" First vertex: ({v.x:.4f}, {v.y:.4f}, {v.z:.4f})")
# First polygon face (list of control-point indices)
if mesh.polygons:
print(f" First polygon: {mesh.polygons[0]}")mesh.control_points є списком Vector4 об’єктів; x, y, z містять позицію та w є однорідною координатою (зазвичай 1.0).
mesh.polygons є списком списків цілих чисел, де кожен внутрішній список — це впорядкований набір індексів контрольних точок для однієї грані.
Крок 6: Застосування специфічних для формату параметрів завантаження
Для тонкого контролю над тим, як інтерпретується файл OBJ, передайте ObjLoadOptions екземпляр до scene.open():
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert right-hand Y-up to Z-up
options.scale = 0.01 # Convert centimetres to metres
options.enable_materials = True # Load .mtl material file
options.normalize_normal = True # Normalize all normals to unit length
scene = Scene()
scene.open("model.obj", options)Для файлів STL еквівалентний клас — це StlLoadOptions. Для glTF використовуйте GltfLoadOptions. Дивіться довідник API для повного списку.
Типові проблеми та їх вирішення
FileNotFoundError під час виклику Scene.from_file()
Шлях має бути абсолютним або правильним відносно робочого каталогу під час виконання. Використовуйте pathlib.Path для створення надійних шляхів:
from pathlib import Path
from aspose.threed import Scene
path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))mesh.polygons порожній після завантаження STL‑файлу
STL‑файли зберігають трикутники як необроблені грані, а не як індексована сітка. Після завантаження полігони синтезуються з цих граней. Якщо polygons здається порожнім, перевірте len(mesh.control_points); якщо кількість кратна 3, геометрія зберігається у неіндексованій формі, і кожна послідовна трійка вершин утворює один трикутник.
Несумісність системи координат (модель виглядає повернутою або віддзеркаленою)
Різні інструменти використовують різні конвенції (Y‑up проти Z‑up, ліва рука проти правої). Встановіть ObjLoadOptions.flip_coordinate_system = True або застосувати обертання до кореневого вузла Transform після завантаження.
AttributeError: 'NoneType' object has no attribute 'polygons'
Список сутностей вузла може містити не‑мешові сутності (камери, освітлення). Завжди захищайтеся за допомогою isinstance(entity, Mesh) перед приведенням типу.
Поширені запитання (FAQ)
Які 3D‑формати я можу завантажити?
OBJ (Wavefront), STL (бінарний та ASCII), glTF 2.0 / GLB, COLLADA (DAE) та 3MF. Токенізація файлів FBX підтримується частково, але повний парсинг ще не завершений.
Чи завантаження файлу OBJ також завантажує .mtl матеріал?
Так, коли ObjLoadOptions.enable_materials = True (за замовчуванням). Бібліотека шукає the .mtl файл у тому ж каталозі, що і .obj файл. Якщо .mtl відсутній, геометрія все ще завантажується, і виводиться попередження.
Чи можу я завантажити файл з байтового потоку замість шляху?
Так. scene.open() приймає будь-який об’єкт, схожий на файл, з .read() методом, крім рядка шляху до файлу. Передайте відкритий бінарний потік (наприклад,., io.BytesIO) безпосередньо. Scene.from_file() приймає лише рядок шляху до файлу.
Як отримати нормалі поверхні?
Після завантаження перевірте mesh.get_element(VertexElementType.NORMAL). Це повертає VertexElementNormal чий data список містить один нормальний вектор на посилання, зіставлений згідно з mapping_mode і reference_mode.
from aspose.threed.entities import Mesh, VertexElementType
normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
print(normals.data[0]) # First normal vectorЧи є бібліотека потокобезпечною для одночасного завантаження кількох файлів?
Кожен Scene об’єкт є незалежним. Завантаження окремих файлів у окремі Scene екземпляри з окремих потоків безпечні, доки ви не ділите один Scene через потоки без зовнішнього блокування.