Jak načíst 3D modely v Pythonu

Jak načíst 3D modely v Pythonu

Aspose.3D FOSS for Python poskytuje jednoduché API pro otevírání 3D souborů bez jakýchkoli nativních závislostí. Po načtení souboru do objektu Scene můžete procházet hierarchii uzlů a číst surová geometrická data pro každý mesh ve scéně.

Průvodce krok za krokem

Krok 1: Nainstalujte balíček

Nainstalujte Aspose.3D FOSS z PyPI. Žádné další systémové knihovny nejsou vyžadovány.

pip install aspose-3d-foss

Podporované verze Pythonu: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Krok 2: Import třídy Scene

Třída Scene je kontejner nejvyšší úrovně pro všechna 3D data. Importujte ji spolu se všemi třídami možností načítání, které potřebujete.

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

Všechny veřejné třídy jsou umístěny pod aspose.threed nebo v jeho podbalíčcích (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


Krok 3: Načíst soubor

Použijte statickou metodu Scene.from_file() k otevření libovolného podporovaného formátu. Knihovna automaticky detekuje formát z přípony souboru.

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

Alternativně vytvořte instanci Scene a zavolejte open(); užitečné, když chcete předat možnosti načítání nebo explicitně zpracovat chyby:

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

Obě metody podporují soubory OBJ, STL (binární a ASCII), glTF 2.0 / GLB, COLLADA (DAE) a 3MF.


Krok 4: Procházet uzly scény

Načtená scéna je strom objektů Node zakořeněný v scene.root_node. Procházejte rekurzivně, abyste našli všechny uzly:

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)

Každý Node může nést nula nebo více Entity objektů (meshes, cameras, lights). Zkontrolujte node.entities, abyste zjistili, co je připojeno.


Krok 5: Přístup k datům vrcholů a polygonů

Přetypujte entitu uzlu na Mesh a přečtěte její řídicí body (pozice vrcholů) a polygonů (seznamy indexů ploch):

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 je seznam Vector4 objektů; x, y, z nesou pozici a w je homogenní souřadnice (normálně 1.0).

mesh.polygons je seznam seznamů celých čísel, kde každý vnitřní seznam je uspořádaná množina indexů řídicích bodů pro jednu plochu.


Krok 6: Použít specifické možnosti načítání formátu

Pro jemnozrnnější kontrolu toho, jak je soubor OBJ interpretován, předávejte instanci ObjLoadOptions do 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)

Pro soubory STL je ekvivalentní třída StlLoadOptions. Pro glTF použijte GltfLoadOptions. Viz API reference pro úplný seznam.


Časté problémy a opravy

FileNotFoundError při volání Scene.from_file()

Cesta musí být absolutní nebo správně relativní k pracovnímu adresáři za běhu. Použijte pathlib.Path k vytvoření spolehlivých cest:

from pathlib import Path
from aspose.threed import Scene

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

mesh.polygons je prázdný po načtení souboru STL

STL soubory ukládají trojúhelníky jako surové fasety, nikoli jako indexovanou síť. Po načtení jsou z těchto faset syntetizovány polygonové tvary. Pokud se polygons jeví jako prázdný, zkontrolujte len(mesh.control_points); pokud je počet násobkem 3, geometrie je uložena v neindexované formě a každá po sobě jdoucí trojice vrcholů tvoří jeden trojúhelník.

Neshoda souřadnicových systémů (model se jeví jako otočený nebo zrcadlený)

Různé nástroje používají různé konvence (Y‑nahoru vs Z‑nahoru, levá ruka vs pravá ruka). Nastavte ObjLoadOptions.flip_coordinate_system = True nebo po načtení aplikujte rotaci na Transform kořenového uzlu.

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

Seznam entit uzlu může obsahovat ne‑mesh entity (kamery, světla). Vždy použijte isinstance(entity, Mesh) jako ochranu před přetypováním.


Často kladené otázky (FAQ)

Jaké 3D formáty mohu načíst?

OBJ (Wavefront), STL (binární a ASCII), glTF 2.0 / GLB, COLLADA (DAE) a 3MF. Tokenizace souborů FBX je částečně podporována, ale úplné parsování ještě není dokončeno.

Načítá načtení souboru OBJ také materiál .mtl?

Ano, když ObjLoadOptions.enable_materials = True (výchozí). Knihovna hledá soubor .mtl ve stejném adresáři jako soubor .obj. Pokud chybí .mtl, geometrie se stále načte a je vypsáno varování.

Mohu načíst soubor z proudu bajtů místo cesty?

Ano. scene.open() přijímá jakýkoli objekt podobný souboru s metodou .read() kromě řetězce cesty k souboru. Předávejte otevřený binární stream (např. io.BytesIO) přímo. Scene.from_file() přijímá pouze řetězec cesty k souboru.

Jak získám povrchové normály?

Po načtení zkontrolujte mesh.get_element(VertexElementType.NORMAL). Toto vrátí VertexElementNormal, jehož seznam data obsahuje jeden normálový vektor na referenci, mapovaný podle mapping_mode a reference_mode.

from aspose.threed.entities import Mesh, VertexElementType

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

Je knihovna vláknově bezpečná při načítání více souborů současně?

Každý objekt Scene je nezávislý. Načítání samostatných souborů do samostatných instancí Scene z různých vláken je bezpečné, pokud nesdílíte jediný Scene mezi vlákny bez externího zamykání.

 Čeština