วิธีโหลดโมเดล 3D ใน Python

วิธีโหลดโมเดล 3D ใน Python

Aspose.3D FOSS สำหรับ Python มี API ที่ตรงไปตรงมาสำหรับการเปิดไฟล์ 3D โดยไม่มีการพึ่งพาเนทีฟ หลังจากโหลดไฟล์เข้าสู่ a Scene object, คุณสามารถเดินทางผ่านลำดับชั้นของโหนดและอ่านข้อมูลเรขาคณิตดิบสำหรับเมชแต่ละอันในฉากได้.

คู่มือแบบขั้นตอนต่อขั้นตอน

ขั้นตอนที่ 1: ติดตั้งแพ็กเกจ

ติดตั้ง Aspose.3D FOSS จาก PyPI ไม่จำเป็นต้องมีไลบรารีระบบเพิ่มเติม.

pip install aspose-3d-foss

เวอร์ชัน Python ที่รองรับ: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


ขั้นตอนที่ 2: นำเข้าคลาส Scene

The Scene class เป็นคอนเทนเนอร์ระดับบนสุดสำหรับข้อมูล 3D ทั้งหมด นำเข้ามันพร้อมกับคลาสตัวเลือกการโหลดที่คุณต้องการ.

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

คลาสสาธารณะทั้งหมดอยู่ภายใต้ aspose.threed หรือแพคเกจย่อยของมัน (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).


ขั้นตอนที่ 3: โหลดไฟล์

ใช้ static Scene.from_file() method เพื่อเปิดฟอร์แมตที่รองรับใด ๆ ไลบรารีจะตรวจจับฟอร์แมตโดยอัตโนมัติจากส่วนขยายของไฟล์.

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

หรืออีกทางเลือกหนึ่ง, สร้าง a Scene instance และเรียก open(); มีประโยชน์เมื่อคุณต้องการส่งตัวเลือกการโหลดหรือจัดการข้อผิดพลาดอย่างชัดเจน:

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

ทั้งสองวิธีรองรับไฟล์ OBJ, STL (แบบไบนารีและ ASCII), glTF 2.0 / GLB, COLLADA (DAE) และ 3MF.


ขั้นตอนที่ 4: เดินทางผ่านโหนดของ Scene

ฉากที่โหลดแล้วเป็นต้นไม้ของ Node objects ที่มีรากอยู่ที่ scene.root_node. ทำการวนซ้ำแบบเรียกซ้ำเพื่อค้นหาโหนดทั้งหมด:

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)

แต่ละ Node สามารถบรรจุศูนย์หรือมากกว่า Entity วัตถุ (meshes, cameras, lights). ตรวจสอบ node.entities เพื่อดูว่าอะไรถูกแนบอยู่.


ขั้นตอนที่ 5: เข้าถึงข้อมูลเวอร์เท็กซ์และโพลิกอน

แปลงเอนทิตีของโหนดเป็น Mesh และอ่านจุดควบคุม (vertex positions) และโพลิกอน (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 เป็นรายการของ Vector4 อ็อบเจ็กต์; x, y, z บรรจุตำแหน่งและ w เป็นพิกัดเชิงเนื้อเดียว (โดยปกติคือ 1.0).

mesh.polygons เป็นรายการของรายการของจำนวนเต็ม, โดยที่แต่ละรายการย่อยเป็นชุดที่เรียงลำดับของดัชนีจุดควบคุมสำหรับแต่ละหน้า.


ขั้นตอนที่ 6: ใช้ตัวเลือกการโหลดตามรูปแบบเฉพาะ

สำหรับการควบคุมอย่างละเอียดว่ามีการตีความไฟล์ OBJ อย่างไร, ส่งผ่าน ObjLoadOptions อินสแตนซ์ไปยัง 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)

สำหรับไฟล์ STL, คลาสที่เทียบเท่าคือ StlLoadOptions. สำหรับ glTF, ใช้ GltfLoadOptions. ดูที่ เอกสารอ้างอิง API สำหรับรายการเต็ม.


ปัญหาทั่วไปและวิธีแก้

FileNotFoundError เมื่อเรียก Scene.from_file()

เส้นทางต้องเป็นแบบสัมบูรณ์หรือสัมพันธ์ที่ถูกต้องกับไดเรกทอรีทำงานในขณะรันไทม์. ใช้ pathlib.Path เพื่อสร้างเส้นทางที่เชื่อถือได้:

from pathlib import Path
from aspose.threed import Scene

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

mesh.polygons ว่างเปล่าหลังจากโหลดไฟล์ STL

ไฟล์ STL เก็บสามเหลี่ยมเป็น facet ดิบ ไม่ใช่เมชที่มีดัชนี หลังจากโหลดแล้ว รูปหลายเหลี่ยมจะถูกสังเคราะห์จาก facet เหล่านั้น หาก polygons ปรากฏว่าเป็นค่าว่าง ให้ตรวจสอบ len(mesh.control_points); หากจำนวนเป็นหลายของ 3 เรขาคณิตจะถูกเก็บในรูปแบบที่ไม่มีดัชนีและแต่ละชุดสามจุดต่อเนื่องของเวอร์เทกซ์จะสร้างเป็นสามเหลี่ยมหนึ่งรูป.

ระบบพิกัดไม่ตรงกัน (โมเดลดูเหมือนถูกหมุนหรือสะท้อนภาพ)

เครื่องมือต่าง ๆ ใช้แนวปฏิบัติที่แตกต่างกัน (Y‑up vs Z‑up, left-hand vs right-hand). ตั้งค่า ObjLoadOptions.flip_coordinate_system = True หรือใช้การหมุนกับรากของโหนด Transform หลังจากโหลดแล้ว.

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

รายการเอนทิตีของโหนดอาจมีเอนทิตีที่ไม่ใช่เมช (กล้อง, ไฟ) ควรตรวจสอบเสมอด้วย isinstance(entity, Mesh) ก่อนทำการแคสท์.


คำถามที่พบบ่อย (FAQ)

ฉันสามารถโหลดฟอร์แมต 3D ใดได้บ้าง?

OBJ (Wavefront), STL (binary และ ASCII), glTF 2.0 / GLB, COLLADA (DAE) และ 3MF. การทำ tokenization ของไฟล์ FBX ได้รับการสนับสนุนบางส่วน แต่การพาร์สเต็มรูปแบบยังไม่สมบูรณ์.

การโหลดไฟล์ OBJ จะโหลด .mtl วัสดุหรือไม่?

ใช่, เมื่อ ObjLoadOptions.enable_materials = True (ค่าเริ่มต้น) ไลบรารีจะค้นหา .mtl ไฟล์ในไดเรกทอรีเดียวกับไฟล์ .obj ไฟล์ หาก .mtl หายไป, เรขาคณิตยังคงถูกโหลดและมีการแจ้งเตือน.

ฉันสามารถโหลดไฟล์จากสตรีมไบต์แทนการใช้พาธได้หรือไม่?

ใช่. scene.open() รับอ็อบเจ็กต์ที่คล้ายไฟล์ใด ๆ ที่มี .read() เมธอด นอกเหนือจากสตริงเส้นทางไฟล์. ส่งสตรีมไบนารีที่เปิดอยู่ (เช่น,., io.BytesIO) โดยตรง. Scene.from_file() รับเฉพาะสตริงเส้นทางไฟล์เท่านั้น.

ฉันจะดึง normal ของพื้นผิวได้อย่างไร?

หลังจากโหลดแล้ว ให้ตรวจสอบ mesh.get_element(VertexElementType.NORMAL). นี้จะคืนค่า VertexElementNormal ซึ่ง data รายการมีเวกเตอร์ปกติหนึ่งตัวต่อการอ้างอิง, ถูกแมปตาม mapping_mode และ reference_mode.

from aspose.threed.entities import Mesh, VertexElementType

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

ไลบรารีนี้ปลอดภัยต่อเธรดสำหรับการโหลดหลายไฟล์พร้อมกันหรือไม่?

แต่ละ Scene อ็อบเจ็กต์เป็นอิสระ การโหลดไฟล์แยกต่างหากเข้าสู่แยก Scene อินสแตนซ์จากเธรดแยกต่างหากนั้นปลอดภัย ตราบใดที่คุณไม่ได้แชร์ออบเจ็กต์เดียว Scene ข้ามเธรดโดยไม่มีการล็อกภายนอก.

 ภาษาไทย