Hvordan laste inn 3D-modeller i Python

Hvordan laste inn 3D-modeller i Python

Aspose.3D FOSS for Python gir et enkelt API for å åpne 3D-filer uten noen native avhengigheter. Etter å ha lastet en fil inn i en Scene objekt, kan du gå gjennom nodehierarkiet og lese rå geometridata for hver mesh i scenen.

Steg-for-steg guide

Steg 1: Installer pakken

Installer Aspose.3D FOSS fra PyPI. Ingen ekstra systembiblioteker er påkrevd.

pip install aspose-3d-foss

Støttede Python-versjoner: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Steg 2: Importer Scene-klassen

Den Scene klassen er den øverste beholderen for all 3D-data. Importer den sammen med eventuelle lastingsalternativklasser du trenger.

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

Alle offentlige klasser finnes under aspose.threed eller dens underpakker (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


Steg 3: Last inn en fil

Bruk den statiske Scene.from_file() metoden for å åpne ethvert støttet format. Biblioteket oppdager formatet automatisk fra filendelsen.

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

Alternativt, opprett en Scene instans og kall open(); nyttig når du vil sende inn lastingsalternativer eller håndtere feil eksplisitt:

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

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


Steg 4: Gå gjennom Scene-noder

En lastet scene er et tre av Node objekter med roten i scene.root_node. Gå rekursivt gjennom for å finne 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 inneholde null eller flere Entity objekter (mesher, kameraer, lys). Sjekk node.entities for å se hva som er festet.


Steg 5: Tilgang til vertex- og polygondata

Kast en nodes enhet til Mesh og les dens kontrollpunkter (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 posisjonen og w er den homogene koordinaten (vanligvis 1.0).

mesh.polygons er en liste av lister med heltall, hvor hver indre liste er den ordnede mengden av kontrollpunktindekser for én flate.


Steg 6: Bruk formatspesifikke lastingsalternativer

For finjustert kontroll over hvordan en OBJ-fil tolkes, send inn 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 klassen StlLoadOptions. For glTF, bruk GltfLoadOptions. Se API-referansen for en fullstendig liste.


Vanlige problemer og løsninger

FileNotFoundError ved kall til Scene.from_file()

Stien må være absolutt eller korrekt relativ til arbeidskatalogen ved kjøring. Bruk pathlib.Path for å bygge pålitelige 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 etter lasting av en STL-fil

STL-filer lagrer trekanter som rå flater, ikke som et indeksert nett. Etter innlasting blir polygoner syntetisert fra disse flatene. Hvis polygons ser tom ut, sjekk len(mesh.control_points); hvis antallet er et multiplum av 3, er geometrien lagret i uindeksert form, og hver påfølgende trippel av vertices danner en trekant.

Uoverensstemmelse i koordinatsystem (modellen ser rotert eller speilet ut)

Ulike verktøy bruker ulike konvensjoner (Y-opp vs Z-opp, venstrehånds vs høyrehånds). Angi ObjLoadOptions.flip_coordinate_system = True eller bruk en rotasjon på rotknutens Transform etter lasting.

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

En nodes entitetsliste kan inneholde ikke-mesh-entiteter (kameraer, lys). Beskytt alltid med isinstance(entity, Mesh) før casting.


Ofte stilte spørsmål (FAQ)

Hvilke 3D-formater kan jeg laste?

OBJ (Wavefront), STL (binær og ASCII), glTF 2.0 / GLB, COLLADA (DAE) og 3MF. FBX‑fil‑tokenisering støttes delvis, men full parsing er ennå ikke komplett.

Laster inn en OBJ-fil også inn .mtl materialet?

Ja, når ObjLoadOptions.enable_materials = True (standard). Biblioteket ser etter .mtl filen i samme katalog som .obj filen. Hvis .mtl mangler, blir geometrien fortsatt lastet inn og en advarsel blir gitt.

Kan jeg laste en fil fra en byte‑strøm i stedet for en sti?

Ja. scene.open() godtar ethvert fil‑lignende objekt med en .read() metode i tillegg til en filstistring. Send en åpen binærstrøm (f.eks., io.BytesIO) direkte. Scene.from_file() godtar kun en filstistring.

Hvordan får jeg overflatenormaler?

Etter lasting, sjekk mesh.get_element(VertexElementType.NORMAL). Dette returnerer en VertexElementNormal hvis data listen inneholder én normalvektor per referanse, kartlagt 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 for å laste flere filer samtidig?

Hver Scene objektet er uavhengig. Laster separate filer inn i separate Scene instanser fra separate tråder er trygt så lenge du ikke deler en enkelt Scene på tvers av tråder uten ekstern låsing.

 Norsk