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-foss

Nenhum 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:

FormatoExtensãoLerGravarNotas
Wavefront OBJ.objSimSim.Carregamento de material .mtl suportado
STL (binário).stlSimSimVerificação de ida e volta concluída (39 testes)
STL (ASCII).stlSimSimVerificação de ida e volta concluída
glTF 2.0.gltfSimSimGrafo de cena completo preservado
GLB (binary glTF).glbSimSimContêiner binário de arquivo único
COLLADA.daeSimSimHierarquia de cena e materiais
3MF.3mfSimSimFormato de manufatura aditiva
FBX.fbxParcialNãoTokenizador 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.

ClassePropósito
Vector22D floating-point vector (UV coordinates)
Vector33D double-precision vector (positions, normals)
Vector44D double-precision vector (homogeneous coordinates)
FVector33D single-precision vector (compact storage)
QuaternionRepresentação de rotação sem bloqueio de gimbal
Matrix44×4 transformation matrix
BoundingBoxCaixa 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.

ClasseFormatoPropriedades Principais
ObjLoadOptionsOBJenable_materials, flip_coordinate_system, normalize_normal, scale
StlSaveOptionsSTLModo de saída binário vs. ASCII
(glTF usa valores padrão)glTF / GLBGrafo 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 = True ao 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 = True quando 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últiplos scene.save() chamados é mais eficiente do que carregamentos repetidos.
  • Ao processar grandes lotes, construa um único ObjLoadOptions ou StlSaveOptions instâ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() e scene.save() chamadas em try/except blocos 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

ProblemaCausaResolução
A malha aparece espelhada após o carregamentoIncompatibilidade de orientação do sistema de coordenadasAlternar ObjLoadOptions.flip_coordinate_system
Normais têm comprimento zeroO arquivo fonte tem normais não normalizadasDefinir ObjLoadOptions.normalize_normal = True
Materiais não carregados do OBJenable_materials é False (padrão)Definir ObjLoadOptions.enable_materials = True
A cena carrega, mas todos os nós estão vaziosO arquivo usa o formato FBXO analisador FBX está em desenvolvimento; use OBJ, STL ou glTF em vez disso
O modelo está extremamente pequeno ou grandeO arquivo fonte usa unidades não métricasAplicar ObjLoadOptions.scale para converter para a sua unidade de destino
AttributeError em mesh.polygonsEntidade de nó não é um MeshProteja com if node.entity is not None antes de acessar as propriedades da entidade
Arquivo GLB é rejeitado pelo visualizadorSalvo com .gltf extensãoUse .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 para open(), from_file(), e save().
  • Node: Nó da árvore no grafo de cena. Carrega entity, transform, global_transform, material, child_nodes, e name.
  • 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 com control_points (lista de vértices) e polygons.
  • 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 com diffuse_color : e emissive_color.
  • PhongMaterial: Modelo de sombreamento especular adicionando specular_color : e shininess.

: 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 com from_angle_axis() : e to_matrix().
  • Matrix4: Matriz de transformação 4×4.
  • BoundingBox: Caixa delimitadora alinhada aos eixos com minimum : e maximum : 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 um Node.
  • Light: Entidade de fonte de luz, anexável a um Node.
 Português