วิธีโหลดโมเดล 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 ข้ามเธรดโดยไม่มีการล็อกภายนอก.