کار با گراف صحنه
تمام محتوای سهبعدی در Aspose.3D FOSS برای TypeScript داخل یک Scene شیء سازماندهیشده به شکل درختی از Node اشیاء. درک این سلسلهمراتب پایهای برای ساخت، بارگذاری و پردازش هر فایل سهبعدی است.
نصب
پکیج را از 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 بهصورت خودکار ایجاد میشود. شما آن را بهصورت دستی ایجاد نمیکنید؛ گرههای فرزند را زیر آن ایجاد میکنید.
گام ۱: ایجاد یک صحنه
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 با یک گره ریشه خالی و بدون کلیپهای انیمیشن شروع میشود. شما محتوا را با اتصال گرههای فرزند میسازید.
مرحله ۲: افزودن گرههای فرزند
استفاده کنید createChildNode() برای رشد درخت. این متد مقدار جدید را برمیگرداند 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)
نامهای گره رشتههای دلخواهی هستند. نیازی به یکتا بودن نامها نیست، اما استفاده از نامهای معنادار کد پیمایش را برای اشکالزدایی آسانتر میکند.
مرحله ۳: ایجاد یک مش و تنظیم رئوس
Mesh کلاس اصلی هندسه است. موقعیتهای راس را با افزودن Vector4 مقدارها را به mesh.controlPoints,، سپس فراخوانی کنید createPolygon() برای تعریف سطحها بر اساس شاخص راس:
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 برای بردارهای جهتدار.
مرحله ۴: تنظیم تبدیلات گره
هر گره دارای یک 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() به عنوان آرگومان قالب تا کتابخانه از رمزگذار صحیح استفاده کند صرفنظر از پسوند فایل.
نکات و بهترین شیوهها
- استفاده کنید
createChildNode()بهجای ساختNodeبهصورت مستقیم:createChildNode()بهصورت خودکار رابطه والد‑فرزند را برقرار میکند و گره را در درخت ثبت مینماید. - بررسی کنید
node.entityقبل از دسترسی به ویژگیهای موجودیت: گرههای بسیاری (گرههای گروهی، استخوانها، مکانیابها) هیچ موجودیتی ندارند. همیشهinstanceofآزمون کنید. - تنظیم کنید
translationروی گرههای فرزند، نه روی رئوس مش:تغییرtransform.translationبدون تخریب است و میتواند با تبدیلات والد ترکیب شود. - ترجیح دهید
binaryMode = trueبرای GLB: یک.glbفایل توزیع، بارگذاری در مرورگرها و وارد کردن به موتورهای بازی آسانتر است نسبت به نسخه تقسیمشده.gltf+.binقالب. - پیمایش از طریق
for...ofرویchildNodes: از ایندکسگذاری عددی خودداری کنید؛ بهجای آن، iterable را مستقیماً برای سازگاری آینده استفاده کنید.
مشکلات رایج
| علائم | دلیل محتمل | رفع |
|---|---|---|
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 |
همچنین ببینید
- ویژگیها و عملکردها: مرجع کامل API برای تمام حوزههای ویژگی.
- پشتیبانی از فرمتها: فرمتهای 3D پشتیبانیشده، قابلیت خواندن/نوشتن، و گزینههای فرمت.
- چگونه یک 3D Mesh را بهصورت برنامهنویسی ایجاد کنیم.