Características y Funcionalidades

Características y Funcionalidades

Aspose.3D FOSS para Python ofrece una API completa de grafo de escena para leer, construir y escribir contenido 3D en múltiples formatos estándar de la industria. Esta página documenta cada área de funcionalidad principal con ejemplos de código Python funcionales que utilizan la API real de la biblioteca.

Instalación y configuración

Instala la biblioteca desde PyPI con un solo comando:

pip install aspose-3d-foss

No se requieren paquetes del sistema adicionales, extensiones nativas ni cadenas de herramientas de compilador. La biblioteca es pura Python y soporta Python 3.7 a 3.12 en Windows, macOS y Linux.

Para verificar la instalación:

from aspose.threed import Scene

scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")

Características y Funcionalidades

Compatibilidad de formatos

Aspose.3D FOSS para Python lee y escribe los siguientes formatos:

FormatoExtensiónLeerEscribirNotas
Wavefront OBJ.obj.Carga de material .mtl compatible
STL (binario).stlRecorrido verificado (39 pruebas)
STL (ASCII).stlRecorrido verificado
glTF 2.0.gltfGrafo completo de escena preservado
GLB (binary glTF).glbContenedor binario de un solo archivo
COLLADA.daeJerarquía de escena y materiales
3MF.3mfFormato de fabricación aditiva
FBX.fbxParcialNoTokenizador funcionando; parser tiene errores conocidos

Cargando OBJ con opciones

ObjLoadOptions controla cómo se analizan los archivos 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")

Guardando en STL

StlSaveOptions controla la salida binaria vs. ASCII y otras configuraciones específicas de 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 escena

Todo el contenido 3D está organizado como un árbol de Node objetos. La raíz del árbol es scene.root_node. Cada nodo puede contener nodos hijos y llevar un Entity (malla, cámara o luz) más un Transform.

Recorriendo la jerarquía de la escena

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)

Construyendo una escena programáticamente

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")

Inspeccionando GlobalTransform

GlobalTransform proporciona la transformación en el espacio mundial de un nodo después de acumular todas las transformaciones de los ancestros:

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 Mesh

El Mesh la entidad brinda acceso a los datos de geometría, incluidos los puntos de control (vértices), polígonos y elementos de vértice para normales, UVs y colores.

Lectura de la geometría de 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)}")

Acceso a los elementos de vértice

Los elementos de vértice contienen datos por vértice o por polígono. Los elementos más comunes son normales, coordenadas UV, colores de vértice y grupos de suavizado:

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 materiales

Aspose.3D FOSS soporta dos tipos de material: LambertMaterial (sombreado difuso) y PhongMaterial (sombreado especular). Ambos se cargan automáticamente desde archivos .mtl al usar ObjLoadOptions con enable_materials = True.

Lectura de materiales desde 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}")

Asignación de un material programáticamente

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")

Utilidades matemáticas

El aspose.threed.utilities el módulo proporciona todos los tipos matemáticos geométricos necesarios para la construcción e inspección de escenas.

ClasePropó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)
QuaternionRepresentación de rotación sin bloqueo de cardán
Matrix44×4 transformation matrix
BoundingBoxCaja delimitadora alineada a los ejes con esquinas mín/máx

Trabajando con transformaciones

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}")

Cálculo de una caja 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})")

Animación

Aspose.3D FOSS proporciona un modelo de animación basado en AnimationClip, AnimationNode, KeyFrame, y KeyframeSequence. Los datos de animación almacenados en los archivos cargados (glTF, COLLADA) son accesibles a través de estos objetos.

Lectura de clips de animación

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}")

Opciones de carga y guardado

Cada formato compatible tiene una clase de opciones correspondiente que controla el comportamiento de análisis y serialización.

ClaseFormatoPropiedades clave
ObjLoadOptionsOBJenable_materials, flip_coordinate_system, normalize_normal, scale
StlSaveOptionsSTLModo de salida binario vs. ASCII
(glTF usa valores predeterminados)glTF / GLBGráfico de escena y materiales preservados automáticamente

Ejemplos de uso

Ejemplo 1: Conversión de formato OBJ a STL

Convertir un archivo OBJ (con materiales) a STL binario, imprimiendo estadísticas de la malla a lo largo del proceso:

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")

Ejemplo 2: Empaquetado por lotes de glTF a GLB

Volver a guardar un directorio de archivos glTF + texturas separados como binarios 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)}")

Ejemplo 3: Inspección del grafo de escena e informe de exportación

Recorrer el grafo de escena de un archivo COLLADA, recopilar estadísticas por malla y generar un informe estructurado:

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}"
    )

Consejos y mejores prácticas

Selección de formato

  • glTF 2.0 / GLB es el formato de intercambio recomendado para escenas que incluyen materiales, animaciones y jerarquías complejas. Prefiera GLB (binario) sobre glTF (texto + archivos externos) para portabilidad.
  • STL es la elección correcta cuando el consumidor posterior es un slicer, una herramienta CAD o cualquier herramienta que solo necesite geometría. STL no lleva datos de material ni de animación.
  • OBJ tiene amplio soporte y es una buena opción cuando los datos de material deben intercambiarse con herramientas más antiguas. Siempre mantenga el archivo .mtl junto al archivo .obj.

Sistemas de coordenadas

  • Diferentes aplicaciones usan diferentes convenciones de mano. Set ObjLoadOptions.flip_coordinate_system = True al importar archivos OBJ de herramientas que usan un sistema de coordenadas de mano derecha si su canal espera coordenadas de mano izquierda, y viceversa.
  • Verifique la convención de ejes del activo de origen antes de aplicar cualquier volteo. Voltear dos veces produce geometría incorrecta.

Normalización

  • Siempre establezca ObjLoadOptions.normalize_normal = True cuando la canalización descendente espera normales unitarias (por ejemplo, al pasar normales a un shader o al realizar cálculos de iluminación por producto punto). Las normales no normalizadas de archivos OBJ mal formados causan artefactos de iluminación.

Rendimiento

  • Cargue los archivos una vez y transforme el grafo de escena en memoria en lugar de recargar desde el disco para cada formato de salida. Un único Scene.from_file() llamado seguido de múltiples scene.save() llamadas es más eficiente que cargas repetidas.
  • Al procesar lotes grandes, construya un único ObjLoadOptions o StlSaveOptions instancia y reutilícela en todos los archivos en lugar de crear un nuevo objeto de opciones por archivo.

Manejo de Errores

  • Envolver scene.open() y scene.save() llamadas en try/except bloques al procesar archivos no confiables o suministrados por el usuario. Informe el nombre de archivo en los mensajes de excepción para simplificar la depuración en canalizaciones por lotes.

Problemas comunes

ProblemaCausaResolución
La malla aparece reflejada después de cargarlaDesajuste de la handedness del sistema de coordenadasAlternar ObjLoadOptions.flip_coordinate_system
Las normales tienen longitud ceroEl archivo fuente tiene normales no normalizadasEstablecer ObjLoadOptions.normalize_normal = True
Materiales no cargados desde OBJenable_materials es False (predeterminado)Establecer ObjLoadOptions.enable_materials = True
La escena se carga pero todos los nodos están vacíosEl archivo usa formato FBXEl analizador FBX está en progreso; use OBJ, STL o glTF en su lugar
El modelo es extremadamente pequeño o grandeEl archivo fuente usa unidades no métricasAplicar ObjLoadOptions.scale para convertir a tu unidad objetivo
AttributeError en mesh.polygonsLa entidad Node no es un MeshProteger con if node.entity is not None antes de acceder a las propiedades de la entidad
El archivo GLB es rechazado por el visorGuardado con .gltf extensiónUsar .glb extensión al llamar scene.save() para activar el contenedor binario

Preguntas Frecuentes

¿Qué versiones de Python son compatibles? Las versiones Python 3.7, 3.8, 3.9, 3.10, 3.11 y 3.12 son compatibles. La biblioteca es pura Python sin extensiones nativas, por lo que funciona en cualquier plataforma donde se ejecute CPython.

¿La biblioteca tiene dependencias externas? No. Aspose.3D FOSS para Python solo usa la biblioteca estándar Python. Se instala como un único pip install aspose-3d-foss comando sin pasos posteriores.

¿Se admite FBX? El tokenizador FBX está implementado y puede analizar el flujo binario de tokens FBX, pero el generador de grafo de escena sobre el tokenizador tiene errores conocidos y no está listo para producción. Use OBJ, STL, glTF, COLLADA o 3MF para un uso fiable en producción.

¿Puedo usar Aspose.3D FOSS en un producto comercial? Sí. La biblioteca se publica bajo la licencia MIT, que permite su uso en software propietario y comercial sin pagos de regalías, siempre que se incluya el aviso de licencia.

¿Cómo informo de un error o solicito un formato? Abra un issue en el repositorio. Incluya un archivo reproducidor mínimo y la versión de Python, el sistema operativo y la versión de la biblioteca de pip show aspose-3d-foss.


Resumen de la Referencia de API

Clases Principales

  • Scene: Contenedor de nivel superior para una escena 3D. Punto de entrada para open(), from_file(), y save().
  • Node: Nodo del árbol en el grafo de escena. Lleva entity, transform, global_transform, material, child_nodes, y name.
  • Entity: Clase base para objetos adjuntos a nodos (Mesh, Camera, Light).
  • Transform: Posición, rotación (Quaternion) y escala en espacio local para un nodo.
  • GlobalTransform: Transformación en espacio mundial de solo lectura calculada acumulando todas las transformaciones de los ancestros.

Geometría

  • Mesh: Malla poligonal con control_points (lista de vértices) y polygons.
  • VertexElementNormal: Vectores normales por vértice o por polígono.
  • VertexElementUV: Coordenadas de textura UV por vértice.
  • VertexElementVertexColor: Datos de color por vértice.
  • VertexElementSmoothingGroup: Asignaciones de grupos de suavizado de polígonos.

Materiales

  • LambertMaterial: Modelo de sombreado difuso con diffuse_color y emissive_color.
  • PhongMaterial: Modelo de sombreado especular que añade specular_color y shininess.

Utilidades matemáticas (aspose.threed.utilities)

  • Vector2: Vector 2D.
  • Vector3: Vector 3D de doble precisión.
  • Vector4: Vector 4D de doble precisión.
  • FVector3: Vector 3D de precisión simple.
  • Quaternion: Cuaternión de rotación con from_angle_axis() : y to_matrix().
  • Matrix4: Matriz de transformación 4×4.
  • BoundingBox: Caja delimitadora alineada a los ejes con minimum : y maximum : esquinas.

Animación

  • AnimationClip: Contenedor con nombre para un conjunto de canales de animación y sus fotogramas clave.
  • AnimationNode: Datos de animación por nodo dentro de un clip.
  • KeyFrame: Fotograma clave único con tiempo y valor.
  • KeyframeSequence: Secuencia ordenada de fotogramas clave para una única propiedad animada.

Opciones de carga / guardado

  • ObjLoadOptions: Configuraciones de carga específicas de OBJ: enable_materials, flip_coordinate_system, normalize_normal, scale.
  • StlSaveOptions: Configuraciones de guardado específicas de STL (modo binario vs. modo ASCII).

Cámaras y luces

  • Camera: Entidad de cámara con configuraciones de proyección, adjuntable a una Node.
  • Light: Entidad de fuente de luz, adjuntable a una Node.
 Español