Skip to content

Three.js - 加载 3D 模型

对于复杂的场景,从零开始用代码创建每个形状是不切实际的。3D 图形的真正强大之处在于导入在专用 3D 建模软件(如 Blender、Maya 或 Cinema 4D)中创建的模型。Three.js 支持多种模型格式,但有一种格式脱颖而出,成为 Web 领域的标准。

glTF (GL Transmission Format) 是 Three.js 团队和更广泛的 Web 3D 社区官方推荐的格式。它常被称为“3D 领域的 JPEG”。

  • 为 Web 优化:它专为 Web 上的高效传输和快速加载而设计。
  • 完整的场景描述:一个 glTF 文件可以在一个包中包含几何体、材质、纹理、动画、骨架(用于绑定角色)等。
  • PBR 材质:它完全支持基于物理的渲染(PBR)材质,这是实现逼真图形的标准。
  • 两种变体:它有两种版本:.gltf(一个 JSON 文件,带外部二进制数据和纹理)和 .glb(一个包含所有内容的单一二进制文件)。通常 .glb 更易于处理。

在 Three.js 中加载任何模型都遵循一致的三步模式:

  1. 导入相应的加载器(Loader):不同格式的加载器不是 Three.js 核心库的一部分,而是作为附加组件在 examples/jsm/loaders/ 目录中提供。
  2. 实例化加载器并调用 .load():.load() 方法接受模型 URL、一个成功回调函数、一个可选的进度回调函数和一个错误回调函数。
  3. 在成功回调中处理结果:加载的数据(例如,模型的场景)会传递给回调函数。然后你将其添加到你的主 Three.js 场景中。

这是一个加载 .glb 文件的现代完整示例。

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// 1. 实例化加载器
const gltfLoader = new GLTFLoader();
// 2. 调用 .load()
gltfLoader.load(
'/models/FlightHelmet/glTF/FlightHelmet.gltf', // 你的模型 URL
(gltf) => { // 成功回调
// 加载的数据是一个 glTF 对象
console.log('Load successful!', gltf);
// gltf.scene 包含了所有网格、灯光等的 THREE.Group
scene.add(gltf.scene);
},
(progress) => { // 进度回调(可选)
console.log('Loading model...', (progress.loaded / progress.total * 100) + '%');
},
(error) => { // 错误回调(可选)
console.error('An error happened', error);
}
);

专业提示:使用 async/await 可以使加载代码更清晰,尤其当你需要加载多个资源时。你可以将加载器的 .loadAsync() 方法 Promise 化。

async function loadModel() {
const gltfLoader = new GLTFLoader();
try {
const gltf = await gltfLoader.loadAsync('/models/myModel.glb');
scene.add(gltf.scene);
} catch (error) {
console.error('模型加载失败:', error);
}
}
loadModel();

Draco 是谷歌开源的用于压缩 3D 几何体的库。它可以显著减小模型的文件大小。glTF 模型可以保存为 Draco 压缩几何体。要加载它,你需要为 GLTFLoader 提供一个 DRACOLoader 实例。

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
// 实例化加载器
const gltfLoader = new GLTFLoader();
// 实例化 Draco 加载器
const dracoLoader = new DRACOLoader();
// 你必须提供 Draco 解码器库的路径。
// 这些文件位于 three/examples/jsm/libs/draco/ 文件夹中。
// 将它们复制到你的 public/draco 目录。
dracoLoader.setDecoderPath('/draco/');
// 告诉 GLTFLoader 使用 DracoLoader 来处理压缩几何体
gltfLoader.setDRACOLoader(dracoLoader);
// 正常加载压缩模型
gltfLoader.load('/models/myCompressedModel.glb', (gltf) => {
scene.add(gltf.scene);
});

虽然 glTF 是首选,但你可能会遇到其他格式。

一种简单的、基于文本的格式,用于定义几何体。它通常与 .mtl 文件一起用于材质。它不支持动画。使用 OBJLoader,如果需要,还可使用 MTLLoader。

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
const mtlLoader = new MTLLoader();
mtlLoader.load('/models/myModel.mtl', (materials) => {
materials.preload();
const objLoader = new OBJLoader();
objLoader.setMaterials(materials);
objLoader.load('/models/myModel.obj', (object) => {
scene.add(object);
});
});

一种在 3D 打印和 CAD 中常见的格式。它只描述表面几何体,没有颜色、材质或纹理的概念。加载后,你必须自己应用材质。

import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
const stlLoader = new STLLoader();
stlLoader.load('/models/my3DPrint.stl', (geometry) => {
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});

如果你的模型未能加载或显示不正确,请遵循以下步骤:

  • 检查控制台:始终检查浏览器的开发者控制台是否有错误。.load() 方法中的错误回调是你的最佳助手。
  • CORS 错误:如果你看到跨域资源共享 (Cross-Origin Resource Sharing, CORS) 错误,这意味着你正在尝试在没有服务器的情况下直接从文件系统加载文件。使用像 Vite 这样的本地开发服务器可以解决这个问题。
  • 验证模型:在其他查看器中打开模型(例如,glTF 模型可使用 https://gltf-viewer.donmccurdy.com/,或使用 Blender)。如果模型在那里也显示损坏,那么问题出在模型文件本身,而不是你的代码。
  • 它不可见! 模型可能太大、太小,或者你的摄像机可能位于模型内部。尝试缩小或放大模型:gltf.scene.scale.set(0.1, 0.1, 0.1);。此外,请确保你的场景中有灯光;许多材质在没有灯光的情况下会显示为黑色。
  • 纹理缺失:检查浏览器的“网络(Network)”标签页。如果你看到纹理文件出现 404 错误,那么模型文件中的路径可能不正确。路径应该是相对于模型文件的(例如,textures/diffuse.png,而不是 C:\Users\...)。

你不必自己创建所有内容!这里有一些很棒的资源:

  • Sketchfab:一个庞大的 3D 模型仓库,许多模型在知识共享(Creative Commons)许可下免费提供。你可以直接下载 glTF 格式的模型。
  • Poly Pizza:一个免费的低多边形模型的好来源,以 .glb 格式提供,非常适合 Web 体验。
  • Blender:免费开源的 3D 创作套件。它是创建自己的模型或将其他格式转换为 glTF 的完美工具。