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/3d

Assegura’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:

NivellClasseRol
EscenaSceneContenidor de nivell superior. Conté rootNode, animationClips, i assetInfo.
NodeNodeNode d’arbre amb nom. Pot tenir nodes fills, una entitat, una transformació i materials.
EntitatMesh, 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 construir Node directament: createChildNode() connecta automàticament la relació pare‑fill i registra el node a l’arbre.
  • Comprova node.entity abans 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 o instanceof prova.
  • Establir translation en nodes fills, no en vèrtexs de la malla: modificant transform.translation no és destructiu i composable amb les transformacions del pare.
  • Prefereix binaryMode = true per a GLB: un únic .glb fitxer és més fàcil de distribuir, carregar en navegadors i importar a motors de joc que el dividit .gltf + .bin format.
  • Recorre via for...of sobre childNodes: evita l’indexació numèrica; utilitza l’iterable directament per a una compatibilitat futura.

Problemes comuns

SímptomaCausa probableSolució
child.entity = mesh no té cap efecte en l’exportacióEntitat assignada al nivell de node incorrecteAssigna entity al node fulla, no a un node de grup
node.entity és sempre nullNomés comprovant rootNode ell mateixRecórrer a node.childNodes; rootNode normalment no té entitat
Transformació no reflectida al visualitzador GLBglobalTransform no actualitzatglobalTransform es calcula en desar; establir transform.translation abans de cridar scene.save()
GLB genera un separat .bin sidecarbinaryMode per defecte falseEstablir saveOpts.binaryMode = true

Vegeu també

 Català