Come caricare modelli 3D in TypeScript

Come caricare modelli 3D in TypeScript

Il pacchetto @aspose/3d fornisce alle applicazioni TypeScript e Node.js un’API semplice per aprire file di scene 3D. Scene è l’oggetto radice: chiama scene.open() con un percorso file e opzioni di caricamento specifiche del formato, quindi attraversa scene.rootNode per accedere a geometria, materiali e trasformazioni.

Guida passo-passo

Passo 1: Installa @aspose/3d tramite npm

Aggiungi il pacchetto al tuo progetto. Non sono necessari binari nativi o strumenti di compilazione specifici per la piattaforma; solo Node.js 18 o versioni successive.

npm install @aspose/3d

Per i progetti TypeScript, le definizioni dei tipi sono incluse nel pacchetto:

##tsconfig.json: minimum required settings
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true
  }
}

Passo 2: Importa scena e opzioni specifiche del formato

Ogni formato espone la propria classe loader e l’oggetto delle opzioni in un sotto‑percorso. Importa solo ciò di cui hai bisogno:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';

Per altri formati il modello è identico:

import { GltfLoadOptions } from '@aspose/3d/formats/gltf';
import { FbxLoadOptions } from '@aspose/3d/formats/fbx';
import { StlLoadOptions } from '@aspose/3d/formats/stl';

Passo 3: Apri un file 3D usando scene.open()

Crea un’istanza Scene, quindi chiama scene.open() con il percorso del file e un oggetto opzionale di opzioni di caricamento. La chiamata è sincrona.

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');

Per caricare da un Buffer già in memoria (utile in contesti serverless o di streaming):

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());

Passo 4: Itera sui nodi della scena

Il grafo della scena è un albero radicato in scene.rootNode. Ogni Node può contenere nodi figlio e un opzionale entity (mesh, camera, light, ecc.).

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);

Passo 5: Accedi ai dati dei vertici della mesh tramite controlPoints

Quando l’entità di un nodo è un Mesh, è possibile leggere i punti di controllo grezzi (vertici) dall’array controlPoints. Ogni voce è un Vector4 con componenti x, y, z e w.

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)}`);
        }
    }
}

Passo 6: Configura ObjLoadOptions per il caricamento dei materiali

ObjLoadOptions espone proprietà per controllare come vengono risolti i file di materiale .mtl e le texture associate.

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}`);
    }
}

Problemi comuni e soluzioni

Errore: Impossibile trovare il modulo ‘@aspose/3d/formats/obj’
I sotto‑percorsi dei formati richiedono le esportazioni dei pacchetti di Node.js 12.7+. Assicurati di utilizzare Node.js 18 o successivo. Se usi TypeScript, imposta "moduleResolution": "node16" o "bundler" in tsconfig.json.

scene.rootNode.childNodes è vuoto dopo open()
Alcuni file OBJ usano terminazioni di riga non standard o mancano di una nuova riga finale. Verifica che il file sia un OBJ valido aprendolo in un editor di testo. Inoltre, conferma di aver passato ObjLoadOptions e non un generico LoadOptions: le opzioni specifiche del formato sono necessarie per una corretta gestione.

L’array controlPoints ha lunghezza zero
Il mesh potrebbe essere stato caricato ma non contiene geometria (ad esempio, un gruppo vuoto nell’OBJ). Usa mesh.polygonCount per verificare prima di iterare i vertici.

L’uso della memoria è elevato per file di grandi dimensioni Il caricamento da buffer con scene.openFromBuffer() non riduce il picco di memoria: l’intero file deve essere analizzato. Per file di grandi dimensioni (> 100 MB), assicurati che il tuo processo Node.js disponga di heap sufficiente: node --max-old-space-size=4096 yourScript.js.

Errori di tipo: ’entity’ è di tipo ‘unknown’
La proprietà entity è tipizzata in modo generico. Esegui il cast a any o a una classe specifica (Mesh, Camera, ecc.) a seconda di ciò che ti aspetti nella tua scena.

Domande Frequenti (FAQ)

Quali formati possono essere caricati con scene.open()?
OBJ, glTF 2.0 (.gltf + .bin), GLB, STL, 3MF, FBX e COLLADA (.dae) sono tutti supportati per l’importazione. Passare la classe *LoadOptions corrispondente per ciascun formato.

Posso caricare un file senza specificare le opzioni?
Sì. scene.open('model.glb') funziona senza opzioni per i formati che non richiedono configurazioni speciali. È consigliato passare le opzioni per OBJ perché la risoluzione dei materiali dipende da enableMaterials.

Il caricamento viene eseguito in modo asincrono?
No. scene.open() e scene.openFromBuffer() sono sincroni. Avvolgili in un thread di lavoro o setImmediate se devi mantenere responsivo il ciclo di eventi.

È supportata l’esportazione OBJ?
Sì. L’esportazione OBJ è supportata tramite scene.save('output.obj'). Il file materiale .mtl viene scritto automaticamente accanto al file .obj.

Dove ci si aspetta il file .mtl durante il caricamento di OBJ?
Per impostazione predefinita, il parser cerca il file .mtl referenziato all’interno dell’OBJ (direttiva mtllib) relativo alla directory del file OBJ. Assicurati che entrambi i file siano nella stessa cartella.

Vedi anche

 Italiano