Cara Memuatkan Model 3D dalam Python

Cara Memuatkan Model 3D dalam Python

Aspose.3D FOSS for Python menyediakan API yang mudah untuk membuka fail 3D tanpa sebarang kebergantungan natif. Selepas memuatkan fail ke dalam objek Scene, anda boleh menelusuri hierarki nod dan membaca data geometri mentah bagi setiap mesh dalam adegan.

Panduan Langkah demi Langkah

Langkah 1: Pasang Pakej

Pasang Aspose.3D FOSS dari PyPI. Tiada perpustakaan sistem tambahan diperlukan.

pip install aspose-3d-foss

Versi Python yang disokong: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Langkah 2: Import Kelas Scene

Kelas Scene adalah kontena peringkat atas untuk semua data 3D. Import ia bersama mana-mana kelas pilihan-muat yang anda perlukan.

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

Semua kelas awam berada di bawah aspose.threed atau sub-pakejnya (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


Langkah 3: Muat Fail

Gunakan kaedah statik Scene.from_file() untuk membuka mana-mana format yang disokong. Pustaka mengesan format secara automatik daripada sambungan fail.

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

Sebagai alternatif, cipta satu contoh Scene dan panggil open(); berguna apabila anda ingin menghantar pilihan muat atau mengendalikan ralat secara eksplisit:

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

Kedua-dua kaedah menyokong fail OBJ, STL (binari dan ASCII), glTF 2.0 / GLB, COLLADA (DAE), dan 3MF.


Langkah 4: Lalui Nod Adegan

Sebuah adegan yang dimuatkan adalah pokok objek Node yang berakar pada scene.root_node. Ulang secara rekursif untuk mencari semua nod:

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)

Setiap Node boleh membawa sifar atau lebih objek Entity (meshes, kamera, lampu). Periksa node.entities untuk melihat apa yang dilampirkan.


Langkah 5: Akses Data Vertex dan Polygon

Lakukan penukaran entiti nod kepada Mesh dan baca titik kawalnya (kedudukan vertex) serta poligon (senarai indeks muka):

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 ialah senarai objek Vector4; x, y, z membawa kedudukan dan w ialah koordinat homogen (biasanya 1.0).

mesh.polygons ialah senarai senarai integer, di mana setiap senarai dalaman merupakan set teratur indeks titik kawalan untuk satu muka.


Langkah 6: Gunakan Pilihan Muat Mengikut Format

Untuk kawalan terperinci ke atas cara fail OBJ ditafsirkan, hantarkan contoh ObjLoadOptions kepada 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)

Bagi fail STL, kelas yang setara ialah StlLoadOptions. Bagi glTF, gunakan GltfLoadOptions. Lihat rujukan API untuk senarai penuh.


Isu Umum dan Penyelesaian

FileNotFoundError semasa memanggil Scene.from_file()

Laluan mesti mutlak atau relatif yang betul kepada direktori kerja semasa runtime. Gunakan pathlib.Path untuk membina laluan yang boleh dipercayai:

from pathlib import Path
from aspose.threed import Scene

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

mesh.polygons kosong selepas memuatkan fail STL

Fail STL menyimpan segitiga sebagai faset mentah, bukan mesh berindeks. Selepas dimuatkan, poligon disintesis daripada faset‑faset tersebut. Jika polygons kelihatan kosong, periksa len(mesh.control_points); jika kiraannya merupakan gandaan 3, geometri disimpan dalam bentuk tidak berindeks dan setiap tiga titik berturutan membentuk satu segitiga.

Ketidakcocokan sistem koordinat (model kelihatan diputar atau dipantulkan)

Alat yang berbeza menggunakan konvensyen yang berbeza (Y-up vs Z-up, tangan kiri vs tangan kanan). Tetapkan ObjLoadOptions.flip_coordinate_system = True atau terapkan putaran pada Transform nod akar selepas memuatkan.

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

Senarai entiti nod mungkin mengandungi entiti bukan‑mesh (kamera, lampu). Sentiasa lindungi dengan isinstance(entity, Mesh) sebelum menukar.


Soalan Lazim (FAQ)

Format 3D mana yang boleh dimuat?

OBJ (Wavefront), STL (binari dan ASCII), glTF 2.0 / GLB, COLLADA (DAE), dan 3MF. Tokenisasi fail FBX disokong secara separa tetapi penguraian penuh belum selesai.

Adakah memuatkan fail OBJ juga memuatkan bahan .mtl?

Ya, apabila ObjLoadOptions.enable_materials = True (lalai). Perpustakaan mencari fail .mtl dalam direktori yang sama dengan fail .obj. Jika .mtl tidak ada, geometri masih dimuatkan dan amaran dikeluarkan.

Bolehkah saya memuatkan fail daripada aliran bait dan bukannya laluan?

Ya. scene.open() menerima sebarang objek seperti fail dengan kaedah .read() selain daripada rentetan laluan fail. Hantar aliran binari terbuka (contohnya, io.BytesIO) secara langsung. Scene.from_file() hanya menerima rentetan laluan fail.

Bagaimana saya dapat normal permukaan?

Selepas dimuatkan, periksa mesh.get_element(VertexElementType.NORMAL). Ini mengembalikan VertexElementNormal yang senarai datanya mengandungi satu vektor normal bagi setiap rujukan, dipetakan mengikut mapping_mode dan reference_mode.

from aspose.threed.entities import Mesh, VertexElementType

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

Adakah perpustakaan thread-safe untuk memuatkan berbilang fail secara serentak?

Setiap Scene objek adalah bebas. Memuatkan fail berasingan ke dalam contoh Scene yang berasingan dari benang berasingan adalah selamat selagi anda tidak berkongsi satu Scene merentasi benang tanpa kunci luaran.

 Bahasa Melayu