Hur man laddar 3D-modeller i Python

Hur man laddar 3D-modeller i Python

Aspose.3D FOSS för Python erbjuder ett enkelt API för att öppna 3D-filer utan några inhemska beroenden. Efter att ha laddat en fil i en Scene objekt kan du gå igenom nodhierarkin och läsa rå geometridata för varje mesh i scenen.

Steg-för-steg-guide

Steg 1: Installera paketet

Installera Aspose.3D FOSS från PyPI. Inga ytterligare systembibliotek krävs.

pip install aspose-3d-foss

Stödda Python-versioner: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Steg 2: Importera Scene-klassen

Den Scene klass är den översta behållaren för all 3D-data. Importera den tillsammans med eventuella laddningsalternativsklasser du behöver.

from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions

Alla offentliga klasser finns under aspose.threed eller dess underpaket (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


Steg 3: Ladda en fil

Använd den statiska Scene.from_file() metoden för att öppna vilket stödformat som helst. Biblioteket upptäcker formatet automatiskt från filändelsen.

##Automatic format detection
scene = Scene.from_file("model.obj")

Alternativt, skapa en Scene instans och anropa open(); användbart när du vill skicka laddningsalternativ eller hantera fel explicit:

scene = Scene()
scene.open("model.obj")

Båda metoderna stödjer OBJ, STL (binär och ASCII), glTF 2.0 / GLB, COLLADA (DAE) och 3MF-filer.


Steg 4: Traversera scen-noder

En laddad scen är ett träd av Node objekt rotade vid scene.root_node. Iterera rekursivt för att hitta alla noder:

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)

Varje Node kan bära noll eller fler Entity objekt (meshes, kameror, ljus). Kontrollera node.entities för att se vad som är anslutet.


Steg 5: Åtkomst till vertex- och polygondata

Casta en nods entitet till Mesh och läs dess kontrollpunkter (vertex positions) och polygoner (face index lists):

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 är en lista med Vector4 objekt; x, y, z bär positionen och w är den homogena koordinaten (vanligtvis 1.0).

mesh.polygons är en lista med listor av heltal, där varje inre lista är den ordnade uppsättningen av kontrollpunktsindex för ett ansikte.


Steg 6: Tillämpa format‑specifika laddningsalternativ

För finjusterad kontroll över hur en OBJ-fil tolkas, skicka en ObjLoadOptions instans till 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)

För STL-filer är den motsvarande klassen StlLoadOptions. För glTF, använd GltfLoadOptions. Se API-referens för en fullständig lista.


Vanliga problem och lösningar

FileNotFoundError vid anrop av Scene.from_file()

Sökvägen måste vara absolut eller korrekt relativ till arbetskatalogen vid körning. Använd pathlib.Path för att bygga pålitliga sökvägar:

from pathlib import Path
from aspose.threed import Scene

path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))

mesh.polygons är tom efter att ha läst in en STL-fil

STL-filer lagrar trianglar som råa facetter, inte ett indexerat nät. Efter inläsning syntetiseras polygoner från dessa facetter. Om polygons verkar tom, kontrollera len(mesh.control_points); om antalet är en multipel av 3 är geometrin lagrad i oindexerad form och varje på varandra följande trippel av vertexer bildar en triangel.

Mismatch i koordinatsystem (modellen verkar roterad eller spegelvänd)

Olika verktyg använder olika konventioner (Y-upp vs Z-upp, vänsterhand vs högerhand). Ställ in ObjLoadOptions.flip_coordinate_system = True eller applicera en rotation på rotnodens Transform efter inläsning.

AttributeError: 'NoneType' object has no attribute 'polygons'

En nods entitetslista kan innehålla icke-mesh‑entiteter (kameror, ljus). Säkerställ alltid med isinstance(entity, Mesh) innan du castar.


Vanliga frågor (FAQ)

Vilka 3D-format kan jag läsa in?

OBJ (Wavefront), STL (binär och ASCII), glTF 2.0 / GLB, COLLADA (DAE) och 3MF. FBX‑filens tokenisering stöds delvis men fullständig parsning är ännu inte klar.

Laddar inläsning av en OBJ‑fil även .mtl materialet?

Ja, när ObjLoadOptions.enable_materials = True (standard). Biblioteket söker efter .mtl fil i samma katalog som .obj fil. Om .mtl saknas, laddas geometrin fortfarande och en varning ges ut.

Kan jag läsa in en fil från en byte‑ström istället för en sökväg?

Ja. scene.open() accepterar vilket fil‑liknande objekt som helst med en .read() metod utöver en filsökvägssträng. Skicka en öppen binärström (t.ex., io.BytesIO) direkt. Scene.from_file() accepterar endast en filsökvägssträng.

Hur får jag ytnormaler?

Efter inläsning, kontrollera mesh.get_element(VertexElementType.NORMAL). Detta returnerar en VertexElementNormal vars data lista innehåller en normalvektor per referens, mappad enligt mapping_mode och reference_mode.

from aspose.threed.entities import Mesh, VertexElementType

normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
    print(normals.data[0])  # First normal vector

Är biblioteket trådsäkert för att ladda flera filer samtidigt?

Varje Scene objektet är oberoende. Att ladda separata filer i separata Scene instanser från separata trådar är säkert så länge du inte delar en enda Scene över trådar utan extern låsning.

 Svenska