Caratteristiche e funzionalità
Aspose.3D FOSS per Python fornisce un’API completa di scene-graph per leggere, costruire e scrivere contenuti 3D in più formati standard del settore. Questa pagina documenta ogni area funzionale principale con esempi di codice Python funzionanti che utilizzano l’API reale della libreria.
Installazione e configurazione
Installa la libreria da PyPI con un unico comando:
pip install aspose-3d-fossNon sono richiesti pacchetti di sistema aggiuntivi, estensioni native o toolchain del compilatore. La libreria è puramente Python e supporta Python 3.7 fino a 3.12 su Windows, macOS e Linux.
Per verificare l’installazione:
from aspose.threed import Scene
scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")Caratteristiche e funzionalità
Supporto dei formati
Aspose.3D FOSS per Python legge e scrive i seguenti formati:
| Formato | Estensione | Lettura | Scrittura | Note |
|---|---|---|---|---|
| Wavefront OBJ | .obj | Sì | Sì | .Caricamento materiale .mtl supportato |
| STL (binario) | .stl | Sì | Sì | Roundtrip verificato (39 test) |
| STL (ASCII) | .stl | Sì | Sì | Roundtrip verificato |
| glTF 2.0 | .gltf | Sì | Sì | Grafo della scena completo preservato |
| GLB (binary glTF) | .glb | Sì | Sì | Contenitore binario a file singolo |
| COLLADA | .dae | Sì | Sì | Gerarchia della scena e materiali |
| 3MF | .3mf | Sì | Sì | Formato per la produzione additiva |
| FBX | .fbx | Parziale | No | Tokenizer funzionante; il parser ha bug noti |
Caricamento OBJ con opzioni
ObjLoadOptions controlla come vengono analizzati i file 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")Salvataggio in STL
StlSaveOptions controlla l’output binario vs. ASCII e altre impostazioni specifiche per 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)Scene Graph
Tutti i contenuti 3D sono organizzati come un albero di Node oggetti. La radice dell’albero è scene.root_node. Ogni nodo può contenere nodi figli e trasportare un Entity (mesh, camera o light) più un Transform.
Attraversamento della gerarchia della scena
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)Costruire una scena programmaticamente
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")Ispezionare GlobalTransform
GlobalTransform fornisce la trasformazione nello spazio mondiale di un nodo dopo aver accumulato tutte le trasformazioni dei suoi antenati:
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
Il Mesh l’entità fornisce l’accesso ai dati geometrici includendo i punti di controllo (vertici), i poligoni e gli elementi dei vertici per normali, UV e colori.
Lettura della geometria 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)}")Accesso agli elementi dei vertici
Gli elementi dei vertici contengono dati per vertice o per poligono. Gli elementi più comuni sono le normali, le coordinate UV, i colori dei vertici e i gruppi di smoothing:
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 dei materiali
Aspose.3D FOSS supporta due tipi di materiale: LambertMaterial (ombreggiatura diffusa) e PhongMaterial (ombreggiatura speculare). Entrambi vengono caricati automaticamente dai file .mtl quando si utilizza ObjLoadOptions con enable_materials = True.
Lettura dei materiali da 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}")Assegnazione di un materiale tramite codice
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")Utility matematiche
Il aspose.threed.utilities module fornisce tutti i tipi matematici geometrici necessari per la costruzione e l’ispezione della scena.
| Classe | Scopo |
|---|---|
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 | Rappresentazione della rotazione senza gimbal lock |
Matrix4 | 4×4 transformation matrix |
BoundingBox | Bounding box allineato agli assi con angoli min/max |
Lavorare con le trasformazioni
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}")Calcolo di un Bounding Box
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})")Animazione
Aspose.3D FOSS fornisce un modello di animazione basato su AnimationClip, AnimationNode, KeyFrame, e KeyframeSequence. I dati di animazione memorizzati nei file caricati (glTF, COLLADA) sono accessibili tramite questi oggetti.
Lettura dei clip di animazione
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}")Opzioni di caricamento e salvataggio
Ogni formato supportato ha una classe di opzioni corrispondente che controlla il comportamento di parsing e serializzazione.
| Classe | Formato | Proprietà chiave |
|---|---|---|
ObjLoadOptions | OBJ | enable_materials, flip_coordinate_system, normalize_normal, scale |
StlSaveOptions | STL | Modalità di output binario vs. ASCII |
| (glTF usa i valori predefiniti) | glTF / GLB | Grafico della scena e materiali preservati automaticamente |
Esempi di utilizzo
Esempio 1: Conversione da OBJ a STL
Converti un file OBJ (con i materiali) in STL binario, stampando le statistiche della mesh lungo il percorso:
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")Esempio 2: Impacchettamento batch da glTF a GLB
Risalva una directory di file glTF + texture separati come binari GLB autonomi:
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)}")Esempio 3: Ispezione del grafo della scena e rapporto di esportazione
Scorri il grafo della scena di un file COLLADA, raccogli le statistiche per mesh e stampa un rapporto strutturato:
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}"
)Suggerimenti e migliori pratiche
Selezione del formato
- glTF 2.0 / GLB è il formato di interscambio consigliato per scene che includono materiali, animazioni e gerarchie complesse. Preferire GLB (binario) rispetto a glTF (testo + file esterni) per la portabilità.
- STL è la scelta giusta quando il consumatore a valle è un slicer, uno strumento CAD o qualsiasi tool che necessita solo della geometria. STL non contiene dati di materiale o animazione.
- OBJ è ampiamente supportato ed è una buona scelta quando i dati dei materiali devono essere scambiati con strumenti più vecchi. Conserva sempre il file .mtl accanto al file .obj.
Sistemi di coordinate
- Le diverse applicazioni usano convenzioni di mano diverse. Imposta
ObjLoadOptions.flip_coordinate_system = Truequando importi file OBJ da strumenti che usano un sistema di coordinate destro se il tuo flusso di lavoro si aspetta coordinate sinistre, e viceversa. - Verifica la convenzione degli assi dell’asset di origine prima di applicare qualsiasi ribaltamento. Ribaltare due volte produce geometria errata.
Normalizzazione
- Imposta sempre
ObjLoadOptions.normalize_normal = Truequando il flusso di lavoro a valle si aspetta normali unitarie (ad esempio, quando si passano le normali a uno shader o si eseguono calcoli di illuminazione a prodotto scalare). Normali non normalizzate da file OBJ malformati causano artefatti di illuminazione.
Prestazioni
- Carica i file una sola volta e trasforma il grafo della scena in memoria invece di ricaricare dal disco per ogni formato di output. Un singolo
Scene.from_file()chiamata seguita da piùscene.save()chiamate è più efficiente rispetto a caricamenti ripetuti. - Durante l’elaborazione di grandi lotti, costruisci un unico
ObjLoadOptionsoStlSaveOptionsistanza e riutilizzala per tutti i file invece di creare un nuovo oggetto di opzioni per ogni file.
Gestione degli errori
- Avvolgere
scene.open()escene.save()chiamate intry/exceptblocchi quando si elaborano file non attendibili o forniti dall’utente. Riporta il nome del file nei messaggi di eccezione per semplificare il debug nei pipeline batch.
Problemi comuni
| Problema | Cause | Risoluzione |
|---|---|---|
| La mesh appare specchiata dopo il caricamento | Discrepanza dell’orientamento del sistema di coordinate | Commuta ObjLoadOptions.flip_coordinate_system |
| Le normali hanno lunghezza zero | Il file sorgente contiene normali non normalizzate | Imposta ObjLoadOptions.normalize_normal = True |
| Materiali non caricati dal file OBJ | enable_materials è False (predefinito) | Imposta ObjLoadOptions.enable_materials = True |
| La scena si carica ma tutti i nodi sono vuoti | Il file utilizza il formato FBX | Il parser FBX è in sviluppo; usa OBJ, STL o glTF invece |
| Il modello è estremamente piccolo o grande | Il file di origine utilizza unità non metriche | Applica ObjLoadOptions.scale per convertire nella tua unità di destinazione |
AttributeError acceso mesh.polygons | L’entità nodo non è una Mesh | Proteggi con if node.entity is not None prima di accedere alle proprietà dell’entità |
| Il file GLB è rifiutato dal visualizzatore | Salvato con .gltf estensione | Usa .glb estensione quando chiami scene.save() per attivare il contenitore binario |
Domande frequenti
Quali versioni di Python sono supportate? Python 3.7, 3.8, 3.9, 3.10, 3.11 e 3.12 sono tutti supportati. La libreria è pure Python senza estensioni native, quindi funziona su qualsiasi piattaforma in cui gira CPython.
La libreria ha dipendenze esterne? No. Aspose.3D FOSS per Python utilizza solo la libreria standard Python. Si installa come un unico pip install aspose-3d-foss comando senza passaggi successivi.
Il formato FBX è supportato? Il tokenizer FBX è implementato e può analizzare il flusso di token binario FBX, ma il costruttore del grafo della scena sopra il tokenizer presenta bug noti e non è pronto per la produzione. Usa OBJ, STL, glTF, COLLADA o 3MF per un uso affidabile in produzione.
Posso usare Aspose.3D FOSS in un prodotto commerciale? Sì. La libreria è rilasciata sotto licenza MIT, che consente l’uso in software proprietario e commerciale senza pagamenti di royalty, a condizione che l’avviso di licenza sia incluso.
Come posso segnalare un bug o richiedere un formato? Apri un problema nel repository. Includi un file riproduttore minimo e la versione Python, il sistema operativo e la versione della libreria da pip show aspose-3d-foss.
Sommario del Riferimento API
Classi principali
Scene: Contenitore di livello superiore per una scena 3D. Punto di ingresso peropen(),from_file(), esave().Node: Nodo dell’albero nel grafo della scena. Trasportaentity,transform,global_transform,material,child_nodes, ename.Entity: Classe base per gli oggetti collegati ai nodi (Mesh, Camera, Light).Transform: Posizione, rotazione (Quaternion) e scala nello spazio locale per un nodo.GlobalTransform: Trasformazione in spazio mondiale di sola lettura calcolata accumulando tutte le trasformazioni dei genitori.
Geometria
Mesh: Mesh poligonale concontrol_points(elenco dei vertici) epolygons.VertexElementNormal: Vettori normali per vertice o per poligono.VertexElementUV: Coordinate di texture UV per vertice.VertexElementVertexColor: Dati di colore per vertice.VertexElementSmoothingGroup: Assegnazioni dei gruppi di smussatura dei poligoni.
Materiali
LambertMaterial: Modello di shading diffuso condiffuse_coloreemissive_color.PhongMaterial: Aggiunta del modello di shading specularespecular_color: eshininess.
: Utility matematiche (aspose.threed.utilities)
Vector2: vettore 2D.Vector3: vettore 3D a doppia precisione.Vector4: vettore 4D a doppia precisione.FVector3: vettore 3D a precisione singola.Quaternion: quaternione di rotazione confrom_angle_axis()eto_matrix().Matrix4: matrice di trasformazione 4×4.BoundingBox: bounding box allineato agli assi conminimumemaximum: vertici.
Animazione
AnimationClip: contenitore denominato per un insieme di canali di animazione e i loro fotogrammi chiave.AnimationNode: dati di animazione per nodo all’interno di una clip.KeyFrame: fotogramma chiave singolo con tempo e valore.KeyframeSequence: sequenza ordinata di fotogrammi chiave per una singola proprietà animata.
Opzioni di caricamento / salvataggio
ObjLoadOptions: impostazioni di caricamento specifiche per OBJ:enable_materials,flip_coordinate_system,normalize_normal,scale.StlSaveOptions: impostazioni di salvataggio specifiche per STL (modalità binaria vs. ASCII).
Telecamere e luci
Camera: entità fotocamera con impostazioni di proiezione, attaccabile a unNode.Light: Entità sorgente luminosa, attaccabile a unaNode.