עבודה עם גרף הסצנה
כל תוכן תלת‑ממדי ב-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 מתחיל עם צומת שורש ריק וללא קטעי אנימציה. אתה בונה תוכן על ידי צירוף צמתים צאצאים.
שלב 2: הוספת צמתים ילדים
השתמש 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)
שמות הצמתים הם מחרוזות שרירותיות. אין צורך שהשמות יהיו ייחודיים, אך שימוש בשמות משמעותיים מקל על ניפוי קוד הניווט.
שלב 3: יצירת Mesh והגדרת קודקודים
Mesh היא מחלקת הגיאומטריה הראשית. הוסף vertex positions על‑ידי דחיפה 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 לוקטורי כיוון.
שלב 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 מספק את world-space transformation matrix (read-only), המחושב על‑ידי צירוף כל ה‑ancestor transforms.
שלב 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 יוצר אותו ללא ארגומנט שם.
תמיד הגן על גישה ל‑entity עם בדיקת null לפני המרה לסוג ספציפי. לא כל צומת נושא entity.
שלב 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לפני גישה למאפייני הישות: רבים מהצמתים (צמתי קבוצה, עצמות, ממקמים) אינם נושאים ישות. תמיד יש להגן עם בדיקת 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 |
ראה גם
- תכונות ופונקציונליות: הפנייה המלאה ל-API לכל תחומי הפיצ’רים.
- תמיכה בפורמט: פורמטים תלת‑ממדיים נתמכים, יכולת קריאה/כתיבה, ואפשרויות פורמט.
- איך לבנות 3D Mesh באופן תכנותי