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 indlæsning af en fil i en 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

Den Scene klasse er den øverste container for al 3D-data. Importer den sammen med eventuelle load-option klasser, du har brug for.

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

Alle offentlige klasser findes under aspose.threed eller dens 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 opdager 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 load options 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: Gå igennem scenenoder

En indlæst scene er et træ af Node objekter med roden 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, kameraer, lys). Tjek node.entities for at se, hvad der er vedhæftet.


Trin 5: Få adgang til vertex- og polygondata

Cast nodeens 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 det ordnede sæt af kontrolpunkt‑indekser for én flade.


Trin 6: Anvend format‑specifikke load‑options

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, brug GltfLoadOptions. Se API‑reference for en komplet liste.


Almindelige problemer og løsninger

FileNotFoundError ved kald af Scene.from_file()

Stien skal være absolut eller korrekt relativ i forhold til arbejdsbiblioteket 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 ser ud til at være tom, 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-mismatch (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 anvende 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 du caster.


Ofte stillede spørgsmål (FAQ)

Hvilke 3D-formater kan jeg indlæse?

OBJ (Wavefront), STL (binær og ASCII), glTF 2.0 / GLB, COLLADA (DAE) og 3MF. FBX‑fil‑tokenisering understøttes delvist, men fuld parsing er endnu ikke færdig.

Indlæser indlæsning af en OBJ-fil også .mtl materiale?

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

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 filstistring. Overgiv en åben binær strøm (f.eks., io.BytesIO) direkte. Scene.from_file() accepterer kun en filstistring.

Hvordan får jeg overfladenormaller?

Efter indlæsning, tjek mesh.get_element(VertexElementType.NORMAL). Dette returnerer en VertexElementNormal hvis data listen 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?

Hver Scene objekt er uafhængig. Indlæsning af separate filer i separate Scene instanser fra separate tråde er sikkert så længe du ikke deler en enkelt Scene på tværs af tråde uden ekstern låsning.

 Dansk