Hoe 3D-modellen te laden in Python
Aspose.3D FOSS for Python biedt een eenvoudige API voor het openen van 3D‑bestanden zonder native afhankelijkheden. Na het laden van een bestand in een Scene‑object kun je door de knoophierarchie lopen en ruwe geometrie‑gegevens lezen voor elke mesh in de scène.
Stapsgewijze handleiding
Stap 1: Installeer het pakket
Installeer Aspose.3D FOSS vanaf PyPI. Er zijn geen extra systeembibliotheken vereist.
pip install aspose-3d-fossOndersteunde Python‑versies: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Stap 2: Importeer de Scene Class
De Scene-klasse is de top-level container voor alle 3D-gegevens. Importeer deze samen met alle laadoptieklassen die u nodig heeft.
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptionsAlle openbare klassen bevinden zich onder aspose.threed of in de sub‑pakketten daarvan (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).
Stap 3: Een bestand laden
Gebruik de statische Scene.from_file()‑methode om elk ondersteund formaat te openen. De bibliotheek detecteert het formaat automatisch op basis van de bestandsextensie.
##Automatic format detection
scene = Scene.from_file("model.obj")Maak eventueel een Scene-instantie aan en roep open() aan; handig wanneer je laadopties wilt doorgeven of fouten expliciet wilt afhandelen:
scene = Scene()
scene.open("model.obj")Beide methoden ondersteunen OBJ, STL (binair en ASCII), glTF 2.0 / GLB, COLLADA (DAE) en 3MF‑bestanden.
Stap 4: Doorloop scèneknopen
Een geladen scène is een boom van Node objecten met wortel scene.root_node. Itereer recursief om alle knooppunten te vinden:
from aspose.threed import Scene, Node
scene = Scene.from_file("model.obj")
def walk(node: Node, depth: int = 0) -> None:
indent = " " * depth
print(f"{indent}Node: {node.name!r}")
for child in node.child_nodes:
walk(child, depth + 1)
walk(scene.root_node)Elke Node kan nul of meer Entity objecten (meshes, camera’s, lichten) dragen. Controleer node.entities om te zien wat er is bevestigd.
Stap 5: Toegang tot Vertex‑ en Polygon‑gegevens
Cast een node’s entiteit naar Mesh en lees de controlepunten (vertexposities) en polygonen (vlakindexlijsten):
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
for node in scene.root_node.child_nodes:
for entity in node.entities:
if isinstance(entity, Mesh):
mesh: Mesh = entity
print(f"Mesh '{node.name}': "
f"{len(mesh.control_points)} vertices, "
f"{len(mesh.polygons)} polygons")
# First vertex position
if mesh.control_points:
v = mesh.control_points[0]
print(f" First vertex: ({v.x:.4f}, {v.y:.4f}, {v.z:.4f})")
# First polygon face (list of control-point indices)
if mesh.polygons:
print(f" First polygon: {mesh.polygons[0]}")mesh.control_points is een lijst van Vector4 objecten; x, y, z dragen de positie en w is de homogene coördinaat (normaal 1.0).
mesh.polygons is een lijst van lijsten van gehele getallen, waarbij elke interne lijst de geordende set van controlepunt‑indices voor één vlak is.
Stap 6: Toepassen van formaat‑specifieke laadopties
Voor fijnmazige controle over hoe een OBJ‑bestand wordt geïnterpreteerd, geef een ObjLoadOptions‑instantie door aan scene.open():
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert right-hand Y-up to Z-up
options.scale = 0.01 # Convert centimetres to metres
options.enable_materials = True # Load .mtl material file
options.normalize_normal = True # Normalize all normals to unit length
scene = Scene()
scene.open("model.obj", options)Voor STL‑bestanden is de equivalente klasse StlLoadOptions. Voor glTF gebruik je GltfLoadOptions. Zie de API‑referentie voor een volledige lijst.
Veelvoorkomende problemen en oplossingen
FileNotFoundError bij het aanroepen van Scene.from_file()
Het pad moet absoluut zijn of correct relatief ten opzichte van de werkmap tijdens runtime. Gebruik pathlib.Path om betrouwbare paden te bouwen:
from pathlib import Path
from aspose.threed import Scene
path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))mesh.polygons is leeg na het laden van een STL‑bestand
STL-bestanden slaan driehoeken op als ruwe facetten, niet als een geïndexeerde mesh. Na het laden worden polygonen gesynthetiseerd uit die facetten. Als polygons leeg lijkt, controleer len(mesh.control_points); als het aantal een veelvoud van 3 is, wordt de geometrie opgeslagen in niet-geïndexeerde vorm en vormt elk opeenvolgend drietal vertices één driehoek.
Coördinatensysteem mismatch (model lijkt gedraaid of gespiegeld)
Verschillende tools gebruiken verschillende conventies (Y‑up vs Z‑up, linkshandig vs rechtshandig). Stel ObjLoadOptions.flip_coordinate_system = True in of pas een rotatie toe op de Transform van de rootnode na het laden.
AttributeError: 'NoneType' object has no attribute 'polygons'
De entiteitslijst van een knoop kan niet‑mesh‑entiteiten bevatten (camera’s, lampen). Bescherm altijd met isinstance(entity, Mesh) voordat je cast.
Veelgestelde vragen (FAQ)
Welke 3D-formaten kan ik laden?
OBJ (Wavefront), STL (binair en ASCII), glTF 2.0 / GLB, COLLADA (DAE) en 3MF. FBX-bestandstokenisatie wordt gedeeltelijk ondersteund, maar volledige parsing is nog niet voltooid.
Laadt het laden van een OBJ‑bestand ook het .mtl‑materiaal?
Ja, wanneer ObjLoadOptions.enable_materials = True (de standaard). De bibliotheek zoekt het .mtl‑bestand in dezelfde map als het .obj‑bestand. Als de .mtl ontbreekt, wordt de geometrie nog steeds geladen en wordt er een waarschuwing uitgegeven.
Kan ik een bestand laden vanuit een byte‑stream in plaats van een pad?
Ja. scene.open() accepteert elk bestand‑achtig object met een .read()‑methode naast een bestandspad‑string. Geef een geopende binaire stream (bijv. io.BytesIO) direct door. Scene.from_file() accepteert alleen een bestandspad‑string.
Hoe krijg ik oppervlaknormaalvectoren?
Na het laden, controleer mesh.get_element(VertexElementType.NORMAL). Dit retourneert een VertexElementNormal waarvan de data‑lijst één normaalvector per referentie bevat, gemapt volgens mapping_mode en reference_mode.
from aspose.threed.entities import Mesh, VertexElementType
normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
print(normals.data[0]) # First normal vectorIs de bibliotheek thread-safe voor het gelijktijdig laden van meerdere bestanden?
Elk Scene-object is onafhankelijk. Het laden van afzonderlijke bestanden in afzonderlijke Scene-instanties vanuit afzonderlijke threads is veilig, zolang je geen enkel Scene over threads deelt zonder externe vergrendeling.