วิธีแปลงโมเดล 3 มิติใน Python
การแปลงรูปแบบด้วย Aspose.3D FOSS for Python เป็นกระบวนการสองขั้นตอน: โหลดเข้าสู่วัตถุ Scene แล้วบันทึกเป็นรูปแบบผลลัพธ์ที่ต้องการ เนื่องจากเรขาคณิตทั้งหมดถูกเก็บไว้ในตัวแทนในหน่วยความจำร่วมกัน ไม่จำเป็นต้องมีขั้นตอนกลางที่เฉพาะเจาะจงต่อรูปแบบ ส่วนต่อไปนี้แสดงการแปลงที่พบบ่อยที่สุดพร้อมโค้ดที่ทำงานได้
คู่มือแบบขั้นตอนต่อขั้นตอน
ขั้นตอนที่ 1: ติดตั้งแพคเกจ
pip install aspose-3d-fossไม่จำเป็นต้องใช้ไลบรารีระบบ, คอมไพเลอร์ หรือการพึ่งพา runtime เพิ่มเติมใดๆ
ขั้นตอนที่ 2: โหลดโมเดลต้นฉบับ
ใช้ Scene.from_file() สำหรับกรณีที่ง่ายที่สุด: รูปแบบจะถูกตรวจจับโดยอัตโนมัติจากส่วนขยายของไฟล์:
from aspose.threed import Scene
scene = Scene.from_file("model.obj")สำหรับไฟล์ OBJ ที่คุณต้องการควบคุมระบบพิกัดหรือการโหลดวัสดุ ให้ใช้ scene.open() พร้อมกับ ObjLoadOptions:
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert to Z-up if needed
options.enable_materials = True # Load the accompanying .mtl file
options.normalize_normal = True
scene = Scene()
scene.open("model.obj", options)ทั้งสองวิธีสร้างอ็อบเจ็กต์ Scene ที่เหมือนกันสำหรับขั้นตอนการบันทึกต่อไป
ขั้นตอนที่ 3: ตรวจสอบฉากที่โหลดแล้ว
ก่อนทำการแปลง ควรตรวจสอบว่าเรขาคณิตโหลดอย่างถูกต้องหรือไม่ ไฟล์หาย ฟีเจอร์ FBX ที่ไม่รองรับ หรือปัญหาเส้นทางกับไฟล์ .mtl ทั้งหมดนี้อาจทำให้ฉากว่างเปล่า.
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
mesh_count = 0
total_vertices = 0
def count_meshes(node) -> None:
global mesh_count, total_vertices
for entity in node.entities:
if isinstance(entity, Mesh):
mesh_count += 1
total_vertices += len(entity.control_points)
for child in node.child_nodes:
count_meshes(child)
count_meshes(scene.root_node)
print(f"Loaded {mesh_count} mesh(es), {total_vertices} total vertices")
if mesh_count == 0:
raise ValueError("Scene contains no geometry: check the source file path and format")ขั้นตอนที่ 4: บันทึกเป็นรูปแบบเป้าหมาย
เรียก scene.save() พร้อมเส้นทางเอาต์พุต. ส่งอ็อบเจ็กต์ตัวเลือกการบันทึกที่เฉพาะรูปแบบเพื่อควบคุมการออกเป็นไบนารีหรือ ASCII, แกนพิกัด, และการบีบอัด.
OBJ เป็น STL (ไบนารี)
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
scene = Scene.from_file("model.obj")
save_opts = StlSaveOptions()
##StlSaveOptions defaults to binary output, which is more compact.
scene.save("model.stl", save_opts)
print("Saved model.stl")OBJ เป็น glTF 2.0
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = GltfSaveOptions()
scene.save("model.gltf", save_opts)
print("Saved model.gltf")เพื่อบันทึกเป็นไฟล์ไบนารี GLB ที่รวมทุกอย่างไว้ในตัวเองแทน .gltf + บัฟเฟอร์ภายนอก ให้เปลี่ยนส่วนขยายของผลลัพธ์เป็น .glb:
scene.save("model.glb", save_opts)OBJ เป็น 3MF
from aspose.threed import Scene
from aspose.threed.formats import ThreeMfSaveOptions
scene = Scene.from_file("model.obj")
save_opts = ThreeMfSaveOptions()
scene.save("model.3mf", save_opts)
print("Saved model.3mf")STL เป็น glTF 2.0
รูปแบบเดียวกันใช้ได้โดยไม่คำนึงถึงรูปแบบของแหล่งข้อมูล:
from aspose.threed import Scene
from aspose.threed.formats import GltfSaveOptions
scene = Scene.from_file("input.stl")
scene.save("output.gltf", GltfSaveOptions())
print("Saved output.gltf")ขั้นตอนที่ 5: ตรวจสอบผลลัพธ์
หลังจากบันทึกแล้ว ให้ยืนยันว่าไฟล์ผลลัพธ์มีอยู่และมีขนาดไม่เป็นศูนย์ สำหรับการตรวจสอบที่ละเอียดขึ้น ให้โหลดไฟล์ใหม่และเปรียบเทียบจำนวนเมช:
import os
from aspose.threed import Scene
from aspose.threed.entities import Mesh
output_path = "model.stl"
##Basic file-system check
size = os.path.getsize(output_path)
print(f"Output file size: {size} bytes")
if size == 0:
raise RuntimeError("Output file is empty: save may have failed silently")
##Round-trip verification: reload and count geometry
def _iter_nodes(node):
yield node
for child in node.child_nodes:
yield from _iter_nodes(child)
reloaded = Scene.from_file(output_path)
mesh_count = sum(
1
for node in _iter_nodes(reloaded.root_node)
for entity in node.entities
if isinstance(entity, Mesh)
)
print(f"Round-trip check: {mesh_count} mesh(es) in output")ปัญหาทั่วไปและการแก้ไข
ไฟล์ผลลัพธ์ถูกสร้างแล้วแต่ไม่มีเรขาคณิต
ไฟล์ต้นทางอาจโหลดมาโดยไม่มีเมชเลย เพิ่มขั้นตอนการตรวจสอบจากขั้นตอนที่ 3 ก่อนบันทึก นอกจากนี้ให้ตรวจสอบให้แน่ใจว่านามสกุลไฟล์ตรงกับรูปแบบจริง; Aspose.3D ใช้นามสกุลเพื่อเลือกตัวแยกวิเคราะห์.
ผลลัพธ์ glTF ขาดเทกเจอร์
Aspose.3D FOSS ส่งต่อเรขาคณิตและคุณสมบัติวัตถุผ่านการแปลง หากไฟล์ OBJ ต้นทางอ้างอิงไฟล์รูปภาพภายนอกใน .mtl ไฟล์รูปภาพเหล่านั้นจะไม่ถูกคัดลอกโดยอัตโนมัติพร้อมกับ .gltf คัดลอกรูปภาพเทกเจอร์ไปยังไดเรกทอรีผลลัพธ์ด้วยตนเองหลังจากบันทึก.
ผลลัพธ์ STL แสดงด้านใน‑นอก (ปกติของหน้าเปลี่ยนทิศ)
STL ไม่ได้บรรจุข้อมูลเมตาดาต้าลำดับการม้วน หากเวกเตอร์ปกติที่ส่งออกถูกกลับด้าน ให้ตั้งค่าตัวเลือก StlSaveOptions หากมี หรือพลิกระบบพิกัดระหว่างการโหลด: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format ขณะบันทึก
ตรวจสอบให้แน่ใจว่าการต่อท้ายไฟล์ผลลัพธ์เป็นหนึ่งใน .obj, .stl, .gltf, .glb, .dae, .3mf. ส่วนต่อท้ายไฟล์เป็นตัวพิมพ์ใหญ่‑เล็กที่แตกต่างกันบน Linux.
ไฟล์ขนาดใหญ่มากทำให้การแปลงช้า
Aspose.3D FOSS ประมวลผลเรขาคณิตในหน่วยความจำ. สำหรับไฟล์ที่มีหลายล้านโพลิกอน ให้ตรวจสอบว่ามี RAM เพียงพอ. ขณะนี้ไม่มี API สำหรับการเขียนแบบสตรีมมิ่ง.
คำถามที่พบบ่อย (FAQ)
ฉันสามารถแปลงไฟล์โดยไม่ต้องบันทึกลงดิสก์ก่อนหรือไม่?
ใช่ ทั้ง scene.open() และ scene.save() ยอมรับอ็อบเจ็กต์ที่คล้ายไฟล์แบบไบนารีเพิ่มเติมจากเส้นทางไฟล์ ส่งผ่านอ็อบเจ็กต์ใดก็ได้ที่ทำตาม read() สำหรับการโหลดหรือ write() สำหรับการบันทึก:
import io
from aspose.threed import Scene
# Load from an in-memory buffer
data = open('model.obj', 'rb').read()
scene = Scene()
scene.open(io.BytesIO(data))
# Save to an in-memory buffer
buf = io.BytesIO()
scene.save(buf)FBX รองรับเป็นรูปแบบแหล่งที่มาสำหรับการแปลงหรือไม่?
การทำโทเคนของ FBX ได้รับการดำเนินการบางส่วน แต่ตัวพาร์เซอร์ยังไม่สมบูรณ์ การป้อนข้อมูล FBX อาจทำให้ฉากไม่สมบูรณ์ ใช้ OBJ, STL, glTF, COLLADA หรือ 3MF เป็นรูปแบบแหล่งที่เชื่อถือได้
วัสดุจะคงอยู่หลังการแปลง OBJ เป็น glTF หรือไม่?
คุณสมบัติพื้นฐานของวัสดุ Phong/Lambert (สีกระจาย) จะถูกส่งต่อผ่านโมเดล Scene และเขียนลงในบล็อกวัสดุของ glTF พารามิเตอร์เชดเดอร์เชิงกระบวนการหรือแบบกำหนดเองที่ไม่สามารถแสดงในโมเดลวัสดุของ glTF จะถูกละทิ้ง.
ฉันสามารถแปลงหลายไฟล์ในลูปได้หรือไม่?
ใช่. แต่ละการเรียก Scene.from_file() จะสร้างอ็อบเจ็กต์อิสระ ดังนั้นการวนลูปผ่านรายการของเส้นทางจึงทำได้อย่างตรงไปตรงมา:
from pathlib import Path
from aspose.threed import Scene
from aspose.threed.formats import StlSaveOptions
source_dir = Path("input")
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
opts = StlSaveOptions()
for obj_file in source_dir.glob("*.obj"):
scene = Scene.from_file(str(obj_file))
out_path = output_dir / obj_file.with_suffix(".stl").name
scene.save(str(out_path), opts)
print(f"Converted {obj_file.name} -> {out_path.name}")การแปลงจะคงลำดับชั้นของซีน (โหนดพาเรนท์/ชิลด์) ไว้หรือไม่?
ใช่. โครงสร้างต้นไม้ของโหนดจะถูกเก็บรักษาตามที่รูปแบบเป้าหมายอนุญาต รูปแบบเช่น STL เก็บเฉพาะเรขาคณิตแบบแบนโดยไม่มีโครงสร้างโหนด; โครงสร้างลำดับชั้นจะถูกทำให้แบนเมื่อบันทึก รูปแบบเช่น glTF และ COLLADA จะรักษาโครงสร้างลำดับชั้นเต็มรูปแบบ.