Como Converter Modelos 3D em Python
Conversão de formato com Aspose.3D FOSS para Python é um processo de duas etapas: carregue em um objeto Scene, depois salve no formato de saída desejado. Como toda a geometria é mantida em uma representação comum na memória, não são necessários passos intermediários específicos de formato. As seções abaixo mostram as conversões mais comuns com código funcional.
Guia passo a passo
Etapa 1: Instalar o Pacote
pip install aspose-3d-fossNenhuma biblioteca do sistema, compiladores ou dependências de tempo de execução adicionais são necessários.
Etapa 2: Carregar o Modelo de Origem
Use Scene.from_file() para o caso mais simples: o formato é detectado automaticamente a partir da extensão do arquivo:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")Para arquivos OBJ onde você precisa de controle sobre o sistema de coordenadas ou o carregamento de materiais, use scene.open() com ObjLoadOptions:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert to Z-up if needed
options.enable_materials = True # Load the accompanying .mtl file
options.normalize_normal = True
scene = Scene()
scene.open("model.obj", options)Ambas as abordagens produzem um objeto Scene idêntico para a etapa de salvamento subsequente.
Etapa 3: Inspecionar a Cena Carregada
Antes de prosseguir com a conversão, vale a pena verificar se a geometria foi carregada corretamente. Um arquivo ausente, um recurso FBX não suportado ou um problema de caminho com um arquivo .mtl podem todos gerar uma cena vazia.
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
mesh_count = 0
total_vertices = 0
def count_meshes(node) -> None:
global mesh_count, total_vertices
for entity in node.entities:
if isinstance(entity, Mesh):
mesh_count += 1
total_vertices += len(entity.control_points)
for child in node.child_nodes:
count_meshes(child)
count_meshes(scene.root_node)
print(f"Loaded {mesh_count} mesh(es), {total_vertices} total vertices")
if mesh_count == 0:
raise ValueError("Scene contains no geometry: check the source file path and format")Etapa 4: Salvar no formato de destino
Chame scene.save() com o caminho de saída. Passe um objeto de opções de salvamento específico do formato para controlar a saída binária vs ASCII, os eixos de coordenadas e a compressão.
OBJ para STL (binário)
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
scene = Scene.from_file("model.obj")
save_opts = StlSaveOptions()
##StlSaveOptions defaults to binary output, which is more compact.
scene.save("model.stl", save_opts)
print("Saved model.stl")OBJ para glTF 2.0
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = GltfSaveOptions()
scene.save("model.gltf", save_opts)
print("Saved model.gltf")Para salvar como um binário GLB autocontido em vez de um .gltf + buffers externos, altere a extensão de saída para .glb:
scene.save("model.glb", save_opts)OBJ para 3MF
from aspose.threed import Scene
from aspose.threed.formats import ThreeMfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = ThreeMfSaveOptions()
scene.save("model.3mf", save_opts)
print("Saved model.3mf")STL para glTF 2.0
O mesmo padrão se aplica independentemente do formato de origem:
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("input.stl")
scene.save("output.gltf", GltfSaveOptions())
print("Saved output.gltf")Etapa 5: Verificar a Saída
Após salvar, confirme se o arquivo de saída existe e tem tamanho diferente de zero. Para uma verificação mais completa, recarregue‑o e compare as contagens de malhas:
import os
from aspose.threed import Scene
from aspose.threed.entities import Mesh
output_path = "model.stl"
##Basic file-system check
size = os.path.getsize(output_path)
print(f"Output file size: {size} bytes")
if size == 0:
raise RuntimeError("Output file is empty: save may have failed silently")
##Round-trip verification: reload and count geometry
def _iter_nodes(node):
yield node
for child in node.child_nodes:
yield from _iter_nodes(child)
reloaded = Scene.from_file(output_path)
mesh_count = sum(
1
for node in _iter_nodes(reloaded.root_node)
for entity in node.entities
if isinstance(entity, Mesh)
)
print(f"Round-trip check: {mesh_count} mesh(es) in output")Problemas Comuns e Soluções
O arquivo de saída é criado, mas não contém geometria
O arquivo de origem pode ter sido carregado com zero malhas. Adicione a etapa de inspeção do Passo 3 antes de salvar. Também confirme que a extensão do arquivo corresponde ao formato real; Aspose.3D usa a extensão para selecionar o analisador.
Saída glTF está sem texturas
Aspose.3D FOSS transporta geometria e propriedades de material durante a conversão. Se o OBJ de origem referencia arquivos de imagem externos em .mtl, esses arquivos de imagem não são copiados automaticamente junto com .gltf. Copie as imagens de textura para o diretório de saída manualmente após salvar.
Saída STL parece invertida (normais das faces invertidas)
STL não contém metadados de ordem de winding. Se as normais de saída estiverem invertidas, defina as opções StlSaveOptions, se disponíveis, ou inverta o sistema de coordenadas durante o carregamento: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format ao salvar
Verifique se a extensão do arquivo de saída é uma das .obj, .stl, .gltf, .glb, .dae, .3mf. As extensões diferenciam maiúsculas de minúsculas no Linux.
Arquivos muito grandes causam conversão lenta
Aspose.3D FOSS processa geometria na memória. Para arquivos com milhões de polígonos, garanta RAM suficiente. Atualmente não há streaming-write API.
Perguntas Frequentes (FAQ)
Posso converter um arquivo sem gravá‑lo no disco primeiro?
Sim. Tanto scene.open() quanto scene.save() aceitam objetos binários semelhantes a arquivos, além de caminhos de arquivo. Passe qualquer objeto que implemente read() para carregamento ou write() para gravação:
import io
from aspose.threed import Scene
# Load from an in-memory buffer
data = open('model.obj', 'rb').read()
scene = Scene()
scene.open(io.BytesIO(data))
# Save to an in-memory buffer
buf = io.BytesIO()
scene.save(buf)O FBX é suportado como formato de origem para conversão?
A tokenização de FBX está parcialmente implementada, mas o analisador não está completo. A entrada FBX pode gerar cenas incompletas. Use OBJ, STL, glTF, COLLADA ou 3MF como formatos de origem confiáveis.
Os materiais sobreviverão a uma conversão OBJ-para-glTF?
As propriedades básicas de material Phong/Lambert (cor difusa) são transportadas através do modelo Scene e escritas no bloco de material glTF. Parâmetros de shader procedurais ou personalizados que não podem ser expressos no modelo de material glTF são descartados.
Posso converter vários arquivos em um loop?
Sim. Cada chamada Scene.from_file() cria um objeto independente, portanto um loop sobre uma lista de caminhos é simples:
from pathlib import Path
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
source_dir = Path("input")
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
opts = StlSaveOptions()
for obj_file in source_dir.glob("*.obj"):
scene = Scene.from_file(str(obj_file))
out_path = output_dir / obj_file.with_suffix(".stl").name
scene.save(str(out_path), opts)
print(f"Converted {obj_file.name} -> {out_path.name}")A conversão preserva a hierarquia da cena (nós pai/filho)?
Sim. A árvore de nós é preservada na medida em que o formato de destino permite. Formatos como STL armazenam apenas geometria plana sem estrutura de nós; a hierarquia é achatada ao salvar. Formatos como glTF e COLLADA mantêm a hierarquia completa.