Caracteristici și Funcționalități
Aspose.3D FOSS pentru Python oferă un API complet de graf de scenă pentru citirea, construirea și scrierea conținutului 3D în multiple formate standard din industrie. Această pagină documentează fiecare zonă majoră de funcționalitate cu exemple de cod Python funcționale care utilizează API-ul real al bibliotecii.
Instalare și configurare
Instalați biblioteca din PyPI cu o singură comandă:
pip install aspose-3d-fossNu sunt necesare pachete suplimentare de sistem, extensii native sau lanțuri de instrumente de compilare. Biblioteca este pur Python și suportă Python 3.7 până la 3.12 pe Windows, macOS și Linux.
Pentru a verifica instalarea:
from aspose.threed import Scene
scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")Caracteristici și Funcționalități
Suport pentru formate
Aspose.3D FOSS pentru Python citește și scrie următoarele formate:
| Format | Extensie | Citire | Scriere | Note |
|---|---|---|---|---|
| Wavefront OBJ | .obj | Da | Da | .mtl încărcarea materialelor suportată |
| STL (binare) | .stl | Da | Da | Verificare roundtrip (39 teste) |
| STL (ASCII) | .stl | Da | Da | Verificare roundtrip |
| glTF 2.0 | .gltf | Da | Da | Graficul complet al scenei păstrat |
| GLB (binary glTF) | .glb | Da | Da | Container binar cu un singur fișier |
| COLLADA | .dae | Da | Da | Ierarhia scenei și materialele |
| 3MF | .3mf | Da | Da | Format de fabricație aditivă |
| FBX | .fbx | Parțial | Nu | Tokenizatorul funcționează; parserul are buguri cunoscute |
Încărcarea OBJ cu opțiuni
ObjLoadOptions controlează modul în care fișierele OBJ sunt analizate:
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")Salvarea în STL
StlSaveOptions controlează ieșirea binară vs. ASCII și alte setări specifice 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)Graf de scenă
Tot conținutul 3D este organizat ca un arbore de Node obiecte. Rădăcina arborelui este scene.root_node. Fiecare nod poate conține noduri copil și poate purta un Entity (mesh, cameră sau lumină) plus un Transform.
Parcurgerea ierarhiei scenei
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)Construirea unei scene programatic
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")Inspectarea GlobalTransform
GlobalTransform furnizează transformarea în spațiul lumii a unui nod după acumularea tuturor transformărilor strămoșilor:
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
The Mesh entitatea oferă acces la datele geometrice, inclusiv punctele de control (vârfuri), poligoanele și elementele de vârf pentru normale, UV-uri și culori.
Citirea geometriei 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)}")Accesarea elementelor de vârf
Elementele de vârf conțin date per-vârf sau per-poligon. Cele mai comune elemente sunt normalele, coordonatele UV, culorile vârfului și grupurile de netezire:
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)}")Sistem de materiale
Aspose.3D FOSS suportă două tipuri de material: LambertMaterial (umbrire difuză) și PhongMaterial (specular shading). Ambele sunt încărcate automat din fișiere .mtl când se folosește ObjLoadOptions cu enable_materials = True.
Citirea materialelor din 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}")Atribuirea unui material programatic
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")Utilitare matematice
The aspose.threed.utilities modulul furnizează toate tipurile de matematică geometrică necesare pentru construcția și inspecția scenei.
| Clasă | Scop |
|---|---|
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 | Reprezentare a rotației fără blocaj de tip gimbal |
Matrix4 | 4×4 transformation matrix |
BoundingBox | Cutie de delimitare aliniată pe axe cu colțuri min/max |
Lucrul cu transformări
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}")Calcularea unei cutii de delimitare
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ție
Aspose.3D FOSS furnizează un model de animație bazat pe AnimationClip, AnimationNode, KeyFrame, și KeyframeSequence. Datele de animație stocate în fișierele încărcate (glTF, COLLADA) sunt accesibile prin aceste obiecte.
Citirea clipurilor de animație
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țiuni de încărcare și salvare
Fiecare format acceptat are o clasă de opțiuni corespunzătoare care controlează comportamentul de parsare și serializare.
| Clasă | Format | Proprietăți cheie |
|---|---|---|
ObjLoadOptions | OBJ | enable_materials, flip_coordinate_system, normalize_normal, scale |
StlSaveOptions | STL | Mod de ieșire binar vs. ASCII |
| (glTF folosește valorile implicite) | glTF / GLB | Graful scenei și materialele sunt păstrate automat |
Exemple de utilizare
Exemplul 1: Conversia formatului OBJ în STL
Convertește un fișier OBJ (cu materiale) în STL binar, afișând statisticile rețelei pe parcurs:
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")Exemplul 2: Ambalare în lot a glTF în GLB
Re-salvează un director cu fișiere glTF + texturi separate ca binare GLB autonome:
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)}")Exemplul 3: Inspecția graficului de scenă și raportul de export
Parcurge graficul de scenă al unui fișier COLLADA, colectează statistici pe fiecare rețea și afișează un raport structurat:
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}"
)Sfaturi și bune practici
Selectarea formatului
- glTF 2.0 / GLB este formatul de interschimb recomandat pentru scene care includ materiale, animații și ierarhii complexe. Preferă GLB (binare) în loc de glTF (text + fișiere externe) pentru portabilitate.
- STL este alegerea potrivită atunci când consumatorul din aval este un slicer, un instrument CAD sau orice alt instrument care are nevoie doar de geometrie. STL nu conține date de material sau animație.
- OBJ este larg suportat și o alegere bună atunci când datele de material trebuie să fie schimbate cu instrumente mai vechi. Păstrează întotdeauna fișierul .mtl alături de fișierul .obj.
Sisteme de coordonate
- Aplicațiile diferite folosesc convenții diferite de orientare a axelor. Set
ObjLoadOptions.flip_coordinate_system = Truecând importați fișiere OBJ din instrumente care utilizează un sistem de coordonate drept, dacă pipeline‑ul dvs. așteaptă coordonate stânga, și invers. - Verificați convenția axelor activului sursă înainte de a aplica orice inversare. Inversarea de două ori produce geometrie incorectă.
Normalizare
- Setați întotdeauna
ObjLoadOptions.normalize_normal = Truecând pipeline‑ul din aval așteaptă normale unitare (de exemplu, când transmiteți normalele către un shader sau efectuați calcule de iluminare prin produs scalar). Normalele neunitare din fișiere OBJ prost formate cauzează artefacte de iluminare.
Performanță
- Încărcați fișierele o singură dată și transformați graful de scenă în memorie în loc să le reîncărcați de pe disc pentru fiecare format de ieșire. Un singur
Scene.from_file()apel urmat de multiplescene.save()apeluri este mai eficient decât încărcările repetate. - Când procesați loturi mari, construiți un singur
ObjLoadOptionssauStlSaveOptionsinstanță și reutilizați‑o în toate fișierele în loc să construiți un nou obiect de opțiuni pentru fiecare fișier.
Gestionarea erorilor
- Înfășurați
scene.open()șiscene.save()apeluri întry/exceptblocuri când se procesează fișiere neîncredere sau furnizate de utilizator. Raportați numele fișierului în mesajele de excepție pentru a simplifica depanarea în pipeline-uri batch.
Probleme comune
| Problemă | Cauză | Rezolvare |
|---|---|---|
| Plasa apare oglindită după încărcare | Neconcordanță a orientării sistemului de coordonate | Comută ObjLoadOptions.flip_coordinate_system |
| Normalele au lungime zero | Fișierul sursă are normale ne-normalizate | Setare ObjLoadOptions.normalize_normal = True |
| Materiale neîncărcate din OBJ | enable_materials este False (implicit) | Setare ObjLoadOptions.enable_materials = True |
| Scena se încarcă, dar toate nodurile sunt goale | Fișierul folosește formatul FBX | Parserul FBX este în dezvoltare; folosește în schimb OBJ, STL sau glTF |
| Modelul este extrem de mic sau mare | Fișierul sursă folosește unități non-metrice | Aplică ObjLoadOptions.scale pentru a converti la unitatea țintă |
AttributeError pe mesh.polygons | Entitatea nod nu este un Mesh | Protecție cu if node.entity is not None înainte de a accesa proprietățile entității |
| Fișierul GLB este respins de vizualizator | Salvat cu .gltf extensie | Utilizați .glb extensie când apelați scene.save() pentru a declanșa containerul binar |
Întrebări frecvente
Ce versiuni Python sunt suportate? Python 3.7, 3.8, 3.9, 3.10, 3.11 și 3.12 sunt toate suportate. Biblioteca este pur Python fără nicio extensie nativă, așa că funcționează pe orice platformă pe care rulează CPython.
Are biblioteca dependențe externe? Nu. Aspose.3D FOSS pentru Python folosește doar biblioteca standard Python. Se instalează ca un singur pip install aspose-3d-foss comandă, fără pași suplimentari.
Este FBX suportat? Tokenizerul FBX este implementat și poate analiza fluxul binar de tokenuri FBX, dar constructorul de graf de scenă deasupra tokenizerului are buguri cunoscute și nu este pregătit pentru producție. Folosiți OBJ, STL, glTF, COLLADA sau 3MF pentru utilizare în producție fiabilă.
Pot folosi Aspose.3D FOSS într-un produs comercial? Da. Biblioteca este lansată sub licența MIT, care permite utilizarea în software proprietar și comercial fără plăți de redevențe, cu condiția să fie inclusă notificarea de licență.
Cum raportez un bug sau solicit un format? Deschideți o problemă în depozit. Includeți un fișier minimal de reproducere și versiunea Python, sistemul de operare și versiunea bibliotecii din pip show aspose-3d-foss.
Rezumat al referinței API
Clase de bază
Scene: Container de nivel superior pentru o scenă 3D. Punct de intrare pentruopen(),from_file(),: , șisave().Node: Nod de arbore în graficul scenei. Poartăentity,transform,global_transform,material,child_nodes,: , șiname.Entity: Clasă de bază pentru obiectele atașate nodurilor (Mesh, Camera, Light).Transform: Poziție, rotație (Quaternion) și scară în spațiul local pentru un nod.GlobalTransform: Transformare în spațiul mondial doar în citire, calculată prin acumularea tuturor transformărilor strămoșilor.
Geometrie
Mesh: Plasă poligonală cucontrol_points: (listă de vârfuri) șipolygons.VertexElementNormal: Vectori normali per-vârf sau per-poligon.VertexElementUV: Coordonate de textură UV per-vârf.VertexElementVertexColor: Date de culoare per-vertex.VertexElementSmoothingGroup: Atribuiri de grupuri de netezire a poligoanelor.
Materiale
LambertMaterial: Model de umbrire difuză cudiffuse_color: șiemissive_color.PhongMaterial: Model de umbrire speculară care adaugăspecular_color: șishininess.
: Utilitare matematice (aspose.threed.utilities)
Vector2: Vector 2D.Vector3: Vector 3D cu precizie dublă.Vector4: Vector 4D cu precizie dublă.FVector3: Vector 3D cu precizie simplă.Quaternion: Quaternion de rotație cufrom_angle_axis(): șito_matrix().Matrix4: matrice de transformare 4×4.BoundingBox: Cutie de delimitare aliniată pe axe cuminimum: șimaximum: colțuri.
Animație
AnimationClip: Container denumit pentru un set de canale de animație și cadrele lor cheie.AnimationNode: Date de animație pe nod în cadrul unui clip.KeyFrame: Cadru cheie unic cu timp și valoare.KeyframeSequence: Secvență ordonată de cadre cheie pentru o singură proprietate animată.
Opțiuni de încărcare / salvare
ObjLoadOptions: Setări de încărcare specifice OBJ:enable_materials,flip_coordinate_system,normalize_normal,scale.StlSaveOptions: Setări de salvare specifice STL (mod binar vs. mod ASCII).
Camere și lumini
Camera: Entitate de cameră cu setări de proiecție, atașabilă la unNode.Light: Entitate de sursă de lumină, atașabilă la unNode.