功能与特性
Aspose.3D FOSS for TypeScript 是一个 MIT 许可证的 Node.js 库,用于加载、构建和导出 3D 场景。它随附完整的 TypeScript 类型定义,只有一个运行时依赖(xmldom),并支持六种主流 3D 文件格式。此页面是所有功能区域的主要参考,并为每个功能提供可运行的 TypeScript 代码示例。.
安装与设置
使用单个命令从 npm 安装该包::
npm install @aspose/3d该包面向 CommonJS,且需要 Node.js 18 或更高版本。安装后,请验证你的 tsconfig.json 包含以下编译器选项以实现完全兼容::
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true
}
}导入主 Scene 类(位于)包根目录。特定格式的选项类从各自的子路径导入::
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';功能与特性
格式支持
Aspose.3D FOSS for TypeScript 能读取和写入六种主流 3D 文件格式。加载时会根据二进制魔数自动检测格式,因此无需显式指定源格式。.
| 格式 | 读取 | 写入 | 备注 |
|---|---|---|---|
| OBJ(Wavefront) | 是 | 是 | 读取/写入 .mtl 材质; 使用 ObjLoadOptions.enableMaterials 用于导入 |
| glTF 2.0 | 是 | 是 | JSON 文本格式; PBR 材质 |
| GLB | 是 | 是 | 二进制 glTF; 设置 GltfSaveOptions.binaryMode = true |
| STL | 是 | 是 | 二进制和 ASCII; 完整往返已验证 |
| 3MF | 是 | 是 | 3D Manufacturing Format with color and material metadata |
| FBX | 否* | 否* | 导入/导出器已存在,但未接通格式自动检测 |
| COLLADA (DAE) | 是 | 是 | 单位缩放、几何体、材质和动画剪辑 |
加载带材质的 OBJ::
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
options.flipCoordinateSystem = false;
options.scale = 1.0;
options.normalizeNormal = true;
scene.open('model.obj', options);保存为 GLB(二进制 glTF)::
import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
// ... build or load scene content
const opts = new GltfSaveOptions();
opts.binaryMode = true;
scene.save('output.glb', GltfFormat.getInstance(), opts);场景图
所有 3D 内容都组织为一个树形结构的 Node 对象,以 … 为根 scene.rootNode.。每个节点可以携带一个 Entity (一个 Mesh, Camera, Light,,或其他 SceneObject) Transform 用于相对于其父节点定位。.
关键的场景图类::
Scene::顶层容器;包含rootNode和animationClipsNode: 具有命名树节点的childNodes,entity,transform,,以及materialsEntity: 可附加对象的基类(Mesh,Camera,Light)SceneObject: 被以下共享的基类Node和EntityA3DObject: 具备…的根基类name和属性包Transform: 本地平移、旋转(欧拉和四元数)和缩放
遍历场景图::
import { Scene, Node, Mesh } from '@aspose/3d';
const scene = new Scene();
scene.open('model.obj');
function visit(node: Node, depth: number = 0): void {
const indent = ' '.repeat(depth);
console.log(`${indent}Node: ${node.name}`);
if (node.entity) {
console.log(`${indent} Entity: ${node.entity.constructor.name}`);
}
for (const child of node.childNodes) {
visit(child, depth + 1);
}
}
visit(scene.rootNode);以编程方式创建场景层次结构::
import { Scene, Node } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('chassis');
const wheel = parent.createChildNode('wheel_fl');
wheel.transform.translation.set(0.9, -0.3, 1.4);几何体和网格
Mesh 是主要的几何类型。它扩展 Geometry 并公开控制点(顶点)、多边形索引以及用于法线、UV 和顶点颜色的顶点元素。.
关键几何类::
Mesh: 具有…的多边形网格controlPoints和polygonCountGeometry: 具备顶点元素管理的基类VertexElementNormal: 每顶点或每多边形顶点法线VertexElementUV: 纹理坐标(一个或多个 UV 通道)VertexElementVertexColor: 每顶点颜色数据MappingMode: 控制元素数据如何映射到多边形(CONTROL_POINT,POLYGON_VERTEX,POLYGON,EDGE,ALL_SAME)ReferenceMode: 控制索引策略(DIRECT,INDEX,INDEX_TO_DIRECT)VertexElementType: 标识顶点元素的语义TextureMapping: 纹理通道枚举
从已加载的场景读取网格数据::
import { Scene, Mesh, VertexElementType } from '@aspose/3d';
const scene = new Scene();
scene.open('model.stl');
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
const mesh = node.entity as Mesh;
console.log(`Mesh "${node.name}": ${mesh.controlPoints.length} vertices, ${mesh.polygonCount} polygons`);
const normals = mesh.getElement(VertexElementType.NORMAL);
if (normals) {
console.log(` Normal mapping: ${normals.mappingMode}`);
}
}
}材质系统
Aspose.3D FOSS for TypeScript 支持三种材质类型,覆盖从传统 Phong 着色到基于物理渲染的完整范围::
LambertMaterial: 漫反射颜色和环境光颜色;映射到简单的 OBJ/DAE 材质PhongMaterial: 添加高光颜色、光泽度和自发光;默认的 OBJ 材质类型PbrMaterial: 基于物理的粗糙度/金属度模型;用于 glTF 2.0 的导入和导出
从已加载的 OBJ 场景读取材质::
import { Scene, PhongMaterial, LambertMaterial } 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);
for (const node of scene.rootNode.childNodes) {
for (const mat of node.materials) {
if (mat instanceof PhongMaterial) {
const phong = mat as PhongMaterial;
console.log(` Phong: diffuse=${JSON.stringify(phong.diffuseColor)}, shininess=${phong.shininess}`);
} else if (mat instanceof LambertMaterial) {
console.log(` Lambert: diffuse=${JSON.stringify((mat as LambertMaterial).diffuseColor)}`);
}
}
}在构建 glTF 场景时应用 PBR 材质::
import { Scene, Node, PbrMaterial } from '@aspose/3d';
import { Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const node = scene.rootNode.createChildNode('sphere');
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.8, 0.2, 0.2); // red-tinted albedo; albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.5;
node.material = mat;
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), opts);数学工具
该库随附完整的 3D 数学类型集合,全部具备完整类型定义::
Vector3: 3 分量向量;支持minus(),times(),dot(),cross(),normalize(),length,angleBetween()Vector4: 用于齐次坐标的 4 分量向量Matrix4: 4×4 变换矩阵,带有concatenate(),transpose,decompose,setTRSQuaternion: 带有旋转四元数fromEulerAngle()(静态,单例),eulerAngles()(实例方法),slerp(),normalize()BoundingBox::轴对齐的包围盒,具有minimum,maximum,center,size,mergeFVector3::单精度变体Vector3用于顶点元素数据
从网格顶点计算包围盒::
import { Scene, Mesh, Vector3, BoundingBox } from '@aspose/3d';
const scene = new Scene();
scene.open('model.obj');
let box = new BoundingBox();
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
for (const pt of (node.entity as Mesh).controlPoints) {
box.merge(new Vector3(pt.x, pt.y, pt.z));
}
}
}
console.log('Center:', box.center);
console.log('Extents:', box.size);从欧拉角构建变换::
import { Quaternion, Vector3, Matrix4 } from '@aspose/3d';
const rot = Quaternion.fromEulerAngle(0, Math.PI / 4, 0); // 45° around Y
const mat = new Matrix4();
mat.setTRS(new Vector3(0, 0, 0), rot, new Vector3(1, 1, 1));动画系统
动画 API 对剪辑、节点、通道和关键帧序列进行建模::
AnimationClip::命名的动画节点集合;通过…访问scene.animationClips;;暴露animations: AnimationNode[]AnimationNode::命名的组BindPoints;通过…创建clip.createAnimationNode(name),,通过…访问clip.animationsBindPoint::绑定一个AnimationNode到场景对象的特定属性;暴露property和channelsCountAnimationChannel::扩展KeyframeSequence; 保存一个独立的keyframeSequence; 通过bindPoint.getChannel(name)KeyFrame: 单个时间/值对;携带每帧数据interpolation: InterpolationKeyframeSequence: 有序列表KeyFrame对象通过keyFrames; 具有preBehavior和postBehavior(Extrapolation)Interpolation: 枚举::LINEAR,CONSTANT,BEZIER,B_SPLINE,CARDINAL_SPLINE,TCB_SPLINEExtrapolation: 类,包含type: ExtrapolationType和repeatCount: numberExtrapolationType: 枚举::CONSTANT,GRADIENT,CYCLE,CYCLE_RELATIVE,OSCILLATE
从已加载的场景读取动画数据::
import { Scene, AnimationNode, BindPoint } from '@aspose/3d';
const scene = new Scene();
scene.open('animated.dae'); // COLLADA animation import is supported
for (const clip of scene.animationClips) {
console.log(`Clip: "${clip.name}"`);
for (const animNode of clip.animations) { // clip.animations, not clip.nodes
console.log(` AnimationNode: ${animNode.name}`);
for (const bp of animNode.bindPoints) { // animNode.bindPoints, not animNode.channels
console.log(` BindPoint: property="${bp.property.name}", channels=${bp.channelsCount}`);
}
}
}流式和缓冲区支持
使用 scene.openFromBuffer() 从内存中直接加载 3D 场景 Buffer. 这是针对无服务器函数、流式管道以及在不写入磁盘的情况下处理通过 HTTP 获取的资源的推荐模式。.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import * as fs from 'fs';
// Load file into memory, then parse from buffer
const buffer: Buffer = fs.readFileSync('model.obj');
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.openFromBuffer(buffer, options);
for (const node of scene.rootNode.childNodes) {
if (node.entity) {
console.log(node.name, node.entity.constructor.name);
}
}从缓冲区加载时会根据二进制魔数自动检测格式,因此 GLB、STL binary 和 3MF 文件无需指定 format 参数即可被识别。.
使用示例
示例 1:加载 OBJ 并导出为 GLB
本示例加载带材质的 Wavefront OBJ 文件,然后将场景重新导出为二进制 glTF(GLB)文件,适用于网页和游戏引擎。.
import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
function convertObjToGlb(inputPath: string, outputPath: string): void {
const scene = new Scene();
const loadOpts = new ObjLoadOptions();
loadOpts.enableMaterials = true;
loadOpts.flipCoordinateSystem = false;
loadOpts.normalizeNormal = true;
scene.open(inputPath, loadOpts);
// Report what was loaded
for (const node of scene.rootNode.childNodes) {
if (node.entity) {
console.log(`Loaded: ${node.name} (${node.entity.constructor.name})`);
}
}
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write .glb instead of .gltf + .bin
scene.save(outputPath, GltfFormat.getInstance(), saveOpts);
console.log(`Exported GLB to: ${outputPath}`);
}
convertObjToGlb('input.obj', 'output.glb');示例 2:往返 STL 并进行法线校验
本示例加载二进制 STL 文件,打印每个顶点的法线信息,然后将场景重新导出为 ASCII STL 并验证往返过程。.
import { Scene, Mesh, VertexElementNormal, VertexElementType } from '@aspose/3d';
import { StlLoadOptions, StlSaveOptions } from '@aspose/3d/formats/stl';
const scene = new Scene();
const loadOpts = new StlLoadOptions();
scene.open('model.stl', loadOpts);
let totalPolygons = 0;
for (const node of scene.rootNode.childNodes) {
if (node.entity instanceof Mesh) {
const mesh = node.entity as Mesh;
totalPolygons += mesh.polygonCount;
const normElem = mesh.getElement(VertexElementType.NORMAL) as VertexElementNormal | null;
if (normElem) {
console.log(` Normals: ${normElem.data.length} entries, mapping=${normElem.mappingMode}`);
}
}
}
console.log(`Total polygons: ${totalPolygons}`);
// Re-export as ASCII STL
const saveOpts = new StlSaveOptions();
saveOpts.binaryMode = false; // ASCII output
scene.save('output_ascii.stl', saveOpts);示例 3:以编程方式构建场景并保存为 glTF
此示例从头构建一个带有 PBR 材质的场景,并将其保存为 JSON glTF 文件。.
import { Scene, Mesh, PbrMaterial, Vector4, Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const node = scene.rootNode.createChildNode('floor');
// Build a simple quad mesh (two triangles)
// controlPoints are Vector4 (x, y, z, w) where w=1 for positions
const mesh = new Mesh();
mesh.controlPoints.push(
new Vector4(-1, 0, -1, 1),
new Vector4( 1, 0, -1, 1),
new Vector4( 1, 0, 1, 1),
new Vector4(-1, 0, 1, 1),
);
mesh.createPolygon([0, 1, 2]);
mesh.createPolygon([0, 2, 3]);
node.entity = mesh;
// Apply a PBR material
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.6, 0.6, 0.6); // albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.8;
node.material = mat;
// Save as JSON glTF
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('floor.gltf', GltfFormat.getInstance(), opts);
console.log('Scene written to floor.gltf');技巧与最佳实践
- 使用
ObjLoadOptions.enableMaterials = true每当您需要从 .mtl 文件获取材质数据时。没有它,每个节点上的材质列表将为空。. - 首选
binaryMode = true用于 GLB 在为网页或游戏引擎生成资产时。二进制 GLB 是单个自包含文件,加载速度比 JSON + .bin 分离的方式在浏览器和引擎中更快。. - 使用
openFromBuffer()在无服务器环境中 以避免临时文件 I/O。获取资产,传递Buffer直接,并将输出写入流或其他缓冲区。. - 检查
node.entity在强制转换之前::并非所有节点都携带实体。始终使用一个instanceof在访问之前进行检查Mesh-特定属性,例如controlPoints. - 设置
normalizeNormal = true在ObjLoadOptions当您的源 OBJ 文件来自不受信任的来源时。这可以防止退化的法线传播到下游渲染或验证步骤中。. - 保持
strict: true在 tsconfig.json 中::该库是使用noImplicitAny和strictNullChecks.。禁用strict会掩盖真实的类型错误,削弱类型化 API 的价值。. - 通过…遍历
childNodes,,而不是索引循环::该childNodes属性返回一个可迭代对象;避免依赖数值索引以保持向前兼容性。.
常见问题
| 症状 | 可能原因 | 修复 |
|---|---|---|
| OBJ 加载后材料列表为空 | enableMaterials 未设置 | 设置 options.enableMaterials = true |
| GLB 文件包含独立的 .bin 辅助文件 | binaryMode 默认使用 false | 设置 opts.binaryMode = true |
| STL 输出中缺少顶点法线 | STL ASCII 模式省略每面法线 | 切换到 binaryMode = true 或在导出前计算法线 |
node.entity 始终是 null | 仅遍历 rootNode, 而不是其子项 | 递归进入 node.childNodes |
| TypeScript 错误:属性不存在 | 旧 @types 缓存 | 运行 npm install @aspose/3d 再次;没有单独的 @types 需要包 |
openFromBuffer 抛出格式错误 | 无法从魔数自动检测格式 | 将显式的 format option 类作为第二个参数传入 |
常见问题
该库是否需要任何本机插件或系统软件包?? 没有。Aspose.3D FOSS for TypeScript 只有一个运行时依赖:: xmldom,,它是纯 JavaScript 并由 npm 自动安装。没有 .node 原生插件且无需安装系统软件包。.
支持哪些 Node.js 版本?? Node.js 18、20 和 22 LTS。该库面向 CommonJS 输出,并在内部使用 ES2020 语言特性。.
我可以在浏览器打包(webpack/esbuild)中使用该库吗?? 该库面向 Node.js 并使用 Node.js fs 和 Buffer API。浏览器打包并未正式支持。若在浏览器中使用,请在服务器端加载场景并将结果(例如 GLB)传输给客户端。.
两者之间有什么区别 GltfSaveOptions.binaryMode = true 和 false? binaryMode = false 生成一个 .gltf JSON 文件以及一个单独的 .bin 二进制缓冲区伴随文件。. binaryMode = true 生成一个单一的自包含 .glb 文件。使用 true 用于生产资产交付。.
我可以在不将文件保存到磁盘的情况下,从 HTTP 响应中加载文件吗?? 是的。将响应获取为一个 Buffer (例如,使用 node-fetch 或内置的 fetch 在 Node 18+ 中),然后调用 scene.openFromBuffer(buffer, options).
FBX 支持完整吗?? 不。库中存在 FBX 导入器和导出器类,但 FBX 并未集成到 Scene.open() 或 Scene.save() 自动检测中。调用 scene.open('file.fbx') 不会触发 FBX 导入器;文件将由 STL 回退路径处理。如果需要 FBX I/O,请直接使用特定于 FBX 的导入/导出类。请参阅上面的格式支持表,其中将 FBX 标记为 No*.
该库支持 TypeScript 4.x 吗?? 推荐使用 TypeScript 5.0+。TypeScript 4.7+ 在实践中应该可以工作,但该库是基于并针对 5.0+ 进行测试和编写的。.
API 参考摘要
| 类 | 模块 | 目的 |
|---|---|---|
Scene | @aspose/3d | 顶层场景容器;; open(), openFromBuffer(), save(), rootNode, animationClips |
Node | @aspose/3d | 场景图节点;; childNodes, entity, transform, materials, createChildNode() |
Entity | @aspose/3d | 可附加到场景的对象的基类 |
SceneObject | @aspose/3d | 被…共享的基类 Node 和 Entity |
A3DObject | @aspose/3d | 具有…的根基类 name 以及属性包 |
Transform | @aspose/3d | 局部平移、旋转和缩放 |
Mesh | @aspose/3d | 多边形网格;; controlPoints, polygonCount, createPolygon(),,顶点元素 |
Geometry | @aspose/3d | 几何类型的基类 |
Camera | @aspose/3d | 具有视场角和投影设置的相机实体 |
Light | @aspose/3d | 光源实体(点光源、方向光、聚光灯) |
LambertMaterial | @aspose/3d | 漫反射 + 环境光着色模型 |
PhongMaterial | @aspose/3d | Phong 着色,带有镜面反射和自发光 |
PbrMaterial | @aspose/3d | 基于物理的粗糙度/金属度模型(用于 glTF) |
Vector3 | @aspose/3d | 3-component double-precision vector |
Vector4 | @aspose/3d | 4-component vector for homogeneous math |
Matrix4 | @aspose/3d | 4×4 transformation matrix |
Quaternion | @aspose/3d | 旋转四元数 |
BoundingBox | @aspose/3d | 轴对齐包围盒 |
FVector3 | @aspose/3d | 单精度变体 Vector3 |
VertexElementNormal | @aspose/3d | 每顶点或每多边形顶点法线 |
VertexElementUV | @aspose/3d | 纹理坐标顶点元素 |
VertexElementVertexColor | @aspose/3d | 每顶点颜色顶点元素 |
MappingMode | @aspose/3d | 枚举:: CONTROL_POINT, POLYGON_VERTEX, POLYGON, ALL_SAME |
ReferenceMode | @aspose/3d | 枚举:: DIRECT, INDEX, INDEX_TO_DIRECT |
AnimationClip | @aspose/3d | 命名动画;公开 animations: AnimationNode[];;通过 scene.createAnimationClip(name) |
AnimationNode | @aspose/3d | 已命名的组 BindPoints;通过…创建 clip.createAnimationNode(name) |
BindPoint | @aspose/3d | 绑定一个 AnimationNode 到场景对象属性;公开 property 和 channelsCount |
AnimationChannel | @aspose/3d | 扩展 KeyframeSequence;;包含一个 keyframeSequence;;通过…访问 bindPoint.getChannel(name) |
KeyFrame | @aspose/3d | 单个时间/值关键帧对;携带 interpolation: Interpolation |
KeyframeSequence | @aspose/3d | 有序 keyFrames 列表;; preBehavior/postBehavior 是 Extrapolation 对象 |
Interpolation | @aspose/3d | 枚举:: LINEAR, CONSTANT, BEZIER, B_SPLINE, CARDINAL_SPLINE, TCB_SPLINE |
Extrapolation | @aspose/3d | 类包含 type: ExtrapolationType 和 repeatCount: number |
ExtrapolationType | @aspose/3d | 枚举:: CONSTANT, GRADIENT, CYCLE, CYCLE_RELATIVE, OSCILLATE |
ObjLoadOptions | @aspose/3d/formats/obj | OBJ 导入选项:: enableMaterials, flipCoordinateSystem, scale, normalizeNormal |
GltfSaveOptions | @aspose/3d/formats/gltf | glTF/GLB 导出选项:: binaryMode |
GltfFormat | @aspose/3d/formats/gltf | glTF/GLB 的 Format 实例;传递给 scene.save() |
StlLoadOptions | @aspose/3d/formats/stl | STL 导入选项 |
StlSaveOptions | @aspose/3d/formats/stl | STL 导出选项:: binaryMode |
StlImporter | @aspose/3d/formats/stl | 低级 STL 读取器 |
StlExporter | @aspose/3d/formats/stl | 低级 STL 写入器 |