其他模型格式
本教程共 40 篇 · 第 29 篇 · 更新于 2026-08-14 · 约 8 分钟阅读
本节目标:学会加载 glTF 之外的常见模型格式——OBJ/MTL、FBX、STL、PLY,搞清楚它们各自返回什么、支持什么,并知道什么场景该选哪种格式。
所有加载器的统一套路
所有模型加载器都是三步:
- 从
three/addons/loaders/引入对应的 Loader。 - 调
loader.load(url, onLoad, onProgress, onError)(或loadAsync)。 - 在回调里处理结果,加入场景。
最大的区别在回调返回什么:
- OBJ、FBX 返回
Group(一组网格,直接加入场景)。 - STL、PLY 返回
BufferGeometry(只有几何,要自己建材质和网格)。
先记住这一点,后面每个格式就好理解了。
load 的四个参数里,onProgress 和 onError 可以省略,但调试期建议都写上——错误信息是排查的第一线索(第 31 章会讲统一的进度与错误管理)。
loadAsync 同样适用于这些加载器,返回 Promise,配合 async/await 写起来更顺。
OBJ + MTL:最老牌的文本格式
OBJ 是纯文本格式,只存几何信息:顶点、法线、UV、面。不支持动画。默认材质是白色 MeshPhongMaterial——所以场景里必须加灯光,否则模型黑漆漆一片。
材质放在配套的 MTL 文件里,需要 MTLLoader 先加载:
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';
const mtlLoader = new MTLLoader();
mtlLoader.load('model.mtl', (materials) => {
materials.preload(); // 加载 MTL 里引用的贴图
const objLoader = new OBJLoader();
objLoader.setMaterials(materials); // 把材质交给 OBJLoader
objLoader.load('model.obj', (group) => {
scene.add(group);
});
});
OBJ 文件里可能没有法线,加载后表面会出现奇怪的块状明暗。遇到这种情况,对几何体补算法线即可:
group.traverse((obj) => {
if (obj.isMesh) obj.geometry.computeVertexNormals();
});
FBX:动画能力强,体积大
FBX 是 Autodesk 的专有格式,动画、骨骼支持很完善,很多游戏美术管线用它。缺点是规范不公开、文件巨大。
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
const loader = new FBXLoader();
loader.load('model.fbx', (group) => {
scene.add(group);
// 动画剪辑在 group.animations 里,配 AnimationMixer 播放(第 26 章)
const mixer = new THREE.AnimationMixer(group);
mixer.clipAction(group.animations[0]).play();
});
FBX 是”中间格式”:美术制作、交换用 FBX,上线前在 Blender 里转成 glTF 再进 Web,体积和加载速度都更好。
FBX 文件可能同时带多个动画剪辑(行走、待机、攻击各一段),遍历 group.animations 数组逐个取名,再用第 26 章的 AnimationClip.findByName 按名字取用。FBX 的另一个坑是单位:很多美术工具默认导出厘米,进 three.js 记得检查缩放。
STL:3D 打印的通用语言
STL 只描述物体表面的三角形,没有颜色、纹理、材质、动画。它是 3D 打印、快速成型的标准格式,也是很多 CAD 软件的输出格式。
import { STLLoader } from 'three/addons/loaders/STLLoader.js';
const loader = new STLLoader();
loader.load('model.stl', (geometry) => {
const mesh = new THREE.Mesh(
geometry,
new THREE.MeshStandardMaterial({ color: 0x88aacc })
);
scene.add(mesh);
});
注意回调直接拿到的是几何体,材质得自己给。STL 适合展示工程零件、打印预览,不适合做游戏资产。
STL 分二进制和 ASCII 两种写法,STLLoader 都能读,优先二进制(体积小很多)。有些 STL 没有法线,显示异常时同样补 computeVertexNormals()。
PLY:点云与顶点色
PLY 既能存三角网格,也能存点云,而且支持顶点颜色——扫描模型常用。PLYLoader 返回 BufferGeometry,顶点色在 geometry.attributes.color 里,可以直接配 MeshBasicMaterial({ vertexColors: true }) 显示。
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js';
const loader = new PLYLoader();
loader.load('scan.ply', (geometry) => {
const mesh = new THREE.Mesh(
geometry,
new THREE.MeshBasicMaterial({ vertexColors: true })
);
scene.add(mesh);
});
PLY 点云不一定要建成网格:用 Points 渲染每个顶点,配合 PointsMaterial,扫描数据直接显示:
const points = new THREE.Points(
geometry,
new THREE.PointsMaterial({ size: 0.02, vertexColors: true })
);
scene.add(points);
格式对比
| 格式 | 扩展名 | 回调返回 | 动画 | 材质/纹理 | 典型用途 |
|---|---|---|---|---|---|
| glTF | .gltf / .glb | gltf 对象 | ✅ | ✅ | Web 首选,游戏资产 |
| OBJ+MTL | .obj / .mtl | Group | ❌ | MTL 文件 | 老资源、跨软件交换 |
| FBX | .fbx | Group | ✅ | ✅ | 美术制作管线 |
| STL | .stl | BufferGeometry | ❌ | ❌ | 3D 打印、CAD |
| PLY | .ply | BufferGeometry | ❌ | 顶点色 | 扫描、点云 |
Tip需要动画、材质完整的角色模型,选 glTF。只有几何、要自己上色的工程数据,选 STL/PLY。拿到什么用什么,但新项目一律优先 glTF。
一句话决策:要动画选 glTF 或 FBX,要打印选 STL,要扫描点云选 PLY,只有老资产才用 OBJ。混合场景就混着用:loader 之间互不影响,同一个场景里可以同时有 glTF 角色和 STL 零件。
可运行示例:OBJ + MTL 双文件加载
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>29. OBJ + MTL 模型加载</title>
<style>
* { margin: 0; padding: 0; }
body { overflow: hidden; background: #1a1a2e; }
canvas { display: block; }
#info {
position: fixed; left: 12px; top: 12px;
color: #fff; font: 14px/1.6 sans-serif;
background: rgba(0, 0, 0, 0.45); padding: 8px 12px; border-radius: 6px;
}
</style>
</head>
<body>
<div id="info">male02.obj + male02.mtl · OBJLoader + MTLLoader</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
scene.add(new THREE.AmbientLight(0xffffff, 1));
const dirLight = new THREE.DirectionalLight(0xffffff, 2);
dirLight.position.set(2, 4, 3);
scene.add(dirLight);
const camera = new THREE.PerspectiveCamera(50, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0.8, 2.5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.append(renderer.domElement);
new OrbitControls(camera, renderer.domElement);
const BASE = 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r185/examples/models/obj/male02/';
// 1. 先加载 MTL 材质
const mtlLoader = new MTLLoader();
mtlLoader.setPath(BASE);
mtlLoader.load('male02.mtl', (materials) => {
materials.preload();
// 2. 再加载 OBJ 几何,套上材质
const objLoader = new OBJLoader();
objLoader.setPath(BASE);
objLoader.setMaterials(materials);
objLoader.load('male02.obj', (group) => {
group.rotation.y = Math.PI; // 模型默认背对相机,转个身
scene.add(group);
});
});
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
Note
setPath(BASE)让 loader 以 BASE 为基准拼接 URL,两个文件都在同一目录时省去重复写路径。OBJ 模型面数多、格式老,尽量只用于遗留资源。
部署时注意:OBJ 和 MTL 是两个文件,必须放在同一目录一起部署;只传 OBJ 不传 MTL,模型就只剩默认的白色材质,场景里没光的话还会全黑。
格式转换:别让格式限制你
拿到什么格式不由你决定,但最后用什么可以。Blender 免费开源,能导入导出几乎所有格式:OBJ、FBX、STL、PLY、glTF 全支持。美术给 FBX,自己在 Blender 里转成 glTF 再上线,是 Web 3D 项目的常规流程。
转换时注意两点。坐标轴:FBX 常用 Y 轴向上(three.js 也是),但有些软件导出的模型是 Z 向上,进 three.js 会”躺倒”,转个 90 度即可。单位:厘米还是米,直接决定模型大小,很多”模型不见了”的案子都栽在这。转换完先转 90 度、缩放 100 倍试试,是多年攒下的老经验。
另外,DRACOLoader 也可以单独加载 .drc 格式的压缩几何文件:new DRACOLoader().load(url, (geometry) => ...),配合 setDecoderPath 使用,用法和本章其他加载器一致。
大模型文件加载时,load 的 onProgress 回调能拿到下载进度(event.loaded / event.total),配合第 31 章的 LoadingManager 做进度条,体验会好很多。
还有哪些加载器
three.js 的 addons 里还有几十个加载器:ColladaLoader(.dae,老格式)、PDBLoader(分子结构)、USDZLoader(苹果 AR 格式)、DRACOLoader(.drc 压缩几何)、KTX2Loader(压缩纹理)等。用法都是同一套路,遇到新格式查文档即可。
加载失败的排查和第 28 章一样:onError 看报错、本地服务器、灯光、缩放。