چگونه یک مش 3D با Aspose.3D در پایتون بسازیم

چگونه یک مش 3D با Aspose.3D در پایتون بسازیم

Aspose.3D FOSS for Python به شما امکان می‌دهد که هندسه 3D را به‌صورت کامل در کد بسازید: نیازی به ابزار مدل‌سازی خارجی نیست. شما یک Mesh ایجاد می‌کنید، آن را با موقعیت‌های راس (control_points) و تعاریف سطح (polygons) پر می‌کنید، ویژگی‌های اختیاری راس مانند نرمال‌ها را پیوست می‌کنید، سپس صحنه را به هر فرمت پشتیبانی‌شده ذخیره می‌کنید.

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

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

Aspose.3D FOSS را از PyPI نصب کنید. هیچ افزونه بومی یا ابزار زنجیره کامپایلر مورد نیاز نیست.

pip install aspose-3d-foss

نصب را تأیید کنید:

from aspose.threed import Scene
print("Aspose.3D FOSS ready")

نسخه‌های پایتون پشتیبانی‌شده: 3.7، 3.8، 3.9، 3.10، 3.11، 3.12.


مرحله ۲: ایجاد یک صحنه و یک گره

هر مش باید داخل یک گراف صحنه زندگی کند. یک Scene ایجاد کنید و یک Node نام‌گذاری‌شده برای نگهداری مش اضافه کنید:

from aspose.threed import Scene

scene = Scene()
node = scene.root_node.create_child_node("triangle")

نام گره در فایل صادر شده حفظ می‌شود و برای اشکال‌زدایی و بازیابی بعدی از طریق node.get_child("triangle") مفید است.


مرحله ۳: ایجاد یک شی مش

یک Mesh را با یک نام توصیفی اختیاری ایجاد کنید:

from aspose.threed.entities import Mesh

mesh = Mesh("triangle")

مش در ابتدا خالی است: هیچ رئوسی، هیچ چندضلعی‌ای وجود ندارد. شما آن را در مراحل زیر پر می‌کنید.


مرحله ۴: افزودن نقاط کنترل (رئوس)

نقاط کنترل موقعیت رئوس هستند. هر راس به صورت 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)}")

مهم: 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 باشند (صفر‑پایه، در محدوده). ترتیب پیچش برای نرمال‌های جهت‌دار به سمت بیرون، خلاف ساعتگرد است.


مرحله ۶: افزودن نرمال‌های راس

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


مرحله ۷: مش را به گره متصل کنید و ذخیره کنید

مش را به گره اضافه کنید، سپس صحنه را ذخیره کنید:

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")

مشکلات رایج

IssueResolution
IndexError در create_polygonاطمینان حاصل کنید که همهٔ ایندکس‌ها در range(len(mesh.control_points)) هستند. ایندکس‌ها صفر‑پایه‌اند.
Mesh exports with zero verticesmesh.control_points.append(...) به‌صورت ساکت راس‌ها را حذف می‌کند زیرا این ویژگی یک کپی برمی‌گرداند. به‌جای آن از mesh._control_points.append(...) استفاده کنید.
Normals count does not match vertex countهنگام استفاده از MappingMode.CONTROL_POINT + ReferenceMode.DIRECT، normals.data باید دقیقاً len(control_points) ورودی داشته باشد.
Mesh missing from saved fileتأیید کنید که node.add_entity(mesh) قبل از scene.save() فراخوانی شده است. مشی که به هیچ نودی متصل نیست، صادر نمی‌شود.
Wrong winding order (face appears invisible)ترتیب راس‌ها به‌صورت پادساعتگرد نرمالی به سمت بیرون تولید می‌کند. برای معکوس کردن آن، ترتیب ایندکس‌ها را در create_polygon معکوس کنید.
polygon_count returns 0polygon_count همان فهرست را که polygons می‌خواند، می‌خواند. اگر create_polygon فراخوانی نشده باشد، فهرست خالی است.
Normals appear incorrect in viewerاطمینان حاصل کنید که تمام بردارهای نرمال دارای طول واحد هستند. با 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 معمولاً 0 هستند. اولین آرگومان باید یک ثابت TextureMapping باشد (مثلاً TextureMapping.DIFFUSE) که تعیین می‌کند لایه UV به کدام اسلات بافت تعلق دارد.

آیا مش برای خروجی صحیح به نرمال‌ها نیاز دارد؟

نه. نرمال‌ها اختیاری هستند. اگر حذف شوند، اکثر نمایشگرها نرمال‌های سطحی را بر اساس ترتیب چرخش چندضلعی محاسبه می‌کنند. افزودن نرمال‌های صریح به‌ازای هر راس، سایه‌زنی نرم‌تری ایجاد می‌کند.

آیا می‌توانم چندین مش را به یک گره اضافه کنم؟

بله. node.add_entity(mesh) را چندین بار فراخوانی کنید. هر فراخوانی یک موجودیت جدید به node.entities اضافه می‌کند. برخی فرمت‌ها ممکن است چندین موجودیت را در هنگام خروجی به یک موجودیت مسطح کنند.

چگونه یک مش را با انواع چندضلعی‌های ترکیبی مثلث‌بندی کنم؟

mesh.triangulate() را فراخوانی کنید تا تمام چهارضلعی‌ها و N‑گون‌ها را به‌صورت درجا به مثلث‌ها تبدیل کنید. این کار پیش از ذخیره‌سازی به قالب‌هایی که فقط از مثلث‌ها پشتیبانی می‌کنند، مفید است.

 فارسی