加载 3D 模型
@aspose/3d 在该类上提供了两种加载方式 Scene 类:: open() 用于文件路径加载和 openFromBuffer() 用于内存数据。格式检测会自动根据二进制魔数或文件扩展名进行,因此通常不需要显式指定源格式。.
从文件路径加载
将文件路径字符串传递给 scene.open().。库会根据文件扩展名检测格式,对于二进制格式,则根据魔数字节检测::
import { Scene } from '@aspose/3d';
const scene = new Scene();
scene.open('model.fbx');
console.log(`Root children: ${scene.rootNode.childNodes.length}`);
console.log(`Animation clips: ${scene.animationClips.length}`);open() 替换任何已有的场景内容。如果需要加载多个文件,请创建独立的 Scene 实例。.
加载带材质的 OBJ
OBJ 文件通过伴随的 .mtl 文件引用材质。材质加载是 默认启用的 (ObjLoadOptions.enableMaterials = true)。传递 ObjLoadOptions 以控制此项及其他加载时选项::
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true; // load the .mtl sidecar
options.flipCoordinateSystem = false; // keep original Y-up orientation
options.normalizeNormal = true; // fix degenerate normals
options.scale = 1.0; // unit scale multiplier
scene.open('character.obj', options);
// Inspect materials on the first node
const first = scene.rootNode.childNodes[0];
if (first) {
console.log(`Materials on ${first.name}: ${first.materials.length}`);
}从缓冲区加载
使用 openFromBuffer() 当文件数据已经在内存中时,例如来自 HTTP 获取、数据库 BLOB 或 zip 存档解压。这样可以避免写入磁盘::
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import * as fs from 'fs';
const buffer: Buffer = fs.readFileSync('model.obj');
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.openFromBuffer(buffer, options);
console.log(`Loaded ${scene.rootNode.childNodes.length} root nodes`);对于二进制格式(GLB、STL binary、3MF),库会从缓冲区读取魔数字节以自动检测格式,因此您可以传入 undefined 作为选项参数::
import { Scene } from '@aspose/3d';
import * as fs from 'fs';
const glbBuffer: Buffer = fs.readFileSync('model.glb');
const scene = new Scene();
scene.openFromBuffer(glbBuffer); // format auto-detected from GLB magic bytes
从 HTTP 加载(Node.js 18+)
获取远程资源并在不触及文件系统的情况下加载它::
import { Scene } from '@aspose/3d';
async function loadFromUrl(url: string): Promise<Scene> {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const scene = new Scene();
scene.openFromBuffer(buffer);
return scene;
}
const scene = await loadFromUrl('https://example.com/model.glb');
console.log(`Loaded scene: ${scene.rootNode.childNodes.length} root nodes`);检查已加载的场景
加载完成后,遍历场景图以枚举节点并识别几何体::
import { Scene, Mesh, Node } from '@aspose/3d';
const scene = new Scene();
scene.open('model.fbx');
function inspect(node: Node, depth: number = 0): void {
const indent = ' '.repeat(depth);
const entityType = node.entity ? node.entity.constructor.name : '(none)';
console.log(`${indent}${node.name} [${entityType}]`);
if (node.entity instanceof Mesh) {
const mesh = node.entity as Mesh;
console.log(`${indent} vertices: ${mesh.controlPoints.length}, polygons: ${mesh.polygonCount}`);
}
for (const child of node.childNodes) {
inspect(child, depth + 1);
}
}
inspect(scene.rootNode);读取资源元数据
该 assetInfo 属性公开文件级元数据::
import { Scene } from '@aspose/3d';
const scene = new Scene();
scene.open('model.fbx');
const info = scene.assetInfo;
if (info) {
console.log(`Creator: ${info.creator}`);
console.log(`Unit name: ${info.unitName}`);
console.log(`Unit scale: ${info.unitScaleFactor}`);
}并非所有格式都会填充 assetInfo. FBX 和 COLLADA 拥有丰富的元数据;OBJ 和 STL 通常没有。.
特定格式加载选项参考
| 格式 | 选项类 | 导入路径 | 关键选项 |
|---|---|---|---|
| OBJ | ObjLoadOptions | @aspose/3d/formats/obj | enableMaterials, flipCoordinateSystem, scale, normalizeNormal |
| glTF / GLB | (无需) | N/A | 自动检测;无需选项类 |
| STL | StlLoadOptions | @aspose/3d/formats/stl | (当前版本中没有可配置的选项) |
| FBX | FbxLoadOptions | @aspose/3d/formats/fbx | (当前版本中没有可配置的选项) |
| COLLADA | ColladaLoadOptions | @aspose/3d/formats/collada | (当前版本中没有可配置的选项) |
| 3MF | (无需) | N/A | 自动检测 |
常见加载错误
| 症状 | 原因 | 修复 |
|---|---|---|
Error: Cannot find module '@aspose/3d/formats/obj' | moduleResolution 未设置为 node | 添加 "moduleResolution": "node" 到 tsconfig.json |
| 加载 OBJ 后节点列表为空 | .mtl sidecar 缺失或 enableMaterials 未设置 | 设置 options.enableMaterials = true 并确保 .mtl 位于同一目录中 |
场景已加载但 rootNode.childNodes 为空 | 格式使用单一根网格,而非子节点 | 访问 scene.rootNode.entity 直接 |
openFromBuffer 抛出二进制 STL | 缓冲区切片不正确(缺少尾部字节) | 使用完整的 readFileSync() 输出而不进行切片 |
| FBX 加载后动画剪辑数组为空 | FBX 文件使用烘焙的变换,而非剪辑 | 动画按帧烘焙;剪辑数组将为空 |