如何在 TypeScript 中将 3D 场景导出为 glTF/GLB

如何在 TypeScript 中将 3D 场景导出为 glTF/GLB

Aspose.3D FOSS 支持 glTF 2.0 作为导入和导出格式。相同的 Scene 对象可以从 OBJ、FBX、STL 或其他源文件填充,然后通过在 GltfSaveOptions 上设置一个标志,将其写入 .gltf(JSON + 外部二进制)或 .glb(单一二进制容器)。

分步指南

步骤 1:安装 @aspose/3d

npm install @aspose/3d

确认已激活 Node.js 18 或更高版本:

node --version   # must be >= 16.0.0

步骤 2:导入 Scene、GltfSaveOptions 和 GltfFormat

import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

GltfFormat 是传递给 scene.save() 的格式描述符。GltfSaveOptions 包含所有导出配置。

如果您还加载了源文件(例如 OBJ),请导入相应的加载选项:

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

步骤 3:构建或加载场景

选项 A:从现有文件加载(OBJ → GLB 转换):

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());

选项 B:以编程方式构建最小场景:

import { Scene, Node, Mesh } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const childNode = new Node('cube');
scene.rootNode.addChildNode(childNode);
// Attach geometry to childNode as needed

步骤 4:配置 GltfSaveOptions

GltfSaveOptions 控制输出格式和编码细节。

const saveOpts = new GltfSaveOptions();

// Set to true for a single binary .glb file
// Set to false (default) for JSON .gltf + separate .bin
saveOpts.binaryMode = true;

您可以设置的其他选项:

属性类型默认效果
binaryModebooleanfalsetrue → GLB, false → glTF JSON
flipTexCoordVbooleantrue翻转 UV 垂直轴以兼容引擎

步骤 5:使用 scene.save() 保存

传递输出路径、GltfFormat 描述符和已配置的选项:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
scene.open('model.obj', new ObjLoadOptions());

const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true;   // produce .glb

scene.save('output.glb', GltfFormat.getInstance(), saveOpts);
console.log('Converted to GLB successfully');

改为生成 JSON .gltf 文件:

saveOpts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Exported to glTF JSON successfully');

步骤 6:验证输出文件

检查输出文件是否存在且大小非零:

import * as fs from 'fs';

const outputPath = 'output.glb';
const stats = fs.statSync(outputPath);
console.log(`Output file size: ${stats.size} bytes`);

if (stats.size === 0) {
    throw new Error('Export produced an empty file: check scene content');
}

为了进行往返验证,请重新加载 GLB 并检查节点计数:

import { Scene } from '@aspose/3d';
import { GltfLoadOptions } from '@aspose/3d/formats/gltf';

const verify = new Scene();
verify.open('output.glb', new GltfLoadOptions());

let nodeCount = 0;
function countNodes(node: any): void {
    nodeCount++;
    for (const child of node.childNodes) countNodes(child);
}
countNodes(verify.rootNode);

console.log(`Round-trip verification: ${nodeCount} node(s) in output`);

常见问题及解决方案

导出后未找到 OBJ 材质文件
通过 scene.save('output.obj') 保存为 OBJ 时,.mtl 材质文件会自动与 .obj 文件一起写入。确保输出目录可写,并且两个文件保持在一起。

Output .glb is smaller than expected / meshes are missing
如果加载的场景中有没有实体的节点(例如来自 OBJ 的空组),GLB 将不包含这些节点的几何体。请在保存前使用 mesh.controlPoints.length > 0 确认您的输入文件具有实际的多边形数据。

找不到模块 ‘@aspose/3d/formats/gltf’
确保您使用的是 Node.js 18+,并且 @aspose/3d 已安装在与入口点相同的 node_modules 中。运行 npm ls @aspose/3d 以确认版本为 24.12.0 或更高。

GltfFormat.getInstance() 返回 undefined
这表明主 @aspose/3d 包与缓存的旧版本之间存在版本不匹配。删除 node_modulespackage-lock.json,然后再次运行 npm install

输出的 GLB 中缺少纹理
确保 binaryMode = true 已设置为生成自包含的 GLB。对于 glTF JSON 输出,纹理图像文件必须与输出文件放在同一目录中,因为它们是通过相对路径引用的。

类型错误:参数类型为 ‘GltfSaveOptions’ 不可分配
确保 SceneGltfSaveOptions 都是从同一已安装的包实例导入的。混合安装(全局 + 本地)可能导致接口不匹配。

常见问题 (FAQ)

glTF 与 GLB 有何区别?
glTF 2.0 JSON(.gltf)将场景图存储为可读的 JSON 文件,并使用独立的.bin缓冲区和图像文件。GLB(.glb)将所有内容打包到单个二进制容器中。将binaryMode = true设置为 GLB,将false设置为 JSON glTF。

我可以导出完全在代码中构建的场景(没有源文件)吗? 是的。创建一个 Scene,添加 Node 对象,附加 Mesh 或其他实体,然后调用 scene.save()。该场景不需要来源于已加载的文件。

glTF 导出是无损的吗? 对于几何体和变换,是的。材料在可能的情况下映射到 glTF PBR 材料属性。专有的 FBX 材料扩展可能无法完美往返。

我可以改为导出为 STL 或 3MF 吗? 是的。模式是相同的;导入相应格式的 *SaveOptions*Format.getInstance()

import { StlSaveOptions, StlFormat } from '@aspose/3d/formats/stl';
const opts = new StlSaveOptions();
scene.save('output.stl', StlFormat.getInstance(), opts);

scene.save() 是异步运行吗?
不。scene.save() 是同步的。如果需要在大规模导出时避免阻塞事件循环,请将其包装在工作线程中。

支持哪些 Node.js 版本? Node.js 18、20 和 22+。Node.js 16 及更早版本不受支持。

另请参阅

 中文