Funkcje i możliwości
Aspose.3D FOSS dla Python zapewnia kompletny interfejs API grafu sceny do odczytu, tworzenia i zapisu treści 3D w wielu standardowych formatach branżowych. Ta strona dokumentuje każdy główny obszar funkcji wraz z działającymi przykładami kodu Python, które używają rzeczywistego API biblioteki.
Instalacja i konfiguracja
Zainstaluj bibliotekę z PyPI za pomocą jednego polecenia:
pip install aspose-3d-fossNie są wymagane dodatkowe pakiety systemowe, natywne rozszerzenia ani łańcuchy narzędzi kompilatora. Biblioteka jest czystym Python i obsługuje Python 3.7‑3.12 na Windows, macOS i Linux.
Aby zweryfikować instalację:
from aspose.threed import Scene
scene = Scene()
print("Aspose.3D FOSS installed successfully")
print(f"Root node name: {scene.root_node.name}")Funkcje i możliwości
Obsługa formatów
Aspose.3D FOSS dla Python odczytuje i zapisuje następujące formaty:
| Format | Rozszerzenie | Odczyt | Zapis | Uwagi |
|---|---|---|---|---|
| Wavefront OBJ | .obj | Tak | Tak | .obsługa ładowania materiałów .mtl |
| STL (binarny) | .stl | Tak | Tak | Weryfikacja roundtrip (39 testów) |
| STL (ASCII) | .stl | Tak | Tak | Weryfikacja roundtrip |
| glTF 2.0 | .gltf | Tak | Tak | Pełny graf sceny zachowany |
| GLB (binary glTF) | .glb | Tak | Tak | Jednoplikowy kontener binarny |
| COLLADA | .dae | Tak | Tak | Hierarchia sceny i materiały |
| 3MF | .3mf | Tak | Tak | Format produkcji przyrostowej |
| FBX | .fbx | Częściowy | Nie | Tokenizer działa; parser ma znane błędy |
Ładowanie OBJ z opcjami
ObjLoadOptions kontroluje sposób parsowania plików 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")Zapisywanie do STL
StlSaveOptions kontroluje wyjście binarne vs. ASCII oraz inne ustawienia specyficzne dla 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 sceny
Cała zawartość 3D jest organizowana jako drzewo Node obiektów. Korzeń drzewa to scene.root_node. Każdy węzeł może zawierać węzły potomne i posiadać Entity (siatkę, kamerę lub światło) plus Transform.
Przeglądanie hierarchii sceny
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)Tworzenie sceny programowo
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")Inspekcja GlobalTransform
GlobalTransform określa transformację w przestrzeni świata węzła po zsumowaniu wszystkich transformacji przodków:
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 siatki
Ten Mesh encja zapewnia dostęp do danych geometrycznych, w tym punktów kontrolnych (wierzchołków), wielokątów oraz elementów wierzchołków dla normalnych, UV i kolorów.
Odczytywanie geometrii siatki
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)}")Dostęp do elementów wierzchołkowych
Elementy wierzchołkowe zawierają dane per-wierzchołkowe lub per-wielokątne. Najbardziej powszechne elementy to normalne, współrzędne UV, kolory wierzchołków oraz grupy wygładzania:
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)}")System materiałów
Aspose.3D FOSS obsługuje dwa typy materiałów: LambertMaterial (cieniowanie dyfuzyjne) i PhongMaterial (specular shading). Oba są ładowane automatycznie z plików .mtl podczas używania ObjLoadOptions z enable_materials = True.
Odczytywanie materiałów z 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}")Przypisywanie materiału programowo
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")Narzędzia matematyczne
Ten aspose.threed.utilities moduł zapewnia wszystkie typy matematyki geometrycznej potrzebne do konstrukcji i inspekcji sceny.
| Klasa | Cel |
|---|---|
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 | Reprezentacja rotacji bez zjawiska gimbal lock |
Matrix4 | 4×4 transformation matrix |
BoundingBox | Prostopadłościan ograniczający wyrównany do osi z narożnikami min/max |
Praca z transformacjami
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}")Obliczanie pudełka ograniczającego
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})")Animacja
Aspose.3D FOSS udostępnia model animacji oparty na AnimationClip, AnimationNode, KeyFrame, oraz KeyframeSequence. Dane animacji przechowywane w załadowanych plikach (glTF, COLLADA) są dostępne poprzez te obiekty.
Odczytywanie klipów animacji
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}")Opcje ładowania i zapisu
Każdy obsługiwany format ma odpowiadającą mu klasę opcji, która kontroluje zachowanie parsowania i serializacji.
| Klasa | Format | Kluczowe właściwości |
|---|---|---|
ObjLoadOptions | OBJ | enable_materials, flip_coordinate_system, normalize_normal, scale |
StlSaveOptions | STL | Tryb wyjścia binarny vs. ASCII |
| (glTF używa wartości domyślnych) | glTF / GLB | Graf sceny i materiały zachowywane automatycznie |
Przykłady użycia
Przykład 1: Konwersja formatu OBJ do STL
Konwertuj plik OBJ (z materiałami) do binarnego STL, wypisując statystyki siatki w trakcie:
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")Przykład 2: Pakowanie wsadowe glTF do GLB
Zapisz ponownie katalog oddzielnych plików glTF + tekstur jako samodzielne pliki binarne GLB:
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)}")Przykład 3: Inspekcja grafu sceny i raport eksportu
Przejdź graf sceny pliku COLLADA, zbierz statystyki dla każdej siatki i wydrukuj ustrukturyzowany raport:
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}"
)Wskazówki i najlepsze praktyki
Wybór formatu
- glTF 2.0 / GLB jest zalecanym formatem wymiany dla scen, które zawierają materiały, animacje i złożone hierarchie. Preferuj GLB (binarny) zamiast glTF (tekst + pliki zewnętrzne) ze względu na przenośność.
- STL jest właściwym wyborem, gdy odbiorcą końcowym jest slicer, narzędzie CAD lub jakiekolwiek narzędzie potrzebujące jedynie geometrii. STL nie zawiera danych o materiałach ani animacjach.
- OBJ jest szeroko wspierany i dobrym wyborem, gdy dane materiałowe muszą być wymieniane ze starszymi narzędziami. Zawsze przechowuj plik .mtl razem z plikiem .obj.
Systemy współrzędnych
- Różne aplikacje używają różnych konwencji praworęczności. Ustaw
ObjLoadOptions.flip_coordinate_system = Trueprzy importowaniu plików OBJ z narzędzi, które używają układu współrzędnych praworęcznego, jeśli Twój potok oczekuje współrzędnych leworęcznych, i odwrotnie. - Sprawdź konwencję osi źródłowego zasobu przed zastosowaniem jakiegokolwiek odbicia. Podwójne odbicie powoduje nieprawidłową geometrię.
Normalizacja
- Zawsze ustaw
ObjLoadOptions.normalize_normal = Truegdy downstreamowy potok oczekuje jednostkowych wektorów normalnych (na przykład przy przekazywaniu normalnych do shadera lub wykonywaniu obliczeń oświetlenia przy użyciu iloczynu skalarnego). Nieznormalizowane wektory normalne z źle sformatowanych plików OBJ powodują artefakty oświetleniowe.
Wydajność
- Wczytuj pliki raz i przekształcaj scenę w pamięci zamiast ponownego ładowania z dysku dla każdego formatu wyjściowego. Jedno
Scene.from_file()wywołanie, po którym następuje wielescene.save()wywołań jest bardziej wydajne niż wielokrotne ładowania. - Podczas przetwarzania dużych partii, utwórz pojedynczy
ObjLoadOptionslubStlSaveOptionsinstancję i używaj jej we wszystkich plikach zamiast tworzyć nowy obiekt opcji dla każdego pliku.
Obsługa błędów
- Zawijaj
scene.open()iscene.save()wywołania wtry/exceptbloki podczas przetwarzania nieufnych lub dostarczonych przez użytkownika plików. Zgłaszaj nazwę pliku w komunikatach wyjątków, aby uprościć debugowanie w potokach wsadowych.
Typowe problemy
| Problem | Przyczyna | Rozwiązanie |
|---|---|---|
| Siatka wydaje się odbita lustrzanie po załadowaniu | Niezgodność orientacji systemu współrzędnych | Przełącz ObjLoadOptions.flip_coordinate_system |
| Normalne mają zerową długość | Plik źródłowy ma nieznormalizowane wektory normalne | Ustaw ObjLoadOptions.normalize_normal = True |
| Materiały nie zostały załadowane z OBJ | enable_materials jest False (domyślnie) | Ustaw ObjLoadOptions.enable_materials = True |
| Scena ładuje się, ale wszystkie węzły są puste | Plik używa formatu FBX | Parser FBX jest w trakcie tworzenia; użyj zamiast tego OBJ, STL lub glTF |
| Model jest niezwykle mały lub duży | Plik źródłowy używa jednostek nie‑metrycznych | Zastosuj ObjLoadOptions.scale aby przeliczyć na jednostkę docelową |
AttributeError na mesh.polygons | Encja węzła nie jest siatką | Zabezpiecz przy użyciu if node.entity is not None przed dostępem do właściwości encji |
| Plik GLB został odrzucony przez przeglądarkę | Zapisano z .gltf rozszerzenie | Użyj .glb rozszerzenie przy wywoływaniu scene.save() aby uruchomić kontener binarny |
Najczęściej zadawane pytania
Jakie wersje Python są obsługiwane? Python 3.7, 3.8, 3.9, 3.10, 3.11 i 3.12 są wszystkie obsługiwane. Biblioteka jest czystym Python bez natywnych rozszerzeń, więc działa na każdej platformie, na której działa CPython.
Czy biblioteka ma jakiekolwiek zewnętrzne zależności? Nie. Aspose.3D FOSS dla Python używa wyłącznie standardowej biblioteki Python. Instalacja odbywa się jako pojedynczy pip install aspose-3d-foss polecenie bez dodatkowych kroków.
Czy FBX jest obsługiwany? Tokenizer FBX jest zaimplementowany i potrafi parsować binarny strumień tokenów FBX, ale konstruktor grafu sceny oparty na tokenizerze ma znane błędy i nie jest gotowy do produkcji. Użyj OBJ, STL, glTF, COLLADA lub 3MF do niezawodnego zastosowania produkcyjnego.
Czy mogę używać Aspose.3D FOSS w produkcie komercyjnym? Tak. Biblioteka jest wydana na licencji MIT, która zezwala na użycie w oprogramowaniu własnościowym i komercyjnym bez opłat licencyjnych, pod warunkiem dołączenia informacji o licencji.
Jak zgłosić błąd lub poprosić o format? Otwórz zgłoszenie w repozytorium. Dołącz minimalny plik reprodukujący oraz wersję Python, system operacyjny i wersję biblioteki z pip show aspose-3d-foss.
Podsumowanie referencji API
Klasy podstawowe
Scene: Kontener najwyższego poziomu dla sceny 3D. Punkt wejścia dlaopen(),from_file(), isave().Node: Węzeł drzewa w grafie sceny. Zawieraentity,transform,global_transform,material,child_nodes, iname.Entity: Klasa bazowa dla obiektów dołączonych do węzłów (Mesh, Camera, Light).Transform: Pozycja, rotacja (Quaternion) i skala w przestrzeni lokalnej dla węzła.GlobalTransform: Transformacja w przestrzeni światowej tylko do odczytu, obliczana przez kumulowanie wszystkich transformacji przodków.
Geometry
Mesh: Siatka wielokątowa zcontrol_points(lista wierzchołków) ipolygons.VertexElementNormal: Wektory normalne per-wierzchołkowe lub per-wielokątne.VertexElementUV: Współrzędne tekstury UV per-wierzchołkowe.VertexElementVertexColor: Dane koloru per‑wierzchołkowe.VertexElementSmoothingGroup: Przypisania grup wygładzania wielokątów.
Materiały
LambertMaterial: Model cieniowania rozproszonego zdiffuse_color: iemissive_color.PhongMaterial: Model cieniowania odbicia dodającyspecular_color: ishininess.
: Narzędzia matematyczne (aspose.threed.utilities)
Vector2: Wektor 2D.Vector3: Wektor 3D podwójnej precyzji.Vector4: Wektor 4D podwójnej precyzji.FVector3: Wektor 3D pojedynczej precyzji.Quaternion: Quaternion obrotu zfrom_angle_axis(): ito_matrix().Matrix4: macierz przekształcenia 4×4.BoundingBox: Prostopadłościan ograniczający wyrównany do osi zminimum: imaximum: wierzchołkami.
Animacja
AnimationClip: Nazwany kontener dla zestawu kanałów animacji i ich klatek kluczowych.AnimationNode: Dane animacji per-węzeł w klipie.KeyFrame: Pojedyncza klatka kluczowa z czasem i wartością.KeyframeSequence: Uporządkowana sekwencja klatek kluczowych dla jednej animowanej właściwości.
Opcje ładowania / zapisu
ObjLoadOptions: Ustawienia ładowania specyficzne dla OBJ:enable_materials,flip_coordinate_system,normalize_normal,scale.StlSaveOptions: Ustawienia zapisu specyficzne dla STL (tryb binarny vs. tryb ASCII).
Kamery i światła
Camera: Obiekt kamery z ustawieniami projekcji, możliwy do dołączenia do aNode.Light: Obiekt źródła światła, możliwy do dołączenia do aNode.