首页 / Three.js 入门教程 / 其他模型格式

Three.js 入门教程

其他模型格式

本教程共 40 篇 · 第 29 篇 · 更新于 2026-08-14 · 约 8 分钟阅读

Three.jsOBJFBXSTLPLY模型加载MTLLoader

本节目标:学会加载 glTF 之外的常见模型格式——OBJ/MTL、FBX、STL、PLY,搞清楚它们各自返回什么、支持什么,并知道什么场景该选哪种格式。

所有加载器的统一套路

所有模型加载器都是三步:

  1. three/addons/loaders/ 引入对应的 Loader。
  2. loader.load(url, onLoad, onProgress, onError)(或 loadAsync)。
  3. 在回调里处理结果,加入场景。

最大的区别在回调返回什么

  • 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 / .glbgltf 对象Web 首选,游戏资产
OBJ+MTL.obj / .mtlGroupMTL 文件老资源、跨软件交换
FBX.fbxGroup美术制作管线
STL.stlBufferGeometry3D 打印、CAD
PLY.plyBufferGeometry顶点色扫描、点云
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 看报错、本地服务器、灯光、缩放。