כיצד להמיר מודלים תלת‑ממדיים בפייתון
המרת פורמט עם Aspose.3D FOSS for Python היא תהליך של שני שלבים: טעינה לאובייקט Scene, ולאחר מכן שמירה לפורמט הפלט הרצוי. מכיוון שכל הגאומטריה מוחזקת בייצוג משותף בזיכרון, אין צורך בשלבים ביניים ספציפיים לפורמט. החלקים שלהלן מציגים את ההמרות הנפוצות ביותר עם קוד עובד.
מדריך שלב אחר שלב
שלב 1: התקנת החבילה
pip install aspose-3d-fossאין צורך בספריות מערכת, במקמלים או בתלויות זמן ריצה נוספות.
שלב 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 משתמשת בסיומת כדי לבחור את ה‑parser.
פלט glTF חסר מרקמים
Aspose.3D FOSS מעביר תכונות גאומטריה וחומר במהלך ההמרה. אם קובץ המקור OBJ מתייחס לקבצי תמונה חיצוניים ב-.mtl, קבצי התמונה האלה אינם מועתקים אוטומטית לצד ה-.gltf. העתק את קבצי המרקם לתיקיית הפלט ידנית לאחר השמירה.
פלט STL נראה הפוך מבפנים (נורמליות הפנים הפוכות)
STL אינו נושא מטא‑נתוני סדר הריפוד. אם נורמליות הפלט הפוכות, הגדר את אפשרויות StlSaveOptions אם זמינות, או הפוך את מערכת הקואורדינטות בזמן הטעינה: ObjLoadOptions.flip_coordinate_system = True.
ValueError: unsupported format בזמן שמירה
בדוק שהרחבת קובץ הפלט היא אחת מ.obj, .stl, .gltf, .glb, .dae, .3mf. הרחבות רגישות לאותיות גדולות/קטנות בלינוקס.
קבצים גדולים מאוד גורמים להמרה איטית
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 (diffuse colour) מועברים דרך מודל Scene ונכתבים לתוך בלוק החומר של glTF. פרמטרי שיידר Procedural או custom שלא ניתנים לביטוי במודל החומר של 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 שומרים על ההיררכיה המלאה.