العمل مع مخطط المشهد
جميع المحتوى ثلاثي الأبعاد في Aspose.3D FOSS لـ TypeScript يعيش داخل Scene كائن منظم كشجرة من Node الكائنات. فهم هذه الهرمية هو الأساس لبناء، تحميل، ومعالجة أي ملف ثلاثي الأبعاد.
Installation
قم بتثبيت الحزمة من npm قبل تشغيل أي من الشيفرة في هذا الدليل:
npm install @aspose/3dتأكد من أن tsconfig.json يتضمن "module": "commonjs" و "moduleResolution": "node" لتحقيق حل صحيح لاستيراد المسارات الفرعية.
مفاهيم مخطط المشهد
مخطط المشهد يتكون من ثلاث طبقات:
| المستوى | الفئة | الدور |
|---|---|---|
| المشهد | Scene | حاوية المستوى الأعلى. تحتوي على rootNode, animationClips, و assetInfo. |
| العقدة | Node | عقدة شجرة مسماة. يمكن أن تحتوي على عقد فرعية، كيان، تحويل، ومواد. |
| الكيان | Mesh, Camera, Light, … | محتوى مرفق بعقدة. تحمل العقدة كيانًا واحدًا كحد أقصى. |
سلسلة الوراثة للكتل الأساسية هي:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode يتم إنشاؤه تلقائيًا. لا تقوم بإنشائه يدويًا؛ بل تنشئ عقدًا فرعية تحته.
الخطوة 1: إنشاء مشهد
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
جديد Scene يبدأ بعقدة جذر فارغة ولا يحتوي على animation clips. تقوم بإنشاء المحتوى عن طريق إرفاق child nodes.
الخطوة 2: إضافة عقد فرعية
استخدم createChildNode() لتوسيع الشجرة. تُعيد method العنصر new Node,، لذا يمكنك ربط مكالمات إضافية من أي مستوى:
import { Scene } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
console.log(scene.rootNode.childNodes.length); // 1 (parent)
console.log(parent.childNodes.length); // 1 (child)
أسماء العقد هي سلاسل عشوائية. لا يلزم أن تكون الأسماء فريدة، لكن استخدام أسماء ذات معنى يجعل شفرة التجوال أسهل في التصحيح.
الخطوة 3: إنشاء شبكة وتعيين الرؤوس
Mesh هي primary geometry class. أضف vertex positions عن طريق دفع Vector4 values إلى mesh.controlPoints,، ثم استدعِ createPolygon() لتحديد faces بواسطة vertex index:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4 } from '@aspose/3d/utilities';
const scene = new Scene();
const child = scene.rootNode.createChildNode('parent').createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3); // quad face using all four vertices
child.entity = mesh;
console.log(mesh.controlPoints.length); // 4
console.log(mesh.polygonCount); // 1
Vector4 يستخدم إحداثيات متجانسة: الـ w المكوّن هو 1 للمواقع و 0 للمتجهات الاتجاهية.
الخطوة 4: تعيين تحويلات العقدة
كل عقدة لها transform خاصية مع translation, rotation, و scaling. اضبط translation لتحريك العقدة بالنسبة إلى والدها:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);globalTransform يوفر مصفوفة التحويل في الفضاء العالمي (للقراءة فقط)، يتم حسابها بدمج جميع التحويلات السلفية.
الخطوة 5: استعراض الشجرة
اكتب دالة تكرارية لزيارة كل عقدة. تحقق من node.entity و node.childNodes في كل مستوى:
function traverse(node: any, depth = 0): void {
const indent = ' '.repeat(depth);
const entityType = node.entity ? node.entity.constructor.name : 'none';
console.log(`${indent}${node.name} [${entityType}]`);
for (const child of node.childNodes) {
traverse(child, depth + 1);
}
}
traverse(scene.rootNode);بالنسبة للهيكلية التي تم إنشاؤها أعلاه، سيكون الناتج:
[none]
parent [none]
child [Mesh]اسم عقدة الجذر هو سلسلة فارغة لأن Scene يقوم بإنشائها دون تمرير معامل الاسم.
دائمًا احمِ الوصول إلى الكيان بفحص null قبل التحويل إلى نوع محدد. ليست كل عقدة تحمل كيانًا.
الخطوة 6: حفظ إلى glTF أو GLB
استخدم GltfSaveOptions للتحكم في تنسيق الإخراج. اضبط binaryMode = true لإنتاج ملف واحد مكتمل ذاتيًا .glb ملف; اتركه false لـ JSON .gltf + .bin زوج sidecar:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write a single .glb file
scene.save('scene.glb', GltfFormat.getInstance(), saveOpts);
console.log('Scene saved to scene.glb');تمرير GltfFormat.getInstance() كمعامل format بحيث تستخدم المكتبة المشفر الصحيح بغض النظر عن امتداد الملف.
نصائح وأفضل الممارسات
- استخدم
createChildNode()بدلاً من إنشاءNodeمباشرةً:createChildNode()يقوم تلقائيًا بربط علاقة الأب-الابن وتسجيل العقدة في الشجرة. - تحقق
node.entityقبل الوصول إلى خصائص الكيان: العديد من العقد (عقد المجموعات، العظام، المحددات) لا تحمل كيانًا. احرص دائمًا على الحماية بفحص null أوinstanceofاختبار. - تعيين
translationعلى العقد الفرعية، وليس على رؤوس الشبكة: تعديلtransform.translationغير مدمر ويمكن تركيبه مع تحولات الوالد. - يفضل
binaryMode = trueلـ GLB: واحد.glbالملف أسهل في التوزيع، والتحميل في المتصفحات، والاستيراد إلى محركات الألعاب مقارنةً بالمقسّم.gltf+.binالصيغة. - التنقل عبر
for...ofعبرchildNodes: تجنّب الفهرسة الرقمية؛ استخدم القابل للتكرار مباشرةً لضمان التوافق المستقبلي.
المشكلات الشائعة
| العَرَض | السبب المحتمل | إصلاح |
|---|---|---|
child.entity = mesh ليس له أي تأثير على التصدير | تم تعيين الكيان إلى مستوى عقدة خاطئ | تعيين entity إلى العقدة الورقية، وليس إلى عقدة مجموعة |
node.entity دائمًا null | التحقق فقط rootNode نفسه | التكرار داخل node.childNodes; rootNode عادةً لا يحتوي على كيان |
| التحويل غير معروض في عارض GLB | globalTransform لم يتم التحديث | globalTransform يُحسب عند الحفظ؛ اضبط transform.translation قبل الاستدعاء scene.save() |
GLB ينتج ملفًا منفصلًا .bin ملف جانبي | binaryMode يُفترض أن يكون false | تعيين saveOpts.binaryMode = true |
انظر أيضًا
- الميزات والوظائف: مرجع كامل لواجهة برمجة التطبيقات لجميع مجالات الميزات.
- دعم الصيغ: صيغ 3D المدعومة، القدرة على القراءة/الكتابة، وخيارات الصيغة.
- كيفية بناء 3D Mesh برمجيًا