Работа с графа на сцената
Всичко 3D съдържание в Aspose.3D FOSS за TypeScript се намира вътре в Scene обект, организиран като дърво от Node обекти. Разбирането на тази йерархия е основата за създаване, зареждане и обработка на всеки 3D файл.
Installation
Инсталирайте пакета от npm преди да изпълните какъвто и да е код от това ръководство:
npm install @aspose/3dУверете се, че вашият tsconfig.json включва "module": "commonjs" и "moduleResolution": "node" за правилно sub-path import resolution.
Концепции за графа на сцената
Графът на сцената има три нива:
| Ниво | Клас | Роля |
|---|---|---|
| Сцена | 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 е основният клас за геометрия. Добавете позициите на върховете, като ги натискате 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 предоставя трансформационната матрица в световното пространство (само за четене), изчислена чрез конкатениране на всички трансформации на предците.
Стъпка 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 съпътстващ чифт:
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 формати, възможност за четене/писане и опции за формати.
- Как да създадем 3D мрежа програмно