كيفية تحميل نماذج ثلاثية الأبعاد في بايثون

كيفية تحميل نماذج ثلاثية الأبعاد في بايثون

Aspose.3D FOSS for Python يوفر واجهة برمجة تطبيقات بسيطة لفتح ملفات 3D دون أي تبعيات أصلية. بعد تحميل ملف إلى كائن Scene، يمكنك استعراض تسلسل العقد وقراءة بيانات الهندسة الخام لكل شبكة في المشهد.

دليل خطوة بخطوة

الخطوة 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 هي الحاوية العليا لجميع بيانات 3D. استوردها مع أي فئات خيارات التحميل التي تحتاجها.

from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions

جميع الفئات العامة موجودة تحت aspose.threed أو حزمها الفرعية (aspose.threed.entities، aspose.threed.formats، aspose.threed.utilities).


الخطوة 3: تحميل ملف

استخدم الطريقة الساكنة Scene.from_file() لفتح أي تنسيق مدعوم. المكتبة تكتشف التنسيق تلقائيًا من امتداد الملف.

##Automatic format detection
scene = Scene.from_file("model.obj")

بدلاً من ذلك، أنشئ مثيل Scene واستدعِ open()؛ مفيد عندما تريد تمرير خيارات التحميل أو معالجة الأخطاء صراحةً:

scene = Scene()
scene.open("model.obj")

يدعم الطريقتان ملفات OBJ و STL (ثنائي و ASCII) و glTF 2.0 / GLB و COLLADA (DAE) و 3MF.


الخطوة 4: استعراض عقد المشهد

المشهد المحمَّل هو شجرة من كائنات Node متجذرة عند 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 (الشبكات، الكاميرات، الأضواء). تحقق من node.entities لمعرفة ما تم إرفاقه.


الخطوة 5: الوصول إلى بيانات الرؤوس والمضلعات

حوّل كيان العقدة إلى Mesh واقرأ نقاط التحكم (مواقع الرؤوس) والبوليجونات (قوائم فهارس الوجوه):

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 المثلثات كواجهات خام، وليس كشبكة مفهرسة. بعد التحميل، يتم تركيب المضلعات من تلك الواجهات. إذا ظهر polygons فارغًا، فافحص len(mesh.control_points)؛ إذا كان العدد مضاعفًا للعدد 3 فإن الهندسة مخزنة بصيغة غير مفهرسة وكل ثلاثية متتالية من الرؤوس تشكل مثلثًا واحدًا.

عدم توافق نظام الإحداثيات (النموذج يبدو مدورًا أو معكوسًا)

تستخدم الأدوات المختلفة اتفاقيات مختلفة (Y‑up مقابل Z‑up، اليد اليسرى مقابل اليد اليمنى). اضبط ObjLoadOptions.flip_coordinate_system = True أو طبّق دورانًا على Transform الخاص بالعقدة الجذرية بعد التحميل.

AttributeError: 'NoneType' object has no attribute 'polygons'

قد تحتوي قائمة الكيانات الخاصة بالعقدة على كيانات غير شبكية (كاميرات، أضواء). احرص دائمًا على الحماية باستخدام isinstance(entity, Mesh) قبل التحويل.


الأسئلة المتكررة (FAQ)

ما هي صيغ 3D التي يمكنني تحميلها؟

OBJ (Wavefront)، STL (ثنائي و ASCII)، glTF 2.0 / GLB، COLLADA (DAE)، و 3MF. يتم دعم تجزئة ملفات FBX جزئياً لكن التحليل الكامل لم يكتمل بعد.

هل تحميل ملف OBJ يحمل أيضًا مادة .mtl؟

نعم، عندما ObjLoadOptions.enable_materials = True (الإعداد الافتراضي). تبحث المكتبة عن ملف .mtl في نفس الدليل الذي يوجد فيه ملف .obj. إذا كان .mtl مفقودًا، لا يزال يتم تحميل الهندسة ويتم إصدار تحذير.

هل يمكنني تحميل ملف من تدفق بايت بدلاً من المسار؟

نعم. scene.open() يقبل أي كائن شبيه بالملف يحتوي على طريقة .read() بالإضافة إلى سلسلة مسار الملف. مرّر تدفقًا ثنائيًا مفتوحًا (مثلاً، io.BytesIO) مباشرة. Scene.from_file() يقبل فقط سلسلة مسار الملف.

كيف أحصل على المتجهات العمودية للسطح؟

بعد التحميل، تحقق من 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 واحد عبر الخيوط دون قفل خارجي.

 العربية