기능 및 특성
Aspose.3D FOSS for Python은(는) 여러 산업 표준 포맷으로 3D 콘텐츠를 읽고, 구성하고, 쓰기 위한 완전한 씬 그래프 API를 제공합니다. 이 페이지에서는 실제 라이브러리 API를 사용하는 작동하는 Python 코드 예제와 함께 모든 주요 기능 영역을 문서화합니다.
설치 및 설정
단일 명령으로 PyPI에서 라이브러리를 설치합니다:
pip install aspose-3d-foss추가 시스템 패키지, 네이티브 확장, 또는 컴파일러 툴체인이 필요하지 않습니다. 이 라이브러리는 순수 Python이며 Windows, macOS, Linux에서 Python 3.7부터 3.12까지를 지원합니다.
설치를 확인하려면:
from aspose.threed import Scene
scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")기능 및 특성
포맷 지원
Aspose.3D FOSS for Python은(는) 다음 포맷을 읽고 씁니다:
| 포맷 | 확장자 | 읽기 | 쓰기 | 비고 |
|---|---|---|---|---|
| Wavefront OBJ | .obj | 예 | 예 | .mtl 재질 로드 지원 |
| STL (바이너리) | .stl | 예 | 예 | 라운드트립 검증 (39 테스트) |
| STL (ASCII) | .stl | 예 | 예 | 라운드트립 검증 |
| glTF 2.0 | .gltf | 예 | 예 | 전체 씬 그래프가 보존됩니다 |
| GLB (바이너리 glTF) | .glb | 예 | 예 | 단일 파일 바이너리 컨테이너 |
| COLLADA | .dae | 예 | 예 | 씬 계층 구조 및 재질 |
| 3MF | .3mf | 예 | 예 | 적층 제조 형식 |
| FBX | .fbx | 부분적 | 아니오 | Tokenizer는 작동하지만 parser에는 알려진 버그가 있습니다 |
옵션을 사용한 OBJ 로드
ObjLoadOptions OBJ 파일이 파싱되는 방식을 제어합니다:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.enable_materials = True # Load accompanying .mtl file
options.flip_coordinate_system = False # Preserve original handedness
options.normalize_normal = True # Normalize vertex normals to unit length
options.scale = 1.0 # Apply a uniform scale factor at load time
scene = Scene()
scene.open("model.obj", options)
print(f"Loaded {len(scene.root_node.child_nodes)} top-level nodes")STL 저장
StlSaveOptions 바이너리와 ASCII 출력 및 기타 STL 전용 설정을 제어합니다:
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
scene = Scene.from_file("model.obj")
options = StlSaveOptions()
scene.save("output.stl", options)씬 그래프
모든 3D 콘텐츠는 트리 형태로 구성됩니다 Node 객체들. 트리의 루트는 scene.root_node. 모든 노드는 자식 노드를 포함할 수 있고, 그리고 Entity (mesh, camera, or light)와 Transform.
씬 계층 구조 탐색
from aspose.threed import Scene
scene = Scene.from_file("model.glb")
def traverse(node, depth=0):
indent = " " * depth
entity_type = type(node.entity).__name__ if node.entity else "none"
print(f"{indent}{node.name} [{entity_type}]")
for child in node.child_nodes:
traverse(child, depth + 1)
traverse(scene.root_node)프로그래밍 방식으로 씬 구축
from aspose.threed import Scene, Node, Entity
from aspose.threed.entities import Mesh
from aspose.threed.utilities import Vector3
scene = Scene()
root = scene.root_node
##Create a child node and position it
child = root.create_child_node("my_object")
child.transform.translation = Vector3(1.0, 0.0, 0.0)
child.transform.scaling = Vector3(2.0, 2.0, 2.0)
scene.save("constructed.glb")GlobalTransform 검사
GlobalTransform 모든 조상 변환을 누적한 후 노드의 월드 공간 변환을 제공합니다:
from aspose.threed import Scene
scene = Scene.from_file("model.dae")
for node in scene.root_node.child_nodes:
gt = node.global_transform
print(f"Node: {node.name}")
print(f" World translation: {gt.translation}")
print(f" World scale: {gt.scale}")Mesh API
그 Mesh 엔터티는 제어점(버텍스), 폴리곤 및 노멀, UV, 색상용 버텍스 요소를 포함한 기하학 데이터에 대한 접근을 제공합니다.
Mesh 기하학 읽기
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.enable_materials = True
options.flip_coordinate_system = False
scene = Scene()
scene.open("model.obj", options)
for node in scene.root_node.child_nodes:
if node.entity is None:
continue
mesh = node.entity
print(f"Mesh: {node.name}")
print(f" Vertices: {len(mesh.control_points)}")
print(f" Polygons: {len(mesh.polygons)}")버텍스 요소 접근
버텍스 요소는 버텍스당 또는 폴리곤당 데이터를 담고 있습니다. 가장 일반적인 요소는 노멀, UV 좌표, 버텍스 색상, 그리고 스무딩 그룹입니다:
from aspose.threed import Scene
from aspose.threed.entities import VertexElementNormal, VertexElementUV
scene = Scene.from_file("model.obj")
for node in scene.root_node.child_nodes:
if node.entity is None:
continue
mesh = node.entity
# Iterate vertex elements to find normals and UVs
for element in mesh.vertex_elements:
if isinstance(element, VertexElementNormal):
print(f" Normals count: {len(element.data)}")
elif isinstance(element, VertexElementUV):
print(f" UV count: {len(element.data)}")Material System
Aspose.3D FOSS는 두 가지 재질 유형을 지원합니다: LambertMaterial (diffuse shading) 및 PhongMaterial (specular shading). 두 경우 모두 .mtl 파일에서 자동으로 로드됩니다, 사용할 때 ObjLoadOptions 와 enable_materials = True.
OBJ에서 머티리얼 읽기
from aspose.threed import Scene
from aspose.threed.shading import LambertMaterial, PhongMaterial
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.enable_materials = True
scene = Scene()
scene.open("model.obj", options)
for node in scene.root_node.child_nodes:
mat = node.material
if mat is None:
continue
print(f"Node: {node.name}")
if isinstance(mat, PhongMaterial):
print(f" Type: Phong")
print(f" Diffuse: {mat.diffuse_color}")
print(f" Specular: {mat.specular_color}")
elif isinstance(mat, LambertMaterial):
print(f" Type: Lambert")
print(f" Diffuse: {mat.diffuse_color}")프로그래밍 방식으로 머티리얼 할당
from aspose.threed import Scene, Node
from aspose.threed.shading import PhongMaterial
from aspose.threed.utilities import Vector3
scene = Scene.from_file("model.glb")
material = PhongMaterial()
material.diffuse_color = Vector3(0.8, 0.2, 0.2) # Red diffuse
material.specular_color = Vector3(1.0, 1.0, 1.0) # White specular
##Apply to the first mesh node
for node in scene.root_node.child_nodes:
if node.entity is not None:
node.material = material
break
scene.save("recolored.glb")수학 유틸리티
그 aspose.threed.utilities 모듈은 씬 구성 및 검사를 위해 필요한 모든 기하학 수학 타입을 제공합니다.
| 클래스 | 목적 |
|---|---|
Vector2 | 2D floating-point vector (UV coordinates) |
Vector3 | 3D double-precision vector (positions, normals) |
Vector4 | 4D double-precision vector (homogeneous coordinates) |
FVector3 | 3D single-precision vector (compact storage) |
Quaternion | 짐벌 락 없이 회전 표현 |
Matrix4 | 4×4 transformation matrix |
BoundingBox | 최소/최대 코너를 갖는 축 정렬 경계 상자 |
변환 작업
from aspose.threed.utilities import Vector3, Quaternion, Matrix4
import math
##Build a rotation quaternion from axis-angle
axis = Vector3(0.0, 1.0, 0.0) # Y-axis
angle_rad = math.radians(45.0)
q = Quaternion.from_angle_axis(angle_rad, axis)
print(f"Quaternion: x={q.x:.4f} y={q.y:.4f} z={q.z:.4f} w={q.w:.4f}")
##Convert to rotation matrix
mat = q.to_matrix()
print(f"Rotation matrix row 0: {mat[0, 0]:.4f} {mat[0, 1]:.4f} {mat[0, 2]:.4f}")바운딩 박스 계산
from aspose.threed import Scene
scene = Scene.from_file("model.stl")
# NOTE: mesh.get_bounding_box() is a stub — it always returns an empty BoundingBox()
# regardless of geometry. Compute bounds manually from control_points:
for node in scene.root_node.child_nodes:
if node.entity is None:
continue
mesh = node.entity
pts = mesh.control_points # returns a copy of the vertex list
if not pts:
continue
xs = [p.x for p in pts]
ys = [p.y for p in pts]
zs = [p.z for p in pts]
print(f"Mesh: {node.name}")
print(f" Min: ({min(xs):.3f}, {min(ys):.3f}, {min(zs):.3f})")
print(f" Max: ({max(xs):.3f}, {max(ys):.3f}, {max(zs):.3f})")애니메이션
Aspose.3D FOSS는 기반의 애니메이션 모델을 제공합니다 AnimationClip, AnimationNode, KeyFrame, 및 KeyframeSequence. 로드된 파일(glTF, COLLADA)에 저장된 애니메이션 데이터는 이러한 객체를 통해 접근할 수 있습니다.
애니메이션 클립 읽기
from aspose.threed import Scene
scene = Scene.from_file("animated.glb")
for clip in scene.animation_clips:
print(f"Clip: {clip.name} ({clip.start:.2f}s – {clip.stop:.2f}s)")
for anim_node in clip.animations:
print(f" Animation node: {anim_node.name}")
for sub in anim_node.sub_animations:
print(f" Sub-animation: {sub.name}")
for bp in anim_node.bind_points:
print(f" Bind point: {bp.name}")로드 및 저장 옵션
지원되는 모든 포맷은 파싱 및 직렬화 동작을 제어하는 해당 옵션 클래스를 가지고 있습니다.
| 클래스 | 포맷 | 핵심 속성 |
|---|---|---|
ObjLoadOptions | OBJ | enable_materials, flip_coordinate_system, normalize_normal, scale |
StlSaveOptions | STL | 바이너리 vs. ASCII 출력 모드 |
| (glTF는 기본값을 사용합니다) | glTF / GLB | 장면 그래프와 재질이 자동으로 보존됩니다. |
사용 예시
예제 1: OBJ를 STL 포맷으로 변환
OBJ 파일(재질 포함)을 바이너리 STL로 변환하고, 진행 중에 메시 통계를 출력합니다:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
from aspose.threed.formats import StlSaveOptions
##Load OBJ with material support
load_opts = ObjLoadOptions()
load_opts.enable_materials = True
load_opts.flip_coordinate_system = False
load_opts.normalize_normal = True
scene = Scene()
scene.open("input.obj", load_opts)
##Report what was loaded
total_vertices = 0
total_polygons = 0
for node in scene.root_node.child_nodes:
if node.entity is not None:
mesh = node.entity
total_vertices += len(mesh.control_points)
total_polygons += len(mesh.polygons)
print(f" {node.name}: {len(mesh.control_points)} vertices, {len(mesh.polygons)} polygons")
print(f"Total: {total_vertices} vertices, {total_polygons} polygons")
##Save as STL
save_opts = StlSaveOptions()
scene.save("output.stl", save_opts)
print("Saved output.stl")예제 2: 배치 glTF를 GLB로 패킹
별도의 glTF + 텍스처 파일이 있는 디렉터리를 자체 포함된 GLB 바이너리로 다시 저장합니다:
import os
from aspose.threed import Scene
input_dir = "gltf_files"
output_dir = "glb_files"
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.endswith(".gltf"):
continue
src = os.path.join(input_dir, filename)
dst = os.path.join(output_dir, filename.replace(".gltf", ".glb"))
scene = Scene.from_file(src)
scene.save(dst)
print(f"Packed {filename} -> {os.path.basename(dst)}")예제 3: 씬 그래프 검사 및 내보내기 보고서
COLLADA 파일의 씬 그래프를 순회하고, 메쉬별 통계를 수집한 뒤 구조화된 보고서를 출력합니다:
from aspose.threed import Scene
scene = Scene.from_file("assembly.dae")
report = []
def collect(node, path=""):
full_path = f"{path}/{node.name}" if node.name else path
if node.entity is not None:
mesh = node.entity
gt = node.global_transform
report.append({
"path": full_path,
"vertices": len(mesh.control_points),
"polygons": len(mesh.polygons),
"world_x": gt.translation.x,
"world_y": gt.translation.y,
"world_z": gt.translation.z,
})
for child in node.child_nodes:
collect(child, full_path)
collect(scene.root_node)
print(f"{'Path':<40} {'Verts':>6} {'Polys':>6} {'X':>8} {'Y':>8} {'Z':>8}")
print("-" * 78)
for entry in report:
print(
f"{entry['path']:<40} "
f"{entry['vertices']:>6} "
f"{entry['polygons']:>6} "
f"{entry['world_x']:>8.3f} "
f"{entry['world_y']:>8.3f} "
f"{entry['world_z']:>8.3f}"
)팁 및 모범 사례
포맷 선택
- glTF 2.0 / GLB 재질, 애니메이션 및 복잡한 계층 구조를 포함하는 장면에 권장되는 교환 형식입니다. 이식성을 위해 glTF(텍스트 + 외부 파일)보다 GLB(바이너리)를 선호하십시오.
- STL 다운스트림 사용자가 슬라이서, CAD 도구 또는 기하학만 필요한 도구인 경우 올바른 선택입니다. STL은 재질이나 애니메이션 데이터를 포함하지 않습니다.
- OBJ 광범위하게 지원되며 재질 데이터를 오래된 도구와 교환해야 할 때 좋은 선택입니다. .obj 파일과 함께 .mtl 파일을 항상 보관하십시오.
좌표계
- 다양한 애플리케이션이 서로 다른 손잡이 규칙을 사용합니다. 설정하십시오
ObjLoadOptions.flip_coordinate_system = True파이프라인이 왼손 좌표계를 기대하는 경우 오른손 좌표계를 사용하는 도구에서 OBJ 파일을 가져올 때 설정하고, 그 반대의 경우에도 마찬가지입니다. - 플립을 적용하기 전에 원본 에셋의 축 규칙을 확인하세요. 두 번 플립하면 잘못된 기하학이 생성됩니다.
정규화
- 항상 설정하십시오
ObjLoadOptions.normalize_normal = True다운스트림 파이프라인이 단위 법선을 기대할 때(예: 법선을 셰이더에 전달하거나 내적 조명 계산을 수행할 때). 형식이 잘못된 OBJ 파일의 정규화되지 않은 법선은 조명 아티팩트를 일으킵니다.
성능
- 파일을 한 번만 로드하고 메모리 내 장면 그래프를 변환하십시오. 각 출력 형식마다 디스크에서 다시 로드하는 대신. 단일
Scene.from_file()호출에 이어 여러scene.save()호출이 반복 로드보다 더 효율적입니다. - 대량 배치를 처리할 때, 단일
ObjLoadOptions또는StlSaveOptions인스턴스를 생성하고 파일마다 새로운 옵션 객체를 만드는 대신 모든 파일에 재사용하십시오.
오류 처리
- 감싸기
scene.open()및scene.save()호출을try/except신뢰할 수 없거나 사용자 제공 파일을 처리할 때 블록합니다. 예외 메시지에 파일 이름을 보고하여 배치 파이프라인에서 디버깅을 단순화합니다.
일반적인 문제
| 문제 | 원인 | 해결책 |
|---|---|---|
| 로드 후 메시가 좌우 반전된 것처럼 보임 | 좌표계 손잡이 불일치 | 전환 ObjLoadOptions.flip_coordinate_system |
| 노멀 벡터가 길이 0임 | 원본 파일에 정규화되지 않은 노멀 존재 | 설정 ObjLoadOptions.normalize_normal = True |
| OBJ에서 재질이 로드되지 않음 | enable_materials 은 False (기본값) | 설정 ObjLoadOptions.enable_materials = True |
| 씬은 로드되지만 모든 노드가 비어 있음 | 파일이 FBX 형식을 사용함 | FBX 파서는 현재 개발 중이며, 대신 OBJ, STL 또는 glTF를 사용하십시오 |
| 모델이 매우 작거나 큽니다 | 소스 파일이 비미터법 단위를 사용합니다 | 적용 ObjLoadOptions.scale 대상 단위로 변환하려면 |
AttributeError 켜짐 mesh.polygons | 노드 엔터티가 메시가 아닙니다. | 다음으로 보호 if node.entity is not None 엔터티 속성에 접근하기 전에 |
| GLB 파일이 뷰어에 의해 거부되었습니다. | 다음으로 저장됨 .gltf 확장자 | 사용 .glb 호출 시 확장자 scene.save() 바이너리 컨테이너를 트리거하려면 |
자주 묻는 질문
지원되는 Python 버전은 무엇입니까? Python 3.7, 3.8, 3.9, 3.10, 3.11, 및 3.12 모두 지원됩니다. 이 라이브러리는 순수 Python이며 네이티브 확장이 없으므로 CPython이 실행되는 모든 플랫폼에서 작동합니다.
이 라이브러리는 외부 의존성이 있습니까? 아니요. Aspose.3D FOSS for Python는 Python 표준 라이브러리만 사용합니다. 단일 pip install aspose-3d-foss 명령이며 추가 단계가 없습니다.
FBX가 지원됩니까? FBX 토크나이저가 구현되어 바이너리 FBX 토큰 스트림을 파싱할 수 있지만, 토크나이저 위에 있는 씬 그래프 빌더에는 알려진 버그가 있으며 프로덕션에 사용할 수 없습니다. 신뢰할 수 있는 프로덕션 사용을 위해 OBJ, STL, glTF, COLLADA 또는 3MF를 사용하십시오.
상업용 제품에서 Aspose.3D FOSS를 사용할 수 있나요? 예. 이 라이브러리는 MIT 라이선스로 배포되며, 라이선스 고지를 포함하는 한 로열티 없이 독점 및 상업 소프트웨어에 사용할 수 있습니다.
버그를 보고하거나 포맷을 요청하려면 어떻게 해야 하나요? 저장소에 이슈를 열어 주세요. 최소 재현 파일과 Python 버전, 운영 체제, 그리고 라이브러리 버전을 포함하십시오. pip show aspose-3d-foss.
API 레퍼런스 요약
핵심 클래스
Scene: 3D 씬을 위한 최상위 컨테이너. 진입점은open(),from_file(), 및save().Node: 장면 그래프의 트리 노드. 다음을 포함합니다entity,transform,global_transform,material,child_nodes, 및name.Entity: 노드에 부착된 객체(Mesh, Camera, Light)의 기본 클래스.Transform: 노드의 로컬 공간 위치, 회전(Quaternion), 및 스케일.GlobalTransform: 모든 조상 변환을 누적하여 계산된 읽기 전용 월드 공간 변환.
기하학
Mesh: 다음과 같은 폴리곤 메시control_points(버텍스 리스트) 및polygons.VertexElementNormal: 버텍스당 또는 폴리곤당 법선 벡터.VertexElementUV: 버텍스당 UV 텍스처 좌표.VertexElementVertexColor: 버텍스당 색상 데이터.VertexElementSmoothingGroup: 폴리곤 스무딩 그룹 할당.
재질
LambertMaterial: 다음과 함께하는 디퓨즈 셰이딩 모델diffuse_color및emissive_color.PhongMaterial: Specular shading 모델 추가specular_color및shininess.
수학 유틸리티 (aspose.threed.utilities)
Vector2: 2D 벡터.Vector3: 3D 이중 정밀도 벡터.Vector4: 4D 이중 정밀도 벡터.FVector3: 3D 단일 정밀도 벡터.Quaternion: 다음과 함께 회전 쿼터니언from_angle_axis(): 및to_matrix().Matrix4: 4×4 변환 행렬.BoundingBox: 축 정렬 경계 상자 (다음과 함께)minimum: 및maximum: 코너들.
애니메이션
AnimationClip: 애니메이션 채널 집합 및 해당 키프레임을 위한 명명된 컨테이너.AnimationNode: 클립 내 각 노드별 애니메이션 데이터.KeyFrame: 시간과 값을 가진 단일 키프레임.KeyframeSequence: 단일 애니메이션 속성을 위한 정렬된 키프레임 시퀀스.
로드 / 저장 옵션
ObjLoadOptions: OBJ 전용 로드 설정:enable_materials,flip_coordinate_system,normalize_normal,scale.StlSaveOptions: STL 전용 저장 설정 (바이너리 vs. ASCII 모드).
카메라 및 조명
Camera: 다음에 부착 가능한 카메라 엔티티.Node.Light: 라이트 소스 엔티티, a에 부착 가능Node.