Cómo cargar modelos 3D en TypeScript
El paquete @aspose/3d brinda a las aplicaciones TypeScript y Node.js una API sencilla para abrir archivos de escena 3D. Scene es el objeto raíz: llame a scene.open() con una ruta de archivo y opciones de carga específicas del formato, luego recorra scene.rootNode para acceder a la geometría, los materiales y las transformaciones.
Guía paso a paso
Paso 1: Instala @aspose/3d mediante npm
Agrega el paquete a tu proyecto. No se requieren binarios nativos ni herramientas de compilación específicas de la plataforma; solo Node.js 18 o posterior.
npm install @aspose/3dPara proyectos TypeScript, las definiciones de tipo se incluyen en el paquete:
##tsconfig.json: minimum required settings
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true
}
}Paso 2: Importar escena y opciones específicas del formato
Cada formato expone su propia clase de cargador y objeto de opciones bajo una subruta. Importe solo lo que necesite:
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';Para otros formatos, el patrón es idéntico:
import { GltfLoadOptions } from '@aspose/3d/formats/gltf';
import { FbxLoadOptions } from '@aspose/3d/formats/fbx';
import { StlLoadOptions } from '@aspose/3d/formats/stl';Paso 3: Abra un archivo 3D usando scene.open()
Cree una instancia Scene, luego llame a scene.open() con la ruta del archivo y un objeto de opciones de carga opcional. La llamada es sincrónica.
import { Scene } 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);
console.log('Scene loaded successfully');Para cargar desde un Buffer ya en memoria (útil en contextos sin servidor o de transmisión):
import * as fs from 'fs';
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const buffer = fs.readFileSync('model.obj');
const scene = new Scene();
scene.openFromBuffer(buffer, new ObjLoadOptions());Paso 4: Iterar sobre los nodos de la escena
El grafo de escena es un árbol con raíz en scene.rootNode. Cada Node puede contener nodos hijos y un entity opcional (malla, cámara, luz, etc.).
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());
function visitNode(node: any, depth: number = 0): void {
const indent = ' '.repeat(depth);
console.log(`${indent}Node: ${node.name}`);
if (node.entity) {
console.log(`${indent} Entity type: ${node.entity.constructor.name}`);
}
for (const child of node.childNodes) {
visitNode(child, depth + 1);
}
}
visitNode(scene.rootNode);Paso 5: Acceder a los datos de vértices de la malla mediante controlPoints
Cuando la entidad de un nodo es un Mesh, puedes leer los puntos de control sin procesar (vértices) del arreglo controlPoints. Cada entrada es un Vector4 con x, y, z y w componentes.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());
for (const node of scene.rootNode.childNodes) {
if (!node.entity) continue;
const entity = node.entity;
// Check if the entity is a Mesh by duck-typing controlPoints
if ('controlPoints' in entity) {
const mesh = entity as any;
console.log(`Mesh "${node.name}": ${mesh.controlPoints.length} vertices`);
// Print first three vertices
for (let i = 0; i < Math.min(3, mesh.controlPoints.length); i++) {
const v = mesh.controlPoints[i];
console.log(` v[${i}]: x=${v.x.toFixed(4)}, y=${v.y.toFixed(4)}, z=${v.z.toFixed(4)}`);
}
}
}Paso 6: Configurar ObjLoadOptions para la carga de materiales
ObjLoadOptions expone propiedades para controlar cómo se resuelven los archivos de material .mtl y las texturas acompañantes.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const options = new ObjLoadOptions();
options.enableMaterials = true; // parse .mtl file if present
const scene = new Scene();
scene.open('model.obj', options);
// Inspect materials attached to nodes
for (const node of scene.rootNode.childNodes) {
if (node.material) {
console.log(`Material on "${node.name}": ${node.material.constructor.name}`);
}
}Problemas comunes y soluciones
Error: No se puede encontrar el módulo ‘@aspose/3d/formats/obj’
Los sub‑caminos de formato requieren exportaciones de paquetes de Node.js 12.7+. Asegúrate de estar en Node.js 18 o posterior. Si utilizas TypeScript, establece "moduleResolution": "node16" o "bundler" en tsconfig.json.
scene.rootNode.childNodes está vacío después de open()
Algunos archivos OBJ utilizan terminaciones de línea no estándar o carecen de una nueva línea final. Verifique que el archivo sea un OBJ válido abriéndolo en un editor de texto. También confirme que pasó ObjLoadOptions y no un LoadOptions genérico: las opciones específicas del formato son necesarias para una correcta distribución.
controlPoints array tiene longitud cero
Es posible que la malla se haya cargado pero no contenga geometría (p. ej., un grupo vacío en el OBJ). Use mesh.polygonCount para comprobar antes de iterar los vértices.
El uso de memoria es alto para archivos grandes
Load-from-buffer con scene.openFromBuffer() no reduce la memoria máxima: el archivo completo debe ser analizado. Para archivos grandes (> 100 MB), asegúrese de que su proceso Node.js tenga suficiente heap: node --max-old-space-size=4096 yourScript.js.
Errores de tipo: ’entity’ es de tipo ‘unknown’
La propiedad entity está tipada de forma amplia. Conviértela a any o a una clase específica (Mesh, Camera, etc.) según lo que esperes en tu escena.
Preguntas Frecuentes (FAQ)
¿Qué formatos se pueden cargar con scene.open()?
OBJ, glTF 2.0 (.gltf + .bin), GLB, STL, 3MF, FBX y COLLADA (.dae) son compatibles para importación. Pase la clase correspondiente *LoadOptions para cada formato.
¿Puedo cargar un archivo sin especificar opciones?
Sí. scene.open('model.glb') funciona sin opciones para formatos que no requieren configuración especial. Se recomienda pasar opciones para OBJ porque la resolución de materiales depende de enableMaterials.
¿La carga se ejecuta de forma asíncrona?
No. scene.open() y scene.openFromBuffer() son síncronos. Envuélvalos en un hilo de trabajo o setImmediate si necesitas mantener el bucle de eventos receptivo.
¿Se admite la exportación OBJ?
Sí. La exportación OBJ es compatible a través de scene.save('output.obj'). El archivo de material .mtl se escribe automáticamente junto al archivo .obj.
¿Dónde se espera el archivo .mtl al cargar OBJ?
Por defecto, el analizador busca el archivo .mtl referenciado dentro del OBJ (directiva mtllib) relativo al directorio del archivo OBJ. Asegúrese de que ambos archivos estén en la misma carpeta.