Python에서 3D 모델을 로드하는 방법

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 스레드 간에 외부 잠금 없이.

 한국어