Skip to content

附加格式加载器

本文档介绍 Three.js 中除 glTF 外的各种 3D 资源格式加载器。这些加载器支持从传统和专用格式导入模型、场景和点云。关于 glTF 导入/导出(推荐的现代格式),请参阅 GLTF 导入与导出

附加格式加载器位于 examples/jsm/loaders/,支持从支持动画的场景格式(FBX、Collada)到简单网格格式(OBJ、STL)再到点云数据(PCD、PLY、VTK)等多种格式。

格式类别与能力

Three.js 支持跨多个格式类别的加载器,每个类别具有不同的能力:

格式加载器类几何体材质纹理动画灯光/相机说明
FBXFBXLoader完整场景格式,行业标准
Collada (.dae)ColladaLoader基于 XML,Khronos 标准
VRML (.wrl)VRMLLoaderWeb3D 传统格式
OBJOBJLoader通过 MTL通过 MTL简单网格格式
STLSTLLoaderCAD/3D 打印
PLYPLYLoader顶点颜色点云/网格
3MFThreeMFLoader3D 打印标准
AMFAMFLoader3D 打印(XML)
PCDPCDLoader顶点颜色点云数据
VTKVTKLoader顶点颜色科学可视化
NRRDNRRDLoader体数据医学成像体素
XYZXYZLoader简单点云
KMZKMZLoader压缩 Collada

FBXLoader 架构

FBXLoader 是最全面的附加格式加载器,支持带动画、材质、纹理、灯光、相机和骨骼动画的完整场景层次结构。它处理 7.0+ 版本的 ASCII 和二进制 FBX 格式。

FBX 解析管线

FBX 解析管线:load() → parse() → FBXTreeParser

SVG
100%

加载器使用 FileLoader 将原始数据作为 ArrayBuffer 加载,然后用 isFbxFormatBinary()isFbxFormatASCII() 辅助函数确定格式。解析器构建包含所有 FBX 节点的全局 fbxTree 对象,FBXTreeParser 然后通过其解析方法顺序处理。最终输出存储在类型为 Group 的全局 sceneGraph 变量中。

FBX 对象类型与 Three.js 映射

FBX 格式在 fbxTree.Objects.Model 中包含多种对象类型,FBXTreeParser.parseModels() 根据 node.attrType 字段将其转换为 Three.js 对象:

FBX node.attrType → Three.js 对象映射

SVG
100%

FBX 材质系统

fbxTree.Objects.Material 中的 FBX 材质具有 ShadingModel 属性,决定 Three.js 材质类型。parseMaterial() 方法提取材质参数,parseParameters() 方法处理纹理连接:

FBX 材质解析:materialNode.ShadingModel → MeshLambertMaterial/MeshPhongMaterial

SVG
100%

FBX 变形器与骨骼动画

fbxTree.Objects.Deformer 中的 FBX 变形器由 parseDeformers() 处理,返回包含 skeletonsmorphTargets 字典的结构。deformerNode.attrType 决定变形器类型:

FBX 变形器处理:parseDeformers() → bindSkeleton()

SVG
100%

FBX 动画系统

FBX 动画由 AnimationParser.parse() 解析,从 fbxTree.Objects.AnimationCurveNode 和相关节点中的动画数据构建 AnimationClip 对象。解析器使用 parseAnimStack()parseAnimationLayers()parseAnimationCurveNodes() 构建动画层次结构:

FBX 动画管线:AnimationParser.parse() → AnimationClip

SVG
100%

OBJLoader 与 MTLLoader

OBJ 格式是简单的 ASCII 网格格式,存储顶点位置、法线、UV 坐标和面定义。材质在单独的 MTL 文件中定义。

OBJ 解析状态机

OBJLoader.parse() 使用 ParserState 对象累积顶点数据并构建对象。解析器逐行读取,根据行前缀分配到状态方法:

OBJ 逐行解析器:ParserState 方法

SVG
100%

MTLLoader 材质创建

MTLLoader.parse() 逐行读取 MTL,构建 materialsInfo 字典。它返回 MaterialCreator 实例,在调用 create(materialName) 时惰性创建材质:

MTL 解析:MaterialCreator.create() → MeshPhongMaterial

SVG
100%

ColladaLoader 架构

Collada(.dae)是基于 XML 的格式,支持带动画、运动学和物理的完整场景图。ColladaLoader 是最复杂的加载器之一。

Collada 解析管线

ColladaLoader.parse() 使用 DOMParser 解析 XML,然后为每个库部分调用 parseLibrary()buildLibrary() 等辅助函数。结果包括 scene(Group)、animations 数组和 kinematics 对象:

Collada XML 处理:parseLibrary() → buildLibrary() → 结果

SVG
100%

Collada 库系统

Collada 将内容组织到库中,独立解析然后交叉引用:

XML 元素解析函数Three.js 输出
Geometries<library_geometries>parseGeometry()BufferGeometry
Materials<library_materials>parseMaterial()MeshLambertMaterial / MeshPhongMaterial
Effects<library_effects>parseEffect()材质参数
Images<library_images>parseImage()Texture
Animations<library_animations>parseAnimation()AnimationClip
Cameras<library_cameras>parseCamera()PerspectiveCamera / OrthographicCamera
Lights<library_lights>parseLight()DirectionalLight / PointLight / SpotLight
Visual Scenes<library_visual_scenes>parseVisualScene()Group 层次结构

点云加载器

Three.js 为点云数据格式提供多个加载器,每个返回包含位置和可选颜色/法线属性的 BufferGeometryPoints 对象。

点云格式比较

点云加载器都返回包含顶点位置和可选颜色/法线属性的 BufferGeometryPoints 对象:

点云加载器:parse() → Points

SVG
100%

PCD 头部与数据解析

PCDLoader.parse() 首先调用 parseHeader() 提取 PCD 元数据,然后使用 PCDheader.data 确定解析路径。_getDataView() 辅助函数从二进制缓冲区读取类型化数据:

PCD 数据提取:parseHeader() → 解析 ASCII/二进制/压缩

SVG
100%

3D 打印格式加载器

多个加载器面向 3D 打印工作流,具有不同程度的材质支持。

3D 打印格式加载器

三个加载器面向复杂度不同的 3D 打印工作流:

3D 打印格式能力

格式加载器几何体材质纹理输出
STLSTLLoader三角网格BufferGeometry(无材质)
3MF3MFLoader三角网格✓(PBR)带 MeshStandardMaterial 的 Group
AMFAMFLoader三角网格✓(基础)带 MeshPhongMaterial 的 Group

STL 格式STLLoader.parse()isBinary() 检测 ASCII 与二进制,然后调用 parseASCII()parseBinary()。二进制 STL 可能在属性字节计数字段中包含“Magics”颜色数据。

3MF 格式3MFLoader.parse() 使用 JSZip 提取 3D/3dmodel.model XML 文件,解析资源(basematerials、texture2d、objects),并用材质数组构建网格。支持 pbmetallicdisplayproperties 用于 PBR 金属/粗糙度。

AMF 格式AMFLoader.parse() 处理纯 XML 和 ZIP 压缩的 AMF 文件。解析 <object><mesh><vertices><volume><triangle> 结构及可选的 <material> 定义。

3MF 材质与纹理系统

3MFLoader 解析 XML 资源并用 buildBasematerialsMeshStandardSet()buildMaterialsMeshPhong() 构建材质。buildTexture() 方法从 ZIP 归档加载纹理:

3MF 资源处理:XML 资源 → 材质数组

SVG
100%

VRMLLoader 场景图

VRMLLoader 解析 VRML 2.0 文件,使用带节点和字段的层次场景图:

VRML 节点类型

VRMLLoader.parse() 使用 Chevrotain 解析器库将 VRML 2.0 语法词法和解析为 AST(抽象语法树)。parseTree() 函数遍历 AST 并根据 node.name 为每个节点调用 buildNode()

VRML 解析:Chevrotain → AST → buildNode() → 场景

SVG
100%

VTKLoader 科学可视化

VTKLoader 支持用于科学和医学数据可视化的 VTK(Visualization Toolkit)格式。它处理 ASCII 和二进制 POLYDATA:

VTK POLYDATA 结构

VTKLoader.parse() 根据文件内容调用 parseASCII()parseBinary()。解析器使用状态机变量(inPointsSectioninPolygonsSection 等)跟踪正在读取的部分:

VTK 基于部分的解析:parseASCII/parseBinary() → BufferGeometry

SVG
100%

NRRDLoader 医学成像

NRRDLoader 加载常用于医学成像和科学体可视化的 NRRD(Nearly Raw Raster Data)格式文件。与网格加载器不同,它返回包含 3D 体素数据的 Volume 对象而非表面几何体。

NRRD 格式结构

NRRD 文件由文本头部和原始二进制体数据组成。头部指定维度、数据类型、编码和空间变换:

NRRD 头部字段

字段描述示例
type数据类型(uint8、int16、float 等)type: unsigned char
dimension维度数dimension: 3
sizes每维的大小sizes: 256 256 128
encoding数据编码(raw、gzip、bzip2)encoding: gzip
endian字节序(little、big)endian: little
space directions空间变换向量space directions: (1,0,0) (0,1,0) (0,0,1)

NRRD 解析管线

NRRDLoader.parse() 将文件分割为头部和数据部分,用 _fieldFunctions 中的字段特定函数解析头部,然后根据编码类型解码数据:

NRRD 解析:parseHeader() → 解压缩 → Volume 对象

SVG
100%

Volume 对象与坐标系

Volume 类存储 3D 体素数据并提供访问值和提取 2D 切片的方法。它维护两个坐标系:

IJK 坐标系:体数据数组的整数索引(0xLength-1 等)

RAS 坐标系:由 space directions 头部定义的真实世界空间坐标(右-前-上)

volume.matrix 属性从 IJK 变换到 RAS 坐标,volume.extractSlice(axis, index) 返回用于渲染的 VolumeSlice 对象:

// Volume 结构
class Volume {
    xLength: number;        // IJK 中的宽度
    yLength: number;        // IJK 中的高度  
    zLength: number;        // IJK 中的深度
    data: TypedArray;       // 体素值
    spacing: Vector3;       // 物理间距
    matrix: Matrix4;        // IJK 到 RAS 变换
    
    getData(i, j, k): number;
    extractSlice(axis, index): VolumeSlice;
}

VolumeSlice 渲染

VolumeSlice 将体的 2D 横截面表示为带动态生成纹理的 MeshupdateGeometry() 方法在 RAS 空间中定位切片平面,repaint() 提取体素数据到画布纹理:

VolumeSlice 架构:画布纹理 → PlaneGeometry 网格

SVG
100%

NRRD 使用示例

import { NRRDLoader } from 'three/addons/loaders/NRRDLoader.js';

const loader = new NRRDLoader();
const volume = await loader.loadAsync('brain.nrrd');

// 创建穿过体的切片
const sliceZ = volume.extractSlice('z', Math.floor(volume.zLength / 2));
scene.add(sliceZ.mesh);

// 访问体素数据
const value = volume.getData(128, 128, 64); // IJK 坐标
console.log(`体素值在 (128,128,64): ${value}`);

// Volume 属性
console.log(`Volume 维度: ${volume.xLength} x ${volume.yLength} x ${volume.zLength}`);
console.log(`RAS 维度: ${volume.RASDimensions.join(' x ')}`);

通用加载器模式

所有 Three.js 加载器遵循继承自 Loader 基类的通用架构模式:

加载器基类集成

所有加载器扩展 Loader 基类,提供 setPath()setResourcePath()setCrossOrigin()setRequestHeader() 等通用功能。典型模式为:

通用加载器模式:load() → FileLoader → parse()

SVG
100%

坐标系转换

许多格式使用不同的坐标系(Z-up 与 Y-up)。加载器通过变换处理:

格式原生坐标系转换策略
FBXY-up(原生)无需转换
ColladaZ-up 或 Y-up(在 <up_axis> 中指定)如 Z-up 则应用 90° X 旋转
OBJY-up无需转换
VRMLY-up无需转换
STLZ-up(约定)建议手动旋转:object.rotation.set(-Math.PI/2, 0, 0)
3MFZ-up(3D 打印标准)建议手动旋转

材质默认处理

当材质缺失或不支持时,加载器使用默认材质:

// FBXLoader 默认材质
const material = new MeshPhongMaterial({
    name: Loader.DEFAULT_MATERIAL_NAME,
    color: 0xcccccc
});

// OBJLoader 默认材质  
const material = new MeshPhongMaterial();

// STLLoader - 仅几何体,无默认材质
// 应用程序必须提供材质

使用示例

加载带动画的 FBX

import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';

const loader = new FBXLoader();
const fbx = await loader.loadAsync('model.fbx');

scene.add(fbx);

// 访问动画
if (fbx.animations && fbx.animations.length > 0) {
    const mixer = new THREE.AnimationMixer(fbx);
    const action = mixer.clipAction(fbx.animations[0]);
    action.play();
}

加载带 MTL 材质的 OBJ

import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';

// 先加载材质
const mtlLoader = new MTLLoader();
const materials = await mtlLoader.loadAsync('model.mtl');
materials.preload();

// 用材质加载 OBJ
const objLoader = new OBJLoader();
objLoader.setMaterials(materials);
const object = await objLoader.loadAsync('model.obj');
scene.add(object);

加载点云数据

import { PCDLoader } from 'three/addons/loaders/PCDLoader.js';

const loader = new PCDLoader();
const points = await loader.loadAsync('pointcloud.pcd');

// Points 对象包含带位置和颜色的几何体
points.geometry.center();
points.geometry.rotateX(Math.PI); // Z-up 转 Y-up
scene.add(points);

加载器能力与局限性

格式特定局限性

FBXLoader

ColladaLoader

VRMLLoader

STLLoader

VTKLoader

NRRDLoader

性能考量

  • 二进制格式(二进制 FBX、二进制 STL、二进制 PLY)比 ASCII 加载更快
  • 压缩格式(3MF、KMZ、压缩 PCD)需要通过 fflate 进行解压缩开销
  • 大点云(PCD、PLY、XYZ)可创建非常大的几何体 - 考虑 LOD 或剔除
  • 复杂场景(FBX、Collada)含多个对象应使用场景图遍历优化