如何在 TypeScript 中加载 3D 模型

如何在 TypeScript 中加载 3D 模型

@aspose/3d package 为 TypeScript 和 Node.js 应用程序提供了一个用于打开 3D 场景文件的简洁 API。. Scene 是根对象:调用 scene.open() 使用文件路径和可选的特定格式加载选项,然后遍历 scene.rootNode 以访问几何体、材质和变换。.

分步指南

步骤 1:通过 npm 安装 @aspose/3d

将该包添加到项目中。无需本机二进制文件或平台特定的构建工具;仅需 Node.js 18 或更高版本。.

npm install @aspose/3d

对于 TypeScript 项目,类型定义已随包一起提供::

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

步骤 2:导入 Scene 和特定格式的选项

每种格式在子路径下公开各自的加载器类和选项对象。仅导入所需的部分::

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

其他格式的使用模式相同::

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

步骤 3:使用 scene.open() 打开 3D 文件

创建一个 Scene 实例,然后调用 scene.open() 使用文件路径和可选的 load-options 对象。此调用是同步的。.

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

从一个 Buffer 已在内存中的(在无服务器或流式场景中很有用)::

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

步骤 4:遍历场景节点

场景图是以 scene.rootNode.为根的树。每个 Node 可以包含子节点和可选的 entity (网格、相机、灯光等)。.

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

步骤 5:通过 controlPoints 访问网格顶点数据

当节点的实体是 a Mesh,,您可以从 the 读取原始控制点(顶点) controlPoints 数组。每个条目是 a Vector4 带有 x, y, z,,并且 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)}`);
        }
    }
}

步骤 6:配置 ObjLoadOptions 以加载材质

ObjLoadOptions 公开属性以控制伴随的 .mtl 材质文件和纹理的解析方式。.

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.entity && node.entity.material) {
        console.log(`Material on "${node.name}": ${node.entity.material.constructor.name}`);
    }
}

常见问题及解决方案

错误:找不到模块 ‘@aspose/3d/formats/obj’ 格式子路径需要 Node.js 12.7+ 的包导出。确保您使用的是 Node.js 18 或更高版本。如果使用 TypeScript,请设置 "moduleResolution": "node16""bundler"tsconfig.json.

在调用 open() 后,scene.rootNode.childNodes 为空 某些 OBJ 文件使用非标准的行结束符或缺少结尾换行符。通过在文本编辑器中打开来验证该文件是有效的 OBJ。还请确认您传入了 ObjLoadOptions 而不是通用的 LoadOptions: 特定格式的选项是正确分发所必需的。.

controlPoints 数组的长度为零 网格可能已加载,但不包含几何体(例如,OBJ 中的空组)。使用 mesh.polygonCount 在迭代顶点之前进行检查。.

大文件的内存使用率很高 使用 Load-from-buffer 与 scene.openFromBuffer() 不会降低峰值内存:必须解析整个文件。对于大文件(> 100 MB),请确保您的 Node.js 进程拥有足够的堆内存:: node --max-old-space-size=4096 yourScript.js.

类型错误:’entity’ 的类型为 ‘unknown’entity 属性的类型定义过于宽泛。请强制转换为 any 或到特定的类(Mesh, Camera,,等等)取决于您在场景中期望的内容。.

常见问题 (FAQ)

使用 scene.open() 可以加载哪些格式?? OBJ、glTF 2.0(.gltf + .bin)、GLB、STL、3MF、FBX 和 COLLADA(.dae)均受支持用于导入。传入相应的 *LoadOptions 每种格式的类。.

我可以在不指定选项的情况下加载文件吗?? 是的。. scene.open('model.glb') 对于不需要特殊配置的格式,可以在不提供选项的情况下工作。建议对 OBJ 传入选项,因为材质分辨率取决于 enableMaterials.

加载是异步执行的吗?? 不是。. scene.open()scene.openFromBuffer() 是同步的。将它们包装在工作线程中或 setImmediate 如果您需要保持事件循环的响应性。.

是否支持 OBJ 导出?? 是的。OBJ 导出通过以下方式支持: scene.save('output.obj').。该 .mtl 材质文件会自动写入到与 .obj 文件一起。.

加载 OBJ 时,.mtl 文件预期位于何处?? 默认情况下,解析器会查找 .mtl 在 OBJ 中引用的文件(mtllib 指令)相对于 OBJ 文件所在的目录。确保两个文件位于同一文件夹中。.

另见

 中文