Cách tải mô hình 3D trong Python
Aspose.3D FOSS cho Python cung cấp một API đơn giản để mở các tệp 3D mà không cần bất kỳ phụ thuộc gốc nào. Sau khi tải một tệp vào một Scene đối tượng, bạn có thể duyệt qua cây phân cấp nút và đọc dữ liệu hình học thô cho mỗi lưới trong cảnh.
Hướng Dẫn Từng Bước
Bước 1: Cài Đặt Gói
Cài đặt Aspose.3D FOSS từ PyPI. Không cần thư viện hệ thống bổ sung.
pip install aspose-3d-fossCác phiên bản Python được hỗ trợ: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Bước 2: Nhập Lớp Scene
Lớp Scene là container cấp cao nhất cho tất cả dữ liệu 3D. Nhập nó cùng với bất kỳ lớp tùy chọn tải nào bạn cần.
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptionsTất cả các lớp công khai nằm dưới aspose.threed hoặc các gói con của nó (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).
Bước 3: Tải Một Tệp
Sử dụng phương thức tĩnh Scene.from_file() để mở bất kỳ định dạng nào được hỗ trợ. Thư viện tự động phát hiện định dạng từ phần mở rộng tệp.
##Automatic format detection
scene = Scene.from_file("model.obj")Ngoài ra, tạo một Scene đối tượng và gọi open(); hữu ích khi bạn muốn truyền các tùy chọn tải hoặc xử lý lỗi một cách rõ ràng:
scene = Scene()
scene.open("model.obj")Cả hai phương pháp đều hỗ trợ các tệp OBJ, STL (nhị phân và ASCII), glTF 2.0 / GLB, COLLADA (DAE) và 3MF.
Bước 4: Duyệt Các Node Trong Scene
Một cảnh đã tải là một cây của Node đối tượng có gốc tại scene.root_node. Duyệt đệ quy để tìm tất cả các nút:
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)Mỗi Node có thể mang không hoặc nhiều Entity đối tượng (lưới, máy ảnh, đèn). Kiểm tra node.entities để xem những gì đã được gắn.
Bước 5: Truy cập Dữ liệu Đỉnh và Đa giác
Ép kiểu thực thể của node sang Mesh và đọc các điểm điều khiển (vị trí đỉnh) và đa giác (danh sách chỉ mục mặt):
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 là một danh sách của Vector4 đối tượng; x, y, z có vị trí và w là tọa độ đồng nhất (thông thường là 1.0).
mesh.polygons là một danh sách các danh sách các số nguyên, trong đó mỗi danh sách bên trong là tập hợp có thứ tự của các chỉ số điểm điều khiển cho một mặt.
Bước 6: Áp dụng Các Tùy chọn Tải Định dạng Cụ thể
Để kiểm soát chi tiết cách một tệp OBJ được diễn giải, truyền một ObjLoadOptions đối tượng tới 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)Đối với các tệp STL, lớp tương đương là StlLoadOptions. Đối với glTF, sử dụng GltfLoadOptions. Xem the Tham chiếu API để xem danh sách đầy đủ.
Các Vấn Đề Thường Gặp và Cách Khắc Phục
FileNotFoundError khi gọi Scene.from_file()
Đường dẫn phải là tuyệt đối hoặc tương đối đúng so với thư mục làm việc tại thời gian chạy. Sử dụng pathlib.Path để xây dựng các đường dẫn đáng tin cậy:
from pathlib import Path
from aspose.threed import Scene
path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))mesh.polygons trống sau khi tải tệp STL
Các tệp STL lưu trữ các tam giác dưới dạng các mặt phẳng thô, không phải lưới có chỉ mục. Sau khi tải, các đa giác được tổng hợp từ các mặt phẳng đó. Nếu polygons có vẻ trống, kiểm tra len(mesh.control_points); nếu số lượng là bội số của 3, hình học được lưu dưới dạng không có chỉ mục và mỗi ba đỉnh liên tiếp tạo thành một tam giác.
Không khớp hệ tọa độ (mô hình bị xoay hoặc phản chiếu)
Các công cụ khác nhau sử dụng các quy ước khác nhau (Y-up so với Z-up, tay trái so với tay phải). Đặt ObjLoadOptions.flip_coordinate_system = True hoặc áp dụng một phép quay cho nút gốc của Transform sau khi tải.
AttributeError: 'NoneType' object has no attribute 'polygons'
Danh sách thực thể của một nút có thể chứa các thực thể không phải lưới (camera, đèn). Luôn bảo vệ bằng isinstance(entity, Mesh) trước khi ép kiểu.
Câu hỏi thường gặp (FAQ)
Tôi có thể tải các định dạng 3D nào?
OBJ (Wavefront), STL (nhị phân và ASCII), glTF 2.0 / GLB, COLLADA (DAE), và 3MF. Việc tách token của tệp FBX được hỗ trợ một phần nhưng việc phân tích đầy đủ vẫn chưa hoàn thiện.
Việc tải tệp OBJ có cũng tải .mtl vật liệu?
Có, khi ObjLoadOptions.enable_materials = True (mặc định). Thư viện tìm kiếm .mtl tệp trong cùng thư mục với .obj tệp. Nếu .mtl bị thiếu, hình học vẫn được tải và một cảnh báo được phát ra.
Tôi có thể tải tệp từ luồng byte thay vì đường dẫn không?
Có. scene.open() chấp nhận bất kỳ đối tượng giống tệp nào có một .read() phương thức bên cạnh một chuỗi đường dẫn tệp. Truyền một luồng nhị phân mở (ví dụ,., io.BytesIO) trực tiếp. Scene.from_file() chỉ chấp nhận một chuỗi đường dẫn tệp.
Làm sao tôi lấy các pháp tuyến bề mặt?
Sau khi tải, kiểm tra mesh.get_element(VertexElementType.NORMAL). Điều này trả về một VertexElementNormal của nó data danh sách chứa một vector pháp tuyến cho mỗi tham chiếu, được ánh xạ theo mapping_mode và reference_mode.
from aspose.threed.entities import Mesh, VertexElementType
normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
print(normals.data[0]) # First normal vectorThư viện có an toàn với đa luồng khi tải nhiều tệp đồng thời không?
Mỗi Scene đối tượng là độc lập. Tải các tệp riêng biệt vào các Scene đối tượng từ các luồng riêng biệt là an toàn miễn là bạn không chia sẻ một Scene giữa các luồng mà không có khóa bên ngoài.