Python에서 3D 모델을 로드하는 방법
Aspose.3D FOSS for Python은 네이티브 종속성 없이 3D 파일을 열 수 있는 간단한 API를 제공합니다. 파일을 Scene 객체에 로드한 후, 노드 계층을 탐색하고 씬의 모든 메시에 대한 원시 기하학 데이터를 읽을 수 있습니다.
단계별 가이드
1단계: 패키지 설치
PyPI에서 Aspose.3D FOSS를 설치하세요. 추가 시스템 라이브러리는 필요하지 않습니다.
pip install aspose-3d-foss지원되는 Python 버전: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
2단계: Scene 클래스 가져오기
그 Scene 클래스는 모든 3D 데이터의 최상위 컨테이너입니다. 필요한 로드 옵션 클래스와 함께 import 하세요.
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단계: Scene 노드 순회
로드된 씬은 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 는 0개 이상의 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 파일은 삼각형을 인덱스된 메시가 아니라 원시 면(facet)으로 저장합니다. 로드한 후, 다각형은 이러한 면으로부터 합성됩니다. 만약 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 (기본값). 라이브러리는 다음을 찾습니다 .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 스레드 간에 외부 잠금 없이.