Treballant amb el graf d'escena
Tot el contingut 3D a Aspose.3D FOSS per a TypeScript viu dins d’un Scene objecte organitzat com un arbre de Node objectes. Entendre aquesta jerarquia és la base per a construir, carregar i processar qualsevol fitxer 3D.
Installation
Instal·leu el paquet des de npm abans d’executar qualsevol codi d’aquest guia:
npm install @aspose/3dAssegura’t que el teu tsconfig.json inclou "module": "commonjs" i "moduleResolution": "node" per a una resolució correcta d’importacions de subcamins.
Conceptes del graf d’escena
El graf d’escena té tres nivells:
| Nivell | Classe | Rol |
|---|---|---|
| Escena | Scene | Contenidor de nivell superior. Conté rootNode, animationClips, i assetInfo. |
| Node | Node | Node d’arbre amb nom. Pot tenir nodes fills, una entitat, una transformació i materials. |
| Entitat | Mesh, Camera, Light, … | Contingut adjuntat a un node. Un node porta com a màxim una entitat. |
La cadena d’herència per als blocs principals és:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode es crea automàticament. No la creeu manualment; creeu nodes fills sota ella.
Pas 1: Crear una escena
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
Un nou Scene comença amb un node arrel buit i sense clips d’animació. Construïu contingut adjuntant nodes fills.
Pas 2: Afegir nodes fills
Utilitzeu createChildNode() per fer créixer l’arbre. El mètode retorna el nou Node, de manera que puguis encadenar crides addicionals des de qualsevol nivell:
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)
Els noms dels nodes són cadenes arbitràries. No cal que siguin únics, però utilitzar noms significatius facilita la depuració del codi de recorregut.
Pas 3: Crear una malla i establir vèrtexs
Mesh és la classe de geometria principal. Afegeix posicions de vèrtexs afegint Vector4 valors a mesh.controlPoints, després crida createPolygon() per definir cares per índex de vèrtex:
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 utilitza coordenades homogènies: el w component és 1 per a posicions i 0 per a vectors de direcció.
Pas 4: Estableix les transformacions del node
Cada node té un transform propietat amb translation, rotation, i scaling. Estableix translation per moure el node respecte del seu pare:
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 proporciona la matriu de transformació en l’espai mundial (només lectura), calculada concatenant totes les transformacions dels avantpassats.
Pas 5: Recórrer l’arbre
Escriu una funció recursiva per visitar cada node. Comprova node.entity i node.childNodes a cada nivell:
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);Per a la jerarquia creada anteriorment, la sortida serà:
[none]
parent [none]
child [Mesh]El nom del node arrel és una cadena buida perquè Scene el crea sense cap argument de nom.
Sempre protegeix l’accés a l’entitat amb una comprovació de nul abans de fer el cast a un tipus específic. No tots els nodes tenen una entitat.
Pas 6: Desar a glTF o GLB
Utilitza GltfSaveOptions per controlar el format de sortida. Estableix binaryMode = true per produir un únic autocontingut .glb fitxer; deixa’l false per al JSON .gltf + .bin parella 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');Passa GltfFormat.getInstance() com a argument de format perquè la biblioteca utilitzi el codificador correcte independentment de l’extensió del fitxer.
Consells i bones pràctiques
- Utilitza
createChildNode()en comptes de construirNodedirectament:createChildNode()connecta automàticament la relació pare‑fill i registra el node a l’arbre. - Comprova
node.entityabans d’accedir a les propietats de l’entitat: molts nodes (nodes de grup, ossos, localitzadors) no tenen entitat. Sempre protegeix amb una comprovació de nulitat oinstanceofprova. - Establir
translationen nodes fills, no en vèrtexs de la malla: modificanttransform.translationno és destructiu i composable amb les transformacions del pare. - Prefereix
binaryMode = trueper a GLB: un únic.glbfitxer és més fàcil de distribuir, carregar en navegadors i importar a motors de joc que el dividit.gltf+.binformat. - Recorre via
for...ofsobrechildNodes: evita l’indexació numèrica; utilitza l’iterable directament per a una compatibilitat futura.
Problemes comuns
| Símptoma | Causa probable | Solució |
|---|---|---|
child.entity = mesh no té cap efecte en l’exportació | Entitat assignada al nivell de node incorrecte | Assigna entity al node fulla, no a un node de grup |
node.entity és sempre null | Només comprovant rootNode ell mateix | Recórrer a node.childNodes; rootNode normalment no té entitat |
| Transformació no reflectida al visualitzador GLB | globalTransform no actualitzat | globalTransform es calcula en desar; establir transform.translation abans de cridar scene.save() |
GLB genera un separat .bin sidecar | binaryMode per defecte false | Establir saveOpts.binaryMode = true |
Vegeu també
- Funcionalitats i característiques: referència completa de l’API per a totes les àrees de característiques.
- Suport de formats: formats 3D compatibles, capacitat de lectura/escriptura i opcions de format.
- Com crear una 3D Mesh programàticament