Características y Funcionalidades
Aspose.3D FOSS para TypeScript es una biblioteca de Node.js bajo licencia MIT para cargar, construir y exportar escenas 3D. Se entrega con definiciones de tipos completas de TypeScript, una única dependencia en tiempo de ejecución (xmldom), y soporte para seis formatos de archivo 3D principales. Esta página es la referencia principal para todas las áreas de funcionalidad e incluye ejemplos de código TypeScript ejecutables para cada una.
Instalación y configuración
Instala el paquete desde npm usando un solo comando:
npm install @aspose/3dEl paquete está dirigido a CommonJS y requiere Node.js 18 o posterior. Después de la instalación, verifica que tu tsconfig.json incluya las siguientes opciones del compilador para una compatibilidad total:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true
}
}Importa el principal Scene clase desde la raíz del paquete. Las clases de opciones específicas de formato se importan desde sus sub‑rutas respectivas:
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';Características y Funcionalidades
Compatibilidad de formatos
Aspose.3D FOSS for TypeScript lee y escribe seis formatos de archivo 3D principales. La detección de formato es automática a partir de los números mágicos binarios al cargar, por lo que no es necesario especificar el formato de origen explícitamente.
| Formato | Leer | Escribir | Notas |
|---|---|---|---|
| OBJ (Wavefront) | Sí | Sí | Lee/escribe .mtl materiales; usar ObjLoadOptions.enableMaterials para importación |
| glTF 2.0 | Sí | Sí | Formato de texto JSON; materiales PBR |
| GLB | Sí | Sí | glTF binario; establecido GltfSaveOptions.binaryMode = true |
| STL | Sí | Sí | Binario y ASCII; verificado el ciclo completo |
| 3MF | Sí | Sí | 3D Manufacturing Format with color and material metadata |
| FBX | No* | No* | El importador/exportador existe pero la detección automática del formato no está conectada |
| COLLADA (DAE) | Sí | Sí | Escala de unidades, geometría, materiales y clips de animación |
Cargando OBJ con materiales:
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
options.flipCoordinateSystem = false;
options.scale = 1.0;
options.normalizeNormal = true;
scene.open('model.obj', options);Guardando en GLB (glTF binario):
import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
// ... build or load scene content
const opts = new GltfSaveOptions();
opts.binaryMode = true;
scene.save('output.glb', GltfFormat.getInstance(), opts);Grafo de escena
Todo el contenido 3D se organiza como un árbol de Node objetos con raíz en scene.rootNode. Cada nodo puede llevar un Entity (un Mesh, Camera, Light, o otro SceneObject) Transform que lo posiciona relativo a su padre.
Clases clave del grafo de escena:
Scene: el contenedor de nivel superior; contienerootNodeyanimationClipsNode: un nodo de árbol con nombre conchildNodes,entity,transform, ymaterialsEntity: clase base para objetos adjuntables (Mesh,Camera,Light)SceneObject: clase base compartida porNodeyEntityA3DObject: clase base raíz connamey bolsa de propiedadesTransform: traslación local, rotación (Euler y Cuaternión), y escala
Recorriendo el grafo de escena:
import { Scene, Node, Mesh } from '@aspose/3d';
const scene = new Scene();
scene.open('model.obj');
function visit(node: Node, depth: number = 0): void {
const indent = ' '.repeat(depth);
console.log(`${indent}Node: ${node.name}`);
if (node.entity) {
console.log(`${indent} Entity: ${node.entity.constructor.name}`);
}
for (const child of node.childNodes) {
visit(child, depth + 1);
}
}
visit(scene.rootNode);Crear una jerarquía de escena programáticamente:
import { Scene, Node } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('chassis');
const wheel = parent.createChildNode('wheel_fl');
wheel.transform.translation.set(0.9, -0.3, 1.4);Geometría y Malla
Mesh es el tipo de geometría principal. Extiende Geometry y expone puntos de control (vértices), índices de polígonos y elementos de vértice para normales, UVs y colores de vértice.
Clases clave de geometría:
Mesh: malla de polígonos concontrolPointsypolygonCountGeometry: clase base con gestión de elementos de vérticeVertexElementNormal: normales por vértice o por vértice de polígonoVertexElementUV: coordenadas de textura (uno o más canales UV)VertexElementVertexColor: datos de color por vérticeMappingMode: controla cómo se asignan los datos de los elementos a los polígonos (CONTROL_POINT,POLYGON_VERTEX,POLYGON,EDGE,ALL_SAME)ReferenceMode: controla la estrategia de indexado (DIRECT,INDEX,INDEX_TO_DIRECT)VertexElementType: identifica la semántica de un elemento de vérticeTextureMapping: enumeración de canales de textura
Lectura de datos de malla de una escena cargada:
import { Scene, Mesh, VertexElementType } from '@aspose/3d';
const scene = new Scene();
scene.open('model.stl');
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
const mesh = node.entity as Mesh;
console.log(`Mesh "${node.name}": ${mesh.controlPoints.length} vertices, ${mesh.polygonCount} polygons`);
const normals = mesh.getElement(VertexElementType.NORMAL);
if (normals) {
console.log(` Normal mapping: ${normals.mappingMode}`);
}
}
}Sistema de materiales
Aspose.3D FOSS para TypeScript soporta tres tipos de material que cubren todo el rango, desde el sombreado Phong heredado hasta el renderizado basado en física:
LambertMaterial: color difuso y color ambiental; se asigna a materiales simples OBJ/DAEPhongMaterial: añade color especular, brillo y emisivo; el tipo de material OBJ predeterminadoPbrMaterial: modelo físico de rugosidad/metallicidad; usado para importación y exportación glTF 2.0
Leyendo materiales de una escena OBJ cargada:
import { Scene, PhongMaterial, LambertMaterial } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.open('model.obj', options);
for (const node of scene.rootNode.childNodes) {
for (const mat of node.materials) {
if (mat instanceof PhongMaterial) {
const phong = mat as PhongMaterial;
console.log(` Phong: diffuse=${JSON.stringify(phong.diffuseColor)}, shininess=${phong.shininess}`);
} else if (mat instanceof LambertMaterial) {
console.log(` Lambert: diffuse=${JSON.stringify((mat as LambertMaterial).diffuseColor)}`);
}
}
}Aplicando un material PBR al construir una escena glTF:
import { Scene, Node, PbrMaterial } from '@aspose/3d';
import { Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const node = scene.rootNode.createChildNode('sphere');
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.8, 0.2, 0.2); // red-tinted albedo; albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.5;
node.material = mat;
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), opts);Utilidades matemáticas
La biblioteca incluye un conjunto completo de tipos matemáticos 3D, todos totalmente tipados:
Vector3: vector de 3 componentes; soportaminus(),times(),dot(),cross(),normalize(),length,angleBetween()Vector4: vector de 4 componentes para coordenadas homogéneasMatrix4: matriz de transformación 4×4 conconcatenate(),transpose,decompose,setTRSQuaternion: cuaternión de rotación confromEulerAngle(): (estático, singular),eulerAngles(): (método de instancia),slerp(),normalize()BoundingBox: caja delimitadora alineada a los ejes conminimum,maximum,center,size,mergeFVector3: variante de precisión simple deVector3: utilizado en datos de elementos de vértice
Calculando una caja delimitadora a partir de los vértices de la malla:
import { Scene, Mesh, Vector3, BoundingBox } from '@aspose/3d';
const scene = new Scene();
scene.open('model.obj');
let box = new BoundingBox();
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
for (const pt of (node.entity as Mesh).controlPoints) {
box.merge(new Vector3(pt.x, pt.y, pt.z));
}
}
}
console.log('Center:', box.center);
console.log('Extents:', box.size);Construyendo una transformación a partir de ángulos de Euler:
import { Quaternion, Vector3, Matrix4 } from '@aspose/3d';
const rot = Quaternion.fromEulerAngle(0, Math.PI / 4, 0); // 45° around Y
const mat = new Matrix4();
mat.setTRS(new Vector3(0, 0, 0), rot, new Vector3(1, 1, 1));Sistema de Animación
La API de animación modela clips, nodos, canales y secuencias de fotogramas clave:
AnimationClip: colección nombrada de nodos de animación; accedida a través descene.animationClips;: ; exponeanimations: AnimationNode[]AnimationNode: grupo nombrado deBindPoint: s; creado medianteclip.createAnimationNode(name), accedido a través declip.animationsBindPoint: enlaza unAnimationNode: a una propiedad específica en un objeto de escena; exponeproperty: ychannelsCountAnimationChannel: extiendeKeyframeSequence; contiene un separadokeyframeSequence; accedido a través debindPoint.getChannel(name)KeyFrame: un único par tiempo/valor; lleva por fotograma claveinterpolation: InterpolationKeyframeSequence: lista ordenada deKeyFrameobjetos a través dekeyFrames; tienepreBehaviorypostBehavior(Extrapolation)Interpolation: enum:LINEAR,CONSTANT,BEZIER,B_SPLINE,CARDINAL_SPLINE,TCB_SPLINEExtrapolation: clase contype: ExtrapolationTypeyrepeatCount: numberExtrapolationType: enum:CONSTANT,GRADIENT,CYCLE,CYCLE_RELATIVE,OSCILLATE
Leyendo datos de animación de una escena cargada:
import { Scene, AnimationNode, BindPoint } from '@aspose/3d';
const scene = new Scene();
scene.open('animated.dae'); // COLLADA animation import is supported
for (const clip of scene.animationClips) {
console.log(`Clip: "${clip.name}"`);
for (const animNode of clip.animations) { // clip.animations, not clip.nodes
console.log(` AnimationNode: ${animNode.name}`);
for (const bp of animNode.bindPoints) { // animNode.bindPoints, not animNode.channels
console.log(` BindPoint: property="${bp.property.name}", channels=${bp.channelsCount}`);
}
}
}Soporte de Stream y Buffer
Usar scene.openFromBuffer() para cargar una escena 3D directamente desde una memoria Buffer. Este es el patrón recomendado para funciones sin servidor, canalizaciones de transmisión y procesamiento de recursos obtenidos mediante HTTP sin escribir en disco.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import * as fs from 'fs';
// Load file into memory, then parse from buffer
const buffer: Buffer = fs.readFileSync('model.obj');
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.openFromBuffer(buffer, options);
for (const node of scene.rootNode.childNodes) {
if (node.entity) {
console.log(node.name, node.entity.constructor.name);
}
}La detección automática de formato a partir de los números mágicos binarios se aplica al cargar desde un buffer, por lo que los archivos GLB, STL binario y 3MF se reconocen sin especificar un parámetro de formato.
Ejemplos de uso
Ejemplo 1: Cargar OBJ y Exportar a GLB
Este ejemplo carga un archivo Wavefront OBJ con materiales, y luego vuelve a exportar la escena como un archivo glTF binario (GLB) adecuado para uso web y en motores de juego.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
function convertObjToGlb(inputPath: string, outputPath: string): void {
const scene = new Scene();
const loadOpts = new ObjLoadOptions();
loadOpts.enableMaterials = true;
loadOpts.flipCoordinateSystem = false;
loadOpts.normalizeNormal = true;
scene.open(inputPath, loadOpts);
// Report what was loaded
for (const node of scene.rootNode.childNodes) {
if (node.entity) {
console.log(`Loaded: ${node.name} (${node.entity.constructor.name})`);
}
}
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write .glb instead of .gltf + .bin
scene.save(outputPath, GltfFormat.getInstance(), saveOpts);
console.log(`Exported GLB to: ${outputPath}`);
}
convertObjToGlb('input.obj', 'output.glb');Ejemplo 2: Recorrido completo STL con Validación de Normales
Este ejemplo carga un archivo STL binario, muestra la información de normales por vértice, y luego vuelve a exportar la escena como STL ASCII y verifica el recorrido completo.
import { Scene, Mesh, VertexElementNormal, VertexElementType } from '@aspose/3d';
import { StlLoadOptions, StlSaveOptions } from '@aspose/3d/formats/stl';
const scene = new Scene();
const loadOpts = new StlLoadOptions();
scene.open('model.stl', loadOpts);
let totalPolygons = 0;
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
const mesh = node.entity as Mesh;
totalPolygons += mesh.polygonCount;
const normElem = mesh.getElement(VertexElementType.NORMAL) as VertexElementNormal | null;
if (normElem) {
console.log(` Normals: ${normElem.data.length} entries, mapping=${normElem.mappingMode}`);
}
}
}
console.log(`Total polygons: ${totalPolygons}`);
// Re-export as ASCII STL
const saveOpts = new StlSaveOptions();
saveOpts.binaryMode = false; // ASCII output
scene.save('output_ascii.stl', saveOpts);Ejemplo 3: Construir una escena programáticamente y guardarla como glTF
Este ejemplo construye una escena con un material PBR desde cero y la guarda como un archivo glTF JSON.
import { Scene, Mesh, PbrMaterial, Vector4, Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const node = scene.rootNode.createChildNode('floor');
// Build a simple quad mesh (two triangles)
// controlPoints are Vector4 (x, y, z, w) where w=1 for positions
const mesh = new Mesh();
mesh.controlPoints.push(
new Vector4(-1, 0, -1, 1),
new Vector4( 1, 0, -1, 1),
new Vector4( 1, 0, 1, 1),
new Vector4(-1, 0, 1, 1),
);
mesh.createPolygon([0, 1, 2]);
mesh.createPolygon([0, 2, 3]);
node.entity = mesh;
// Apply a PBR material
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.6, 0.6, 0.6); // albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.8;
node.material = mat;
// Save as JSON glTF
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('floor.gltf', GltfFormat.getInstance(), opts);
console.log('Scene written to floor.gltf');Consejos y mejores prácticas
- Usar
ObjLoadOptions.enableMaterials = truecuando necesites datos de material de archivos .mtl. Sin ello, la lista de materiales en cada nodo estará vacía. - Preferir
binaryMode = truepara GLB al producir activos para web o motores de juego. El GLB binario es un único archivo autónomo y se carga más rápido en navegadores y motores que la división JSON + .bin. - Usar
openFromBuffer()en entornos sin servidor para evitar E/S de archivos temporales. Obtén el activo, pasa elBufferdirectamente, y escribe la salida a un flujo o a otro búfer. - Verificar
node.entityantes de convertir: no todos los nodos llevan una entidad. Siempre protege con uninstanceofverifique antes de accederMesh-propiedades específicas comocontrolPoints. - Establecer
normalizeNormal = trueenObjLoadOptionscuando sus archivos OBJ de origen provienen de fuentes no confiables. Esto evita que normales degeneradas se propaguen a los pasos posteriores de renderizado o validación. - Mantenga
strict: trueen tsconfig.json: la biblioteca está escrita connoImplicitAnyystrictNullChecks. Desactivarstrictoculta errores de tipo reales y anula el valor de la API tipada. - Recorrer vía
childNodes, no un bucle de índice: elchildNodesla propiedad devuelve un iterable; evite depender del indexado numérico para mantener la compatibilidad futura.
Problemas comunes
| Síntoma | Causa probable | Solución |
|---|---|---|
| Lista de materiales vacía después de cargar OBJ | enableMaterials no establecido | Establecer options.enableMaterials = true |
| El archivo GLB contiene un sidecar .bin separado | binaryMode predeterminando a false | Establecer opts.binaryMode = true |
| Faltan normales de vértice en la salida STL | El modo ASCII de STL omite las normales por cara | Cambiar a binaryMode = true o calcular normales antes de exportar |
node.entity es siempre null | Recorriendo solo rootNode, no sus hijos | Recursar en node.childNodes |
| Error de TypeScript: la propiedad no existe | Antiguo @types caché | Ejecutar npm install @aspose/3d de nuevo; sin separado @types se necesita el paquete |
openFromBuffer lanza error de formato | Formato no detectable automáticamente a partir del magic | Pase la clase de opción de formato explícita como segundo argumento |
Preguntas Frecuentes
¿Requiere la biblioteca algún complemento nativo o paquetes del sistema? No. Aspose.3D FOSS para TypeScript tiene una única dependencia en tiempo de ejecución: xmldom, que es JavaScript puro y se instala automáticamente mediante npm. No hay .node complementos nativos y sin paquetes del sistema que instalar.
¿Qué versiones de Node.js son compatibles? Node.js 18, 20 y 22 LTS. La biblioteca tiene como objetivo una salida CommonJS y utiliza características del lenguaje ES2020 internamente.
¿Puedo usar la biblioteca en un paquete para navegador (webpack/esbuild)? La biblioteca tiene como objetivo Node.js y utiliza el Node.js fs y Buffer APIs. El empaquetado para navegador no está oficialmente soportado. Para uso en navegador, cargue la escena del lado del servidor y transmita el resultado (p. ej., como GLB) al cliente.
¿Cuál es la diferencia entre GltfSaveOptions.binaryMode = true y false? binaryMode = false produce un .gltf archivo JSON más un separado .bin sidecar de búfer binario. binaryMode = true produce un único auto‑contenible .glb archivo. Use true para la entrega de activos en producción.
¿Puedo cargar un archivo desde una respuesta HTTP sin guardarlo en disco? Sí. Obtenga la respuesta como una Buffer (p. ej., usando node-fetch o la incorporada fetch en Node 18+), luego llame scene.openFromBuffer(buffer, options).
¿Está completo el soporte de FBX? No. Existen clases de importador y exportador de FBX en la biblioteca, pero FBX no está integrado en Scene.open() o Scene.save() detección automática. Llamar scene.open('file.fbx') no invocará el importador FBX; el archivo será manejado por la ruta de respaldo STL. Use directamente las clases importador/exportador específicas de FBX si necesita I/O de FBX. Consulte la tabla de soporte de formatos arriba que marca FBX como No*.
¿La biblioteca admite TypeScript 4.x? Se recomienda TypeScript 5.0+. TypeScript 4.7+ debería funcionar en la práctica, pero la biblioteca se prueba y se desarrolla contra 5.0+.
Resumen de la Referencia de API
| Clase | Módulo | Propósito |
|---|---|---|
Scene | @aspose/3d | Contenedor de escena de nivel superior; open(), openFromBuffer(), save(), rootNode, animationClips |
Node | @aspose/3d | Nodo del grafo de escena; childNodes, entity, transform, materials, createChildNode() |
Entity | @aspose/3d | Clase base para objetos que se pueden adjuntar a la escena |
SceneObject | @aspose/3d | Clase base compartida por Node y Entity |
A3DObject | @aspose/3d | Base raíz con name y bolsa de propiedades |
Transform | @aspose/3d | Traslación, rotación y escala locales |
Mesh | @aspose/3d | Malla poligonal; controlPoints, polygonCount, createPolygon(), elementos de vértice |
Geometry | @aspose/3d | Clase base para tipos de geometría |
Camera | @aspose/3d | entidad de cámara con campo de visión y configuraciones de proyección |
Light | @aspose/3d | entidad de luz (puntual, direccional, foco) |
LambertMaterial | @aspose/3d | Modelo de sombreado difuso + ambiental |
PhongMaterial | @aspose/3d | Phong shading con specular y emissive |
PbrMaterial | @aspose/3d | Modelo basado en la física de rugosidad/metallic para glTF |
Vector3 | @aspose/3d | 3-component double-precision vector |
Vector4 | @aspose/3d | 4-component vector for homogeneous math |
Matrix4 | @aspose/3d | 4×4 transformation matrix |
Quaternion | @aspose/3d | Cuaternión de rotación |
BoundingBox | @aspose/3d | Caja delimitadora alineada a los ejes |
FVector3 | @aspose/3d | Variante de precisión simple de Vector3 |
VertexElementNormal | @aspose/3d | Normales por vértice o por vértice de polígono |
VertexElementUV | @aspose/3d | Elemento de vértice de coordenada de textura |
VertexElementVertexColor | @aspose/3d | Elemento de vértice de color por vértice |
MappingMode | @aspose/3d | Enum: CONTROL_POINT, POLYGON_VERTEX, POLYGON, ALL_SAME |
ReferenceMode | @aspose/3d | Enum: DIRECT, INDEX, INDEX_TO_DIRECT |
AnimationClip | @aspose/3d | Animación nombrada; expone animations: AnimationNode[]; creado mediante scene.createAnimationClip(name) |
AnimationNode | @aspose/3d | Grupo nombrado de BindPoints; creado mediante clip.createAnimationNode(name) |
BindPoint | @aspose/3d | Vincula un AnimationNode a una propiedad de objeto de escena; expone property y channelsCount |
AnimationChannel | @aspose/3d | Amplía KeyframeSequence; contiene un keyframeSequence; accedido a través de bindPoint.getChannel(name) |
KeyFrame | @aspose/3d | Par de fotogramas clave de tiempo/valor único; lleva interpolation: Interpolation |
KeyframeSequence | @aspose/3d | Ordenado keyFrames lista; preBehavior/postBehavior son Extrapolation objetos |
Interpolation | @aspose/3d | Enum: LINEAR, CONSTANT, BEZIER, B_SPLINE, CARDINAL_SPLINE, TCB_SPLINE |
Extrapolation | @aspose/3d | Clase con type: ExtrapolationType y repeatCount: number |
ExtrapolationType | @aspose/3d | Enum: CONSTANT, GRADIENT, CYCLE, CYCLE_RELATIVE, OSCILLATE |
ObjLoadOptions | @aspose/3d/formats/obj | Opciones de importación OBJ: enableMaterials, flipCoordinateSystem, scale, normalizeNormal |
GltfSaveOptions | @aspose/3d/formats/gltf | Opciones de exportación glTF/GLB: binaryMode |
GltfFormat | @aspose/3d/formats/gltf | Instancia de formato para glTF/GLB; pasar a scene.save() |
StlLoadOptions | @aspose/3d/formats/stl | Opciones de importación STL |
StlSaveOptions | @aspose/3d/formats/stl | Opciones de exportación STL: binaryMode |
StlImporter | @aspose/3d/formats/stl | Lector STL de bajo nivel |
StlExporter | @aspose/3d/formats/stl | Escritor STL de bajo nivel |