كيفية بناء شبكة ثلاثية الأبعاد باستخدام Aspose.3D في بايثون
يتيح لك Aspose.3D FOSS for Python إنشاء هندسة ثلاثية الأبعاد بالكامل عبر الشيفرة: لا حاجة إلى أداة نمذجة خارجية. تقوم بإنشاء Mesh، وتملأه بمواقع الرؤوس (control_points) وتعريفات الوجوه (polygons)، وتضيف سمات الرؤوس الاختيارية مثل المتجهات العمودية، ثم تحفظ المشهد بأي تنسيق مدعوم.
دليل خطوة بخطوة
الخطوة 1: تثبيت الحزمة
قم بتثبيت Aspose.3D FOSS من PyPI. لا يلزم أي امتدادات أصلية أو مجموعة أدوات المترجم.
pip install aspose-3d-fossتحقق من التثبيت:
from aspose.threed import Scene
print("Aspose.3D FOSS ready")الإصدارات المدعومة من Python: 3.7، 3.8، 3.9، 3.10، 3.11، 3.12.
الخطوة 2: إنشاء مشهد وعقدة
يجب أن تكون كل شبكة داخل رسم بياني للمشهد. أنشئ Scene وأضف Node مسمى لاحتواء الشبكة:
from aspose.threed import Scene
scene = Scene()
node = scene.root_node.create_child_node("triangle")يتم الحفاظ على اسم العقدة في الملف المُصدَّر وهو مفيد للتصحيح والاسترجاع لاحقًا عبر node.get_child("triangle").
الخطوة 3: إنشاء كائن شبكة
إنشاء Mesh مع اسم وصفي اختياري:
from aspose.threed.entities import Mesh
mesh = Mesh("triangle")الشبكة فارغة في البداية: لا توجد رؤوس، لا توجد مضلعات. تقوم بملئها في الخطوات التالية.
الخطوة 4: إضافة نقاط التحكم (الرؤوس)
نقاط التحكم هي مواضع الرؤوس. يتم تخزين كل رأس كـ Vector4(x, y, z, w) حيث w=1 تشير إلى نقطة في الفضاء ثلاثي الأبعاد:
from aspose.threed.utilities import Vector4
##Vertex 0: origin
# Note: control_points returns a copy of the internal vertex list.
# Appending to the returned copy discards the vertex silently.
# Use _control_points to mutate the backing list directly.
# This is a known library limitation — a public add_control_point() API is not yet available.
mesh._control_points.append(Vector4(0.0, 0.0, 0.0, 1.0))
##Vertex 1: 1 unit along X
mesh._control_points.append(Vector4(1.0, 0.0, 0.0, 1.0))
##Vertex 2: apex
mesh._control_points.append(Vector4(0.5, 1.0, 0.0, 1.0))
print(f"Vertices added: {len(mesh.control_points)}")Important: mesh.control_points يُرجِع نسخة من قائمة الرؤوس الداخلية (المستخرج ينفّذ list(self._control_points)). استدعاء mesh.control_points.append(v) يضيف إلى النسخة، وليس إلى الشبكة، لذا يتم تجاهل الرأسة بصمت. استخدم دائمًا mesh._control_points.append(v) لإضافة الرؤوس. الوصول إلى الحالة الخاصة عبر _control_points هو حل معروف؛ قد يتغيّر الواجهة في نسخة مستقبلية من المكتبة.
الخطوة 5: إنشاء وجوه متعددة الأضلاع
حدد طوبولوجيا الوجه باستخدام فهارس الرؤوس. مرّر فهارس الرؤوس إلى create_polygon(). ثلاثة فهارس تُنتج مثلثًا؛ أربعة تُنتج رباعيًا:
##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)
print(f"Polygon count: {mesh.polygon_count}")بالنسبة لشبكة رباعية، ستمرر أربعة مؤشرات: mesh.create_polygon(0, 1, 2, 3).
يجب أن تكون الفهارس مواضع صالحة في control_points (مؤشرها يبدأ من الصفر، ضمن النطاق). ترتيب الالتفاف هو عكس اتجاه عقرب الساعة للسطوح التي تواجه الخارج.
الخطوة 6: إضافة المتجهات العادية للرؤوس
يتم تخزين المتجهات العادية للرؤوس كـ VertexElement مرفقة بالشبكة. استخدم mesh.create_element() مع VertexElementType.NORMAL، MappingMode.CONTROL_POINT، وReferenceMode.DIRECT:
from aspose.threed.entities import VertexElementType, MappingMode, ReferenceMode, VertexElementNormal
from aspose.threed.utilities import Vector4, FVector4
##Create the normal element (returns VertexElementNormal, a VertexElementFVector subclass)
normals: VertexElementNormal = mesh.create_element(
VertexElementType.NORMAL,
MappingMode.CONTROL_POINT,
ReferenceMode.DIRECT
)
##One normal per vertex: all pointing out of the XY plane (0, 0, 1)
normals.set_data([
FVector4(0, 0, 1, 0), # vertex 0
FVector4(0, 0, 1, 0), # vertex 1
FVector4(0, 0, 1, 0), # vertex 2
])
print("Normal layer attached.")MappingMode.CONTROL_POINT يعني عاديًا واحدًا لكل رأس. ReferenceMode.DIRECT يعني أن بيانات العادي تُقرأ بنفس ترتيب نقاط التحكم (بدون مخزن فهرس إضافي).
تستخدم المتجهات العادية FVector4(x, y, z, w) مع w=0 للإشارة إلى اتجاه بدلاً من موقع. FVector4 هو متجه عائم بدقة مفردة؛ بيانات سمة القمة في الفئات الفرعية VertexElementFVector تستخدم هذا النوع.
الخطوة 7: إرفاق Mesh إلى Node وحفظ
أضف الشبكة إلى العقدة، ثم احفظ المشهد:
node.add_entity(mesh)
scene.save("triangle.gltf")
print("Saved triangle.gltf")البرنامج النصي الكامل العامل (جميع الخطوات مجمعة):
from aspose.threed import Scene
from aspose.threed.entities import Mesh, VertexElementType, MappingMode, ReferenceMode, VertexElementNormal
from aspose.threed.utilities import Vector3, Vector4, FVector4
scene = Scene()
node = scene.root_node.create_child_node("triangle")
mesh = Mesh("triangle")
##Add 3 vertices (x, y, z, w)
# Use _control_points to mutate the backing list directly (control_points returns a copy)
mesh._control_points.append(Vector4(0.0, 0.0, 0.0, 1.0))
mesh._control_points.append(Vector4(1.0, 0.0, 0.0, 1.0))
mesh._control_points.append(Vector4(0.5, 1.0, 0.0, 1.0))
##Create a triangle polygon
mesh.create_polygon(0, 1, 2)
##Add normals (create_element returns VertexElementNormal, a VertexElementFVector subclass)
normals: VertexElementNormal = mesh.create_element(VertexElementType.NORMAL, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT)
normals.set_data([
FVector4(0, 0, 1, 0),
FVector4(0, 0, 1, 0),
FVector4(0, 0, 1, 0),
])
node.add_entity(mesh)
scene.save("triangle.gltf")المشكلات الشائعة
| المشكلة | الحل |
|---|---|
IndexError في create_polygon | تحقق من أن جميع الفهارس ضمن range(len(mesh.control_points)). الفهارس تبدأ من الصفر. |
| تصدير Mesh بدون رؤوس | mesh.control_points.append(...) يتجاهل الرؤوس بصمت لأن الخاصية تُعيد نسخة. استخدم mesh._control_points.append(...) بدلاً من ذلك. |
| عدد المتجهات العمودية لا يتطابق مع عدد الرؤوس | عند استخدام MappingMode.CONTROL_POINT + ReferenceMode.DIRECT، يجب أن يحتوي normals.data على بالضبط len(control_points) مدخلات. |
| Mesh مفقودة من الملف المحفوظ | تأكد من أنه تم استدعاء node.add_entity(mesh) قبل scene.save(). Mesh غير مرفقة بأي عقدة لا يتم تصديرها. |
| ترتيب اللف غير صحيح (الوجه يظهر غير مرئي) | ترتيب الرؤوس عكس عقارب الساعة ينتج متجه عمودي يوجه إلى الخارج. عكس ترتيب الفهارس في create_polygon لتغييره. |
polygon_count returns 0 | polygon_count يقرأ نفس القائمة كما في polygons. إذا لم يتم استدعاء create_polygon، تكون القائمة فارغة. |
| المتجهات العمودية تظهر غير صحيحة في العارض | تأكد من أن جميع المتجهات العمودية ذات طول وحدة. احسبها باستخدام n / abs(n) أو مرّر قيمًا مُعَدّة مسبقًا. |
الأسئلة المتكررة
ما الفرق بين Vector3 و Vector4 لنقاط التحكم؟
control_points يخزن كائنات Vector4. المكوّن w هو الإحداثي المتجانس: استخدم w=1 لمواقع الرؤوس وw=0 للمتجهات الاتجاهية مثل النورمال. يُستخدم Vector3 للتحويلات (الإزاحة، التحجيم) ولكن ليس لتخزين الهندسة.
هل يمكنني بناء شبكة باستخدام رباعيات بدلاً من المثلثات؟
نعم. استدعِ mesh.create_polygon(0, 1, 2, 3) بأربعة مؤشرات لتعريف رباعية. بعض أهداف الحفظ (STL، 3MF) تتطلب مثلثات وستقوم بتحويل الرباعيات إلى مثلثات تلقائيًا. يدعم كل من glTF و COLLADA الرباعيات.
كيف أضيف إحداثيات UV؟
استخدم mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX) لإنشاء VertexElementUV لقناة الانتشار، ثم املأ قائمة data الخاصة به بمدخلات Vector4. تستخدم إحداثيات UV x وy؛ عادةً ما تكون z وw صفر. يجب أن يكون الوسيط الأول ثابتًا من نوع TextureMapping (مثال: TextureMapping.DIFFUSE) يحدد أي فتحة نسيج ينتمي إليها طبقة UV.
هل تحتاج الشبكة إلى الـnormals لتصديرها بشكل صحيح؟
لا. المتجهات العادية اختيارية. إذا تم حذفها، فإن معظم عارضات الصور تحسب المتجهات العادية لكل وجه بناءً على ترتيب تدوير المضلع. إضافة المتجهات العادية لكل رأس صراحةً ينتج تظليلًا أكثر سلاسة.
هل يمكنني إضافة عدة شبكات إلى عقدة واحدة؟
نعم. استدعِ node.add_entity(mesh) عدة مرات. كل استدعاء يضيف كيانًا جديدًا إلى node.entities. قد تقوم بعض الصيغ بدمج عدة كيانات في كيان واحد عند التصدير.
كيف أقوم بتثليث شبكة ذات أنواع متعددة من المضلعات؟
استدعِ mesh.triangulate() لتحويل جميع الأرباع و N‑gons إلى مثلثات في الموقع. هذا مفيد قبل الحفظ إلى الصيغ التي تدعم المثلثات فقط.