![]()
38. 模型工具
1. 概述
模型工具用于创建、转换、优化 3D 模型。Blender 是最常用的建模软件,glTF 工具用于模型转换和优化。
┌─────────────────────────────────────────────────────────────┐ │ 模型工具生态 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Blender │ │ ├── 建模:创建和编辑模型 │ │ ├── 材质:纹理和材质设置 │ │ ├── 动画:骨骼和关键帧动画 │ │ ├── UV 展开:纹理坐标 │ │ └── 导出:glTF/GLB 格式 │ │ │ │ glTF 工具 │ │ ├── glTF-Pipeline:模型优化 │ │ ├── glTF-Validator:格式验证 │ │ ├── Draco:网格压缩 │ │ └── Basis:纹理压缩 │ │ │ └─────────────────────────────────────────────────────────────┘
2. Blender 基础
2.1 安装和配置
- 下载 Blender:https://www.blender.org/
- 安装 glTF 导出插件(内置)
2.2 模型导出设置
导出设置: - 格式:glTF 2.0 (.glb / .gltf) - 包含:几何体、材质、动画、变形 - 压缩:启用 Draco 压缩 - 纹理:嵌入或分离
2.3 模型优化建议
优化要点: 1. 减少多边形数量 2. 合并材质 3. 使用纹理图集 4. 烘焙光照贴图 5. 使用 LOD(细节层次)
3. glTF 工具
3.1 glTF-Pipeline
npminstall-ggltf-pipeline# 转换 glTF 到 glbgltf-pipeline-imodel.gltf-omodel.glb# 压缩纹理gltf-pipeline-imodel.glb-omodel-compressed.glb--compressTextures# 应用 Draco 压缩gltf-pipeline-imodel.glb-omodel-draco.glb--draco.compressionLevel10
3.2 glTF-Validator
npminstall-ggltf-validator# 验证模型gltf-validator model.glb# 详细输出gltf-validator model.glb--verbose
3.3 Draco 压缩
// Three.js 中使用 Dracoimport{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);});
3.4 Basis 纹理压缩
import{BasisTextureLoader}from'three/examples/jsm/loaders/BasisTextureLoader.js';constbasisLoader=newBasisTextureLoader();basisLoader.setTranscoderPath('three/examples/jsm/libs/basis/');basisLoader.load('texture.basis',(texture)=>{constmaterial=newTHREE.MeshStandardMaterial({map:texture});});
4. 模型优化工作流
4.1 减面优化
// 使用 SimplifyModifier 减面import{SimplifyModifier}from'three/examples/jsm/modifiers/SimplifyModifier.js';constmodifier=newSimplifyModifier();constsimplifiedGeometry=modifier.modify(originalGeometry,Math.floor(originalGeometry.attributes.position.count/2));
4.2 LOD 生成
import{LOD}from'three';constlod=newLOD();// 添加不同细节级别lod.addLevel(highDetailMesh,0);// 近距离lod.addLevel(mediumDetailMesh,20);// 中距离lod.addLevel(lowDetailMesh,50);// 远距离scene.add(lod);
5. 完整示例
import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import{DRACOLoader}from'three/examples/jsm/loaders/DRACOLoader.js';importGUIfrom'lil-gui';constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x111122);constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(5,4,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);// 辅助对象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);// 创建简单模型(Blender 导出的模型示例)constgroup=newTHREE.Group();// 身体constbodyGeo=newTHREE.BoxGeometry(0.8,1,0.6);constbodyMat=newTHREE.MeshStandardMaterial({color:0x44aa88,metalness:0.5,roughness:0.3});constbody=newTHREE.Mesh(bodyGeo,bodyMat);body.castShadow=true;group.add(body);// 头部constheadGeo=newTHREE.SphereGeometry(0.5,32,32);constheadMat=newTHREE.MeshStandardMaterial({color:0x88aaff,metalness:0.2,roughness:0.4});consthead=newTHREE.Mesh(headGeo,headMat);head.position.y=0.7;head.castShadow=true;group.add(head);// 眼睛consteyeGeo=newTHREE.SphereGeometry(0.08,16,16);consteyeMat=newTHREE.MeshStandardMaterial({color:0xffffff});constleftEye=newTHREE.Mesh(eyeGeo,eyeMat);leftEye.position.set(-0.2,0.85,0.55);constrightEye=newTHREE.Mesh(eyeGeo,eyeMat);rightEye.position.set(0.2,0.85,0.55);group.add(leftEye,rightEye);// 手臂constarmGeo=newTHREE.BoxGeometry(0.3,0.7,0.3);constarmMat=newTHREE.MeshStandardMaterial({color:0x44aa88});constleftArm=newTHREE.Mesh(armGeo,armMat);leftArm.position.set(-0.6,0.2,0);constrightArm=newTHREE.Mesh(armGeo,armMat);rightArm.position.set(0.6,0.2,0);group.add(leftArm,rightArm);group.position.set(0,0,0);group.castShadow=true;scene.add(group);// LOD 示例constlod=newTHREE.LOD();// 高精度模型consthighDetail=group.clone();highDetail.position.set(-2,0,0);// 中精度模型constmediumDetail=newTHREE.Mesh(newTHREE.BoxGeometry(0.8,1.2,0.8),newTHREE.MeshStandardMaterial({color:0x88aaff}));mediumDetail.position.set(-2,0,0);// 低精度模型constlowDetail=newTHREE.Mesh(newTHREE.SphereGeometry(0.6,8,8),newTHREE.MeshStandardMaterial({color:0x88aaff}));lowDetail.position.set(-2,0,0);lod.addLevel(highDetail,0);lod.addLevel(mediumDetail,3);lod.addLevel(lowDetail,6);scene.add(lod);// 加载外部模型(示例代码,需要实际文件)// const loader = new GLTFLoader();// const dracoLoader = new DRACOLoader();// dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/');// loader.setDRACOLoader(dracoLoader);//// loader.load('models/character.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 控制constgui=newGUI();constmodelFolder=gui.addFolder('模型控制');modelFolder.add(group.position,'x',-2,2).name('模型 X');modelFolder.add(group.position,'y',-1,2).name('模型 Y');modelFolder.add(group.rotation,'y',0,Math.PI*2).name('旋转');modelFolder.add(group.scale,'x',0.5,1.5).name('缩放 X');modelFolder.add(group.scale,'y',0.5,1.5).name('缩放 Y');modelFolder.add(group.scale,'z',0.5,1.5).name('缩放 Z');modelFolder.open();constlodFolder=gui.addFolder('LOD 控制');letlodDistance=0;lodFolder.add({distance:0},'distance',0,10).name('相机距离').onChange(val=>{lodDistance=val;constdist=Math.abs(lodDistance);if(dist<3)lod.levels[0].visible=true;elselod.levels[0].visible=false;if(dist>=3&&dist<6)lod.levels[1].visible=true;elselod.levels[1].visible=false;if(dist>=6)lod.levels[2].visible=true;elselod.levels[2].visible=false;});lodFolder.open();// 动画lettime=0;functionanimate(){requestAnimationFrame(animate);time+=0.01;// 手臂摆动leftArm.rotation.z=Math.sin(time)*0.5;rightArm.rotation.z=-Math.sin(time)*0.5;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. 模型工具对比
| 工具 | 用途 | 特点 |
|---|
| Blender | 建模/动画 | 免费强大 |
| glTF-Pipeline | 优化 | 命令行 |
| Draco | 压缩 | 高效 |
| Basis | 纹理压缩 | 高质量 |
| glTF-Validator | 验证 | 格式检查 |
7. 总结
| 工具/技术 | 用途 |
|---|
| Blender | 模型创建 |
| glTF-Pipeline | 模型优化 |
| Draco | 网格压缩 |
| Basis | 纹理压缩 |
| LOD | 细节层次 |
| SimplifyModifier | 减面 |