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

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

Aspose.3D FOSS لـ 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

الـ 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، مرّر an 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. راجع the مرجع 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

هل المكتبة thread-safe لتحميل ملفات متعددة بشكل متزامن؟?

كل Scene الكائن مستقل. تحميل ملفات منفصلة إلى منفصلة Scene النُسخ من خيوط منفصلة آمنة طالما أنك لا تشارك نسخة واحدة Scene عبر الخيوط دون قفل خارجي.

 العربية