کار با گراف صحنه

تمام محتوای سه‌بعدی در 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

همچنین ببینید

 فارسی