כיצד להמיר מודלים תלת‑ממדיים בפייתון

כיצד להמיר מודלים תלת‑ממדיים בפייתון

המרת פורמט עם 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 שומרים על ההיררכיה המלאה.

 עברית