Sådan indlæses 3D-modeller i Python

Sådan indlæses 3D-modeller i Python

Aspose.3D FOSS for Python leverer et enkelt API til at åbne 3D-filer uden nogen native afhængigheder. Efter at have indlæst en fil i et Scene-objekt, kan du traversere nodehierarkiet og læse rå geometridata for hver mesh i scenen.

Trin-for-trin guide

Trin 1: Installer pakken

Installer Aspose.3D FOSS fra PyPI. Ingen yderligere systembiblioteker er påkrævet.

pip install aspose-3d-foss

Understøttede Python-versioner: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Trin 2: Importer Scene‑klassen

Klassen Scene er den øverste container for alle 3D‑data. Importer den sammen med eventuelle indlæsningsindstillingsklasser, du har brug for.

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

Alle offentlige klasser findes under aspose.threed eller dets underpakker (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


Trin 3: Indlæs en fil

Brug den statiske Scene.from_file()‑metode til at åbne ethvert understøttet format. Biblioteket registrerer formatet automatisk ud fra filendelsen.

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

Alternativt kan du oprette en Scene‑instans og kalde open(); nyttigt, når du vil videregive indlæsningsindstillinger eller håndtere fejl eksplicit:

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

Begge metoder understøtter OBJ, STL (binær og ASCII), glTF 2.0 / GLB, COLLADA (DAE) og 3MF-filer.


Trin 4: Gennemløb scenenoder

En indlæst scene er et træ af Node‑objekter med rod i scene.root_node. Iterer rekursivt for at finde alle 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)

Hver Node kan bære nul eller flere Entity-objekter (meshes, cameras, lights). Tjek node.entities for at se, hvad der er vedhæftet.


Trin 5: Få adgang til Vertex- og polygondata

Kast en nodes enhed til Mesh og læs dens kontrolpunkter (vertex positions) og 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 er en liste over Vector4-objekter; x, y, z bærer positionen og w er den homogene koordinat (normalt 1.0).

mesh.polygons er en liste af lister af heltal, hvor hver indre liste er den ordnede mængde af kontrolpunktindekser for én flade.


Trin 6: Anvend format‑specifikke indlæsningsindstillinger

For finjusteret kontrol over, hvordan en OBJ‑fil fortolkes, skal du videregive en ObjLoadOptions‑instans til 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)

For STL-filer er den tilsvarende klasse StlLoadOptions. For glTF skal du bruge GltfLoadOptions. Se API-referencen for en komplet liste.


Almindelige problemer og rettelser

FileNotFoundError ved kald af Scene.from_file()

Stien skal være absolut eller korrekt relativ til arbejdsmappe ved kørsel. Brug pathlib.Path til at opbygge pålidelige stier:

from pathlib import Path
from aspose.threed import Scene

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

mesh.polygons er tom efter indlæsning af en STL-fil

STL-filer gemmer trekanter som rå facetter, ikke som et indekseret net. Efter indlæsning syntetiseres polygoner fra disse facetter. Hvis polygons fremstår tom, så tjek len(mesh.control_points); hvis antallet er et multiplum af 3, er geometrien gemt i uindekseret form, og hver på hinanden følgende tredobling af vertexer udgør en trekant.

Koordinatsystem uoverensstemmelse (model ser roteret eller spejlet ud)

Forskellige værktøjer bruger forskellige konventioner (Y‑op vs Z‑op, venstre‑hånd vs højre‑hånd). Indstil ObjLoadOptions.flip_coordinate_system = True eller anvend en rotation på rotnodens Transform efter indlæsning.

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

En nodes entitetsliste kan indeholde ikke‑mesh‑entiteter (kameraer, lys). Beskyt altid med isinstance(entity, Mesh) før casting.


Ofte stillede spørgsmål (FAQ)

Hvilke 3D‑formater kan jeg indlæse?

OBJ (Wavefront), STL (binary and ASCII), glTF 2.0 / GLB, COLLADA (DAE) og 3MF. FBX-fil-tokenisering understøttes delvist, men fuld parsing er endnu ikke fuldført.

Indlæser en OBJ-fil også materialet .mtl?

Ja, når ObjLoadOptions.enable_materials = True (standard). Biblioteket søger efter .mtl-filen i samme mappe som .obj-filen. Hvis .mtl mangler, indlæses geometrien stadig, og der udstedes en advarsel.

Kan jeg indlæse en fil fra en byte‑strøm i stedet for en sti?

Ja. scene.open() accepterer ethvert fil‑lignende objekt med en .read()‑metode ud over en filsti som streng. Overfør en åben binær strøm (f.eks., io.BytesIO) direkte. Scene.from_file() accepterer kun en filsti som streng.

Hvordan får jeg overfladenormaler?

Efter indlæsning, tjek mesh.get_element(VertexElementType.NORMAL). Dette returnerer en VertexElementNormal, hvis data-liste indeholder én normalvektor pr. reference, kortlagt i henhold til mapping_mode og reference_mode.

from aspose.threed.entities import Mesh, VertexElementType

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

Er biblioteket trådsikkert ved indlæsning af flere filer samtidigt?

Hvert Scene-objekt er uafhængigt. Indlæsning af separate filer i separate Scene-instanser fra separate tråde er sikkert, så længe du ikke deler et enkelt Scene på tværs af tråde uden ekstern låsning.

 Dansk