功能与特性
Aspose.3D FOSS for Python 提供了完整的场景图 API,用于读取、构建和写入多种行业标准格式的 3D 内容。本页记录了每个主要功能区域,并提供使用实际库 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 | 部分 | 否 | 分词器工作正常;解析器已知存在错误 |
使用选项加载 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}")网格 API
该 Mesh 实体提供对几何数据的访问,包括控制点(顶点)、多边形以及用于法线、UV 和颜色的顶点元素。.
读取网格几何
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)}")材质系统
Aspose.3D FOSS 支持两种材质类型:: LambertMaterial (漫反射着色)和 PhongMaterial (镜面反射着色)。两者在使用时会自动从 .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 | 二进制与 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 是包含材质、动画和复杂层次结构的场景的推荐交换格式。为提高可移植性,建议使用 GLB(二进制)而非 glTF(文本 + 外部文件)。.
- STL 当下游使用者是切片软件、CAD 工具或仅需几何数据的任何工具时,这是正确的选择。STL 不包含材质或动画数据。.
- OBJ 得到广泛支持,并且在需要与旧工具交换材质数据时是一个不错的选择。务必将 .mtl 文件与 .obj 文件放在一起。.
坐标系
- 不同的应用程序使用不同的坐标系约定。设置
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 |
| 法线长度为零 | 源文件的法线未归一化 | 设置 ObjLoadOptions.normalize_normal = True |
| 未从 OBJ 加载材质 | enable_materials 是 False (默认) | 设置 ObjLoadOptions.enable_materials = True |
| 场景加载成功,但所有节点为空 | 文件使用 FBX 格式 | FBX 解析器仍在开发中;请改用 OBJ、STL 或 glTF。 |
| 模型极小或极大 | 源文件使用非公制单位 | 应用 ObjLoadOptions.scale 以转换为目标单位 |
AttributeError 开启 mesh.polygons | 节点实体不是 Mesh | 使用 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 许可证发布,允许在专有和商业软件中使用且无需支付版税,只要包含许可证声明即可。.
我该如何报告错误或请求支持某种格式?? 在仓库中打开一个 issue。请附上最小复现文件以及来自的 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::节点的局部空间位置、旋转(四元数)和缩放。.GlobalTransform::只读的世界空间变换,通过累积所有祖先的变换计算得到。.
几何
Mesh::具有control_points(顶点列表)以及polygons.VertexElementNormal::每顶点或每多边形的法线向量。.VertexElementUV::每顶点的 UV 纹理坐标。.VertexElementVertexColor::每顶点的颜色数据。.VertexElementSmoothingGroup::多边形平滑组分配。.
材质
LambertMaterial::带有diffuse_color和emissive_color.PhongMaterial: 添加镜面着色模型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 特定的保存设置(二进制模式或 ASCII 模式)。.
相机和灯光
Camera: 相机实体,带有投影设置,可附加到 aNode.Light: 光源实体,可附加到 aNode.