![]()
18. 模型加载
1. 概述
模型加载是 Three.js 中导入外部 3D 模型的功能。支持多种格式,最常用的是 glTF/GLB 格式,它是 Web 3D 的标准格式。
┌─────────────────────────────────────────────────────────────┐ │ 模型加载体系 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 加载器类型 │ │ ├── GLTFLoader:glTF/GLB 格式(推荐) │ │ ├── OBJLoader:OBJ 格式 │ │ ├── FBXLoader:FBX 格式 │ │ ├── STLLoader:STL 格式 │ │ ├── PLYLoader:PLY 格式 │ │ └── DRACOLoader:DRACO 压缩格式 │ │ │ │ 加载流程 │ │ ├── 创建加载器 │ │ ├── 配置加载器(压缩、路径) │ │ ├── 加载模型 │ │ ├── 处理进度回调 │ │ ├── 成功回调 │ │ └── 错误回调 │ │ │ └─────────────────────────────────────────────────────────────┘
2. GLTF/GLB 加载
2.1 基础加载
import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';constloader=newGLTFLoader();loader.load('model.glb',(gltf)=>{constmodel=gltf.scene;scene.add(model);},(xhr)=>{console.log((xhr.loaded/xhr.total*100)+'% loaded');},(error)=>{console.error('An error happened',error);});
2.2 带 DRACO 压缩的加载
import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import{DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';constloader=newGLTFLoader();constdracoLoader=newDRACOLoader();dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/');loader.setDRACOLoader(dracoLoader);loader.load('compressed-model.glb',(gltf)=>{scene.add(gltf.scene);});
2.3 模型属性配置
loader.load('model.glb',(gltf)=>{constmodel=gltf.scene;// 位置model.position.set(0,0,0);// 缩放model.scale.set(1,1,1);// 旋转model.rotation.y=Math.PI/4;// 阴影model.traverse((node)=>{if(node.isMesh){node.castShadow=true;node.receiveShadow=true;}});scene.add(model);});
3. OBJ 加载
import{OBJLoader}from'three/examples/jsm/loaders/OBJLoader.js';import{MTLLoader}from'three/examples/jsm/loaders/MTLLoader.js';constmtlLoader=newMTLLoader();mtlLoader.load('model.mtl',(materials)=>{materials.preload();constobjLoader=newOBJLoader();objLoader.setMaterials(materials);objLoader.load('model.obj',(object)=>{scene.add(object);});});
4. FBX 加载
import{FBXLoader}from'three/examples/jsm/loaders/FBXLoader.js';constloader=newFBXLoader();loader.load('model.fbx',(object)=>{object.scale.set(0.01,0.01,0.01);scene.add(object);});
5. 完整示例
import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x111122);constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(5,5,8);camera.lookAt(0,0,0);constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);constcontrols=newOrbitControls(camera,renderer.domElement);controls.enableDamping=true;// 光源constambientLight=newTHREE.AmbientLight(0x404040,0.5);scene.add(ambientLight);constdirectionalLight=newTHREE.DirectionalLight(0xffffff,1);directionalLight.position.set(5,10,7);directionalLight.castShadow=true;scene.add(directionalLight);constfillLight=newTHREE.PointLight(0x88aaff,0.3);fillLight.position.set(-2,2,3);scene.add(fillLight);// 辅助对象constaxesHelper=newTHREE.AxesHelper(5);scene.add(axesHelper);constgridHelper=newTHREE.GridHelper(10,20);scene.add(gridHelper);// 地面constplaneGeometry=newTHREE.PlaneGeometry(8,8);constplaneMaterial=newTHREE.MeshStandardMaterial({color:0x336699,side:THREE.DoubleSide});constplane=newTHREE.Mesh(planeGeometry,planeMaterial);plane.rotation.x=-Math.PI/2;plane.position.y=-1;plane.receiveShadow=true;scene.add(plane);// 创建简单模型(立方体组合)constgroup=newTHREE.Group();constbodyGeo=newTHREE.BoxGeometry(1,1.2,0.8);constbodyMat=newTHREE.MeshStandardMaterial({color:0x44aa88,metalness:0.5,roughness:0.3});constbody=newTHREE.Mesh(bodyGeo,bodyMat);body.castShadow=true;body.receiveShadow=true;group.add(body);constheadGeo=newTHREE.SphereGeometry(0.6,32,32);constheadMat=newTHREE.MeshStandardMaterial({color:0x88aaff,metalness:0.2,roughness:0.4});consthead=newTHREE.Mesh(headGeo,headMat);head.position.y=0.9;head.castShadow=true;group.add(head);consteyeGeo=newTHREE.SphereGeometry(0.1,16,16);consteyeMat=newTHREE.MeshStandardMaterial({color:0xffffff});constleftEye=newTHREE.Mesh(eyeGeo,eyeMat);leftEye.position.set(-0.2,1.1,0.55);constrightEye=newTHREE.Mesh(eyeGeo,eyeMat);rightEye.position.set(0.2,1.1,0.55);group.add(leftEye,rightEye);constpupilGeo=newTHREE.SphereGeometry(0.05,16,16);constpupilMat=newTHREE.MeshStandardMaterial({color:0x000000});constleftPupil=newTHREE.Mesh(pupilGeo,pupilMat);leftPupil.position.set(-0.2,1.08,0.65);constrightPupil=newTHREE.Mesh(pupilGeo,pupilMat);rightPupil.position.set(0.2,1.08,0.65);group.add(leftPupil,rightPupil);scene.add(group);// 加载外部模型(示例代码,需要实际文件)// const loader = new GLTFLoader();// loader.load('models/robot.glb', (gltf) => {// const model = gltf.scene;// model.position.set(2, 0, 0);// model.scale.set(0.5, 0.5, 0.5);// scene.add(model);// });// GUI 控制importGUIfrom'lil-gui';constgui=newGUI();constmodelFolder=gui.addFolder('模型控制');modelFolder.add(group.position,'x',-3,3).name('X 位置');modelFolder.add(group.position,'y',-1,2).name('Y 位置');modelFolder.add(group.position,'z',-3,3).name('Z 位置');modelFolder.add(group.rotation,'y',0,Math.PI*2).name('旋转');modelFolder.add(group.scale,'x',0.5,2).name('缩放 X');modelFolder.add(group.scale,'y',0.5,2).name('缩放 Y');modelFolder.add(group.scale,'z',0.5,2).name('缩放 Z');modelFolder.open();// 动画lettime=0;functionanimate(){requestAnimationFrame(animate);time+=0.02;// 眼睛跟随鼠标consteyes=[leftPupil,rightPupil];eyes.forEach(eye=>{eye.position.x=eye.position.x+(Math.sin(time)*0.02);});controls.update();renderer.render(scene,camera);}animate();window.addEventListener('resize',onWindowResize,false);functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}
6. 模型加载器对比
| 加载器 | 格式 | 特点 | 适用场景 |
|---|
| GLTFLoader | glTF/GLB | 标准格式,支持压缩 | 所有场景 |
| OBJLoader | OBJ | 简单通用 | 简单模型 |
| FBXLoader | FBX | 支持动画 | 复杂动画 |
| STLLoader | STL | 3D 打印 | CAD |
| PLYLoader | PLY | 点云数据 | 扫描数据 |
7. 总结
| 加载器 | 用途 |
|---|
| GLTFLoader | glTF/GLB 格式 |
| OBJLoader | OBJ 格式 |
| FBXLoader | FBX 格式 |
| STLLoader | STL 格式 |
| PLYLoader | PLY 格式 |
| DRACOLoader | DRACO 压缩 |
| 加载方法 | 说明 |
|---|
load(url, onLoad, onProgress, onError) | 加载模型 |
setDRACOLoader(dracoLoader) | 设置 DRACO 加载器 |
setPath(path) | 设置基础路径 |
setResourcePath(path) | 设置资源路径 |