نحوه تبدیل مدل‌های سه‌بعدی در پایتون

نحوه تبدیل مدل‌های سه‌بعدی در پایتون

تبدیل فرمت با Aspose.3D FOSS برای پایتون یک فرآیند دو مرحله‌ای است: بارگذاری در یک شیء Scene، سپس ذخیره به فرمت خروجی مورد نظر. از آنجا که تمام هندسه در یک نمایش حافظه‌درون‌خطی مشترک نگهداری می‌شود، نیازی به مراحل میانی خاص هر فرمت نیست. بخش‌های زیر رایج‌ترین تبدیل‌ها را همراه با کدهای عملی نشان می‌دهند.

راهنمای گام به گام

مرحله 1: نصب بسته

pip install aspose-3d-foss

هیچ کتابخانه سیستمی، کامپایلری یا وابستگی‌های زمان اجرا اضافی مورد نیاز نیست.


مرحله ۲: بارگذاری مدل منبع

از 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 یکسان برای مرحله ذخیره‌سازی بعدی تولید می‌کنند.


مرحله ۳: بررسی صحنه بارگذاری‌شده

قبل از انجام تبدیل، ارزش دارد که بررسی کنید هندسه به‌درستی بارگذاری شده است. یک فایل گمشده، ویژگی پشتیبانی‌نشده 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")

مرحله ۴: ذخیره در قالب هدف

با مسیر خروجی، 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 باشد. پسوندها در لینوکس به حروف حساس هستند.

فایل‌های بسیار بزرگ باعث تبدیل آهسته می‌شوند

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 حفظ می‌شوند؟

ویژگی‌های پایهٔ مواد فنگ/لامبرت (رنگ پخش) از طریق مدل 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 سلسله‌مراتب کامل را نگه می‌دارند.

 فارسی