Recursos e Funcionalidades
Aspose.3D FOSS para Python fornece uma API completa de grafo de cena para ler, construir e gravar conteúdo 3D em vários formatos padrão da indústria. Esta página documenta todas as principais áreas de recursos com exemplos de código Python funcionais que utilizam a API real da biblioteca.
Instalação e Configuração
Instale a biblioteca a partir do PyPI com um único comando:
pip install aspose-3d-fossNenhum pacote de sistema adicional, extensões nativas ou toolchains de compilador são necessários. A biblioteca é pura Python e suporta Python 3.7 até 3.12 no Windows, macOS e Linux.
Para verificar a instalação:
from aspose.threed import Scene
scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")Recursos e Funcionalidades
Suporte a Formatos
Aspose.3D FOSS para Python lê e grava os seguintes formatos:
| Formato | Extensão | Ler | Gravar | Notas |
|---|---|---|---|---|
| Wavefront OBJ | .obj | Sim | Sim | .Carregamento de material .mtl suportado |
| STL (binário) | .stl | Sim | Sim | Verificação de ida e volta concluída (39 testes) |
| STL (ASCII) | .stl | Sim | Sim | Verificação de ida e volta concluída |
| glTF 2.0 | .gltf | Sim | Sim | Grafo de cena completo preservado |
| GLB (binary glTF) | .glb | Sim | Sim | Contêiner binário de arquivo único |
| COLLADA | .dae | Sim | Sim | Hierarquia de cena e materiais |
| 3MF | .3mf | Sim | Sim | Formato de manufatura aditiva |
| FBX | .fbx | Parcial | Não | Tokenizador funcionando; analisador tem bugs conhecidos |
Carregando OBJ com Opções
ObjLoadOptions controla como os arquivos OBJ são analisados:
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")Salvando em STL
StlSaveOptions controla a saída binária vs. ASCII e outras configurações específicas do 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)Grafo de Cena
Todo o conteúdo 3D é organizado como uma árvore de Node objetos. A raiz da árvore é scene.root_node. Cada nó pode conter nós filhos e carregar um Entity (malha, câmera ou luz) mais um Transform.
Percorrendo a Hierarquia da Cena
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)Construindo uma Cena Programaticamente
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")Inspecionando GlobalTransform
GlobalTransform fornece a transformação no espaço mundial de um nó após acumular todas as transformações dos ancestrais:
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 de Malha
O Mesh entidade fornece acesso aos dados de geometria, incluindo pontos de controle (vértices), polígonos e elementos de vértice para normais, UVs e cores.
Leitura da Geometria da Malha
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)}")Acessando Elementos de Vértice
Elementos de vértice carregam dados por vértice ou por polígono. Os elementos mais comuns são normais, coordenadas UV, cores de vértice e grupos de suavização:
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)}")Sistema de Material
Aspose.3D FOSS suporta dois tipos de material: LambertMaterial (sombras difusas) e PhongMaterial (sombras especulares). Ambos são carregados automaticamente a partir de arquivos .mtl ao usar ObjLoadOptions com enable_materials = True.
Lendo Materiais de 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}")Atribuindo um Material Programaticamente
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")Utilitários Matemáticos
O aspose.threed.utilities módulo fornece todos os tipos matemáticos geométricos necessários para a construção e inspeção de cenas.
| Classe | Propósito |
|---|---|
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 | Representação de rotação sem bloqueio de gimbal |
Matrix4 | 4×4 transformation matrix |
BoundingBox | Caixa delimitadora alinhada aos eixos com cantos min/máx |
Trabalhando com Transformações
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}")Computando uma Caixa Delimitadora
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})")Animação
Aspose.3D FOSS fornece um modelo de animação baseado em AnimationClip, AnimationNode, KeyFrame, e KeyframeSequence. Dados de animação armazenados em arquivos carregados (glTF, COLLADA) são acessíveis através desses objetos.
Lendo Clipes de Animação
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}")Opções de Carregamento e Salvamento
Cada formato suportado possui uma classe de opções correspondente que controla o comportamento de análise e serialização.
| Classe | Formato | Propriedades Principais |
|---|---|---|
ObjLoadOptions | OBJ | enable_materials, flip_coordinate_system, normalize_normal, scale |
StlSaveOptions | STL | Modo de saída binário vs. ASCII |
| (glTF usa valores padrão) | glTF / GLB | Grafo de cena e materiais preservados automaticamente |
Exemplos de Uso
Exemplo 1: Conversão de Formato OBJ para STL
Converta um arquivo OBJ (com materiais) para STL binário, imprimindo estatísticas da malha ao longo do processo:
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")Exemplo 2: Empacotamento em lote de glTF para GLB
Regrave um diretório de arquivos glTF + textura separados como binários GLB autônomos:
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)}")Exemplo 3: Inspeção do Grafo de Cena e Relatório de Exportação
Percorra o grafo de cena de um arquivo COLLADA, colete estatísticas por malha e imprima um relatório estruturado:
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}"
)Dicas e Melhores Práticas
Seleção de Formato
- glTF 2.0 / GLB é o formato de intercâmbio recomendado para cenas que incluem materiais, animações e hierarquias complexas. Prefira GLB (binário) em vez de glTF (texto + arquivos externos) para portabilidade.
- STL é a escolha certa quando o consumidor downstream é um fatiador, ferramenta CAD ou qualquer ferramenta que precise apenas de geometria. STL não contém dados de material ou animação.
- OBJ é amplamente suportado e uma boa escolha quando os dados de material precisam ser trocados com ferramentas mais antigas. Sempre mantenha o arquivo .mtl ao lado do arquivo .obj.
Sistemas de Coordenadas
- Diferentes aplicativos usam convenções de orientação diferentes. Defina
ObjLoadOptions.flip_coordinate_system = Trueao importar arquivos OBJ de ferramentas que utilizam um sistema de coordenadas direito se seu pipeline espera coordenadas esquerdas, e vice‑versa. - Verifique a convenção de eixos do recurso de origem antes de aplicar qualquer inversão. Inverter duas vezes produz geometria incorreta.
Normalização
- Sempre defina
ObjLoadOptions.normalize_normal = Truequando o pipeline a jusante espera normais unitárias (por exemplo, ao passar normais para um shader ou ao fazer cálculos de iluminação por produto escalar). Normais não normalizadas de arquivos OBJ malformados causam artefatos de iluminação.
Desempenho
- Carregue os arquivos uma única vez e transforme o grafo de cena em memória ao invés de recarregar do disco para cada formato de saída. Um único
Scene.from_file()chamado seguido de múltiplosscene.save()chamados é mais eficiente do que carregamentos repetidos. - Ao processar grandes lotes, construa um único
ObjLoadOptionsouStlSaveOptionsinstância e reutilize-a em todos os arquivos ao invés de criar um novo objeto de opções por arquivo.
Tratamento de Erros
- Envolva
scene.open()escene.save()chamadas emtry/exceptblocos ao processar arquivos não confiáveis ou fornecidos pelo usuário. Relate o nome do arquivo nas mensagens de exceção para simplificar a depuração em pipelines em lote.
Problemas Comuns
| Problema | Causa | Resolução |
|---|---|---|
| A malha aparece espelhada após o carregamento | Incompatibilidade de orientação do sistema de coordenadas | Alternar ObjLoadOptions.flip_coordinate_system |
| Normais têm comprimento zero | O arquivo fonte tem normais não normalizadas | Definir ObjLoadOptions.normalize_normal = True |
| Materiais não carregados do OBJ | enable_materials é False (padrão) | Definir ObjLoadOptions.enable_materials = True |
| A cena carrega, mas todos os nós estão vazios | O arquivo usa o formato FBX | O analisador FBX está em desenvolvimento; use OBJ, STL ou glTF em vez disso |
| O modelo está extremamente pequeno ou grande | O arquivo fonte usa unidades não métricas | Aplicar ObjLoadOptions.scale para converter para a sua unidade de destino |
AttributeError em mesh.polygons | Entidade de nó não é um Mesh | Proteja com if node.entity is not None antes de acessar as propriedades da entidade |
| Arquivo GLB é rejeitado pelo visualizador | Salvo com .gltf extensão | Use .glb extensão ao chamar scene.save() para acionar o contêiner binário |
Perguntas Frequentes
Quais versões do Python são suportadas? As versões Python 3.7, 3.8, 3.9, 3.10, 3.11 e 3.12 são todas suportadas. A biblioteca é pura Python sem extensão nativa, portanto funciona em qualquer plataforma onde o CPython é executado.
A biblioteca tem dependências externas? Não. Aspose.3D FOSS para Python usa apenas a biblioteca padrão Python. Ele é instalado como um único pip install aspose-3d-foss comando, sem etapas adicionais.
O FBX é suportado? O tokenizador FBX está implementado e pode analisar o fluxo binário de tokens FBX, mas o construtor de grafo de cena sobre o tokenizador tem bugs conhecidos e não está pronto para produção. Use OBJ, STL, glTF, COLLADA ou 3MF para uso confiável em produção.
Posso usar Aspose.3D FOSS em um produto comercial? Sim. A biblioteca é lançada sob a licença MIT, que permite o uso em software proprietário e comercial sem pagamentos de royalties, desde que o aviso de licença seja incluído.
Como relato um bug ou solicito um formato? Abra uma issue no repositório. Inclua um arquivo reprodutor mínimo e a versão do Python, o sistema operacional e a versão da biblioteca de pip show aspose-3d-foss.
Resumo da Referência da API
Classes Principais
Scene: Contêiner de nível superior para uma cena 3D. Ponto de entrada paraopen(),from_file(), esave().Node: Nó da árvore no grafo de cena. Carregaentity,transform,global_transform,material,child_nodes, ename.Entity: Classe base para objetos anexados a nós (Mesh, Camera, Light).Transform: Posição, rotação (Quaternion) e escala em espaço local para um nó.GlobalTransform: Transformação em espaço mundial de somente leitura calculada acumulando todas as transformações dos ancestrais.
Geometria
Mesh: Malha poligonal comcontrol_points(lista de vértices) epolygons.VertexElementNormal: Vetores normais por vértice ou por polígono.VertexElementUV: Coordenadas de textura UV por vértice.VertexElementVertexColor: Dados de cor por vértice.VertexElementSmoothingGroup: Atribuições de grupos de suavização de polígonos.
Materiais
LambertMaterial: Modelo de sombreamento difuso comdiffuse_color: eemissive_color.PhongMaterial: Modelo de sombreamento especular adicionandospecular_color: eshininess.
: Utilitários Matemáticos (aspose.threed.utilities)
Vector2: vetor 2D.Vector3: vetor 3D de dupla precisão.Vector4: vetor 4D de dupla precisão.FVector3: vetor 3D de precisão simples.Quaternion: Quaternion de rotação comfrom_angle_axis(): eto_matrix().Matrix4: Matriz de transformação 4×4.BoundingBox: Caixa delimitadora alinhada aos eixos comminimum: emaximum: cantos.
Animação
AnimationClip: Contêiner nomeado para um conjunto de canais de animação e seus quadros‑chave.AnimationNode: Dados de animação por nó dentro de um clipe.KeyFrame: Quadro‑chave único com tempo e valor.KeyframeSequence: Sequência ordenada de quadros‑chave para uma única propriedade animada.
Opções de Carregamento / Salvamento
ObjLoadOptions: Configurações de carregamento específicas para OBJ:enable_materials,flip_coordinate_system,normalize_normal,scale.StlSaveOptions: Configurações de salvamento específicas do STL (modo binário vs. modo ASCII).
Câmeras e Luzes
Camera: Entidade de câmera com configurações de projeção, anexável a umNode.Light: Entidade de fonte de luz, anexável a umNode.