如何将GLTFLoader加载的对象合并为单个Mesh?
解决GLTF模型合并为单个Mesh及控制台重复输出问题
一、先搞定控制台重复打印的问题
你现在用traverse遍历整个模型场景,会把模型里的所有子对象(包括空节点、骨骼、网格、甚至材质相关的对象)都扫一遍,所以才会输出上百条重复内容。如果只是想获取整个模型的尺寸,根本不用遍历每个子对象,直接给整个gltf.scene计算包围盒就行:
var loader = new THREE.GLTFLoader(); loader.load( `objekt.gltf`, ( gltf ) => { this.scene.add( gltf.scene ); // 直接计算整个模型的包围盒,无需遍历 const box = new THREE.Box3().setFromObject( gltf.scene ); console.log('模型整体尺寸:', box.getSize(new THREE.Vector3())); });
二、把多个Mesh合并成单个Mesh
要合并GLTF里的多个Mesh,得先看模型的材质情况,还有是不是带骨骼动画(这里先假设是静态模型,带动画的话合并会影响骨骼绑定,后续可以单独处理)。
情况1:模型所有Mesh用同一种材质
这种情况最简单,直接合并几何体就行:
var loader = new THREE.GLTFLoader(); loader.load( `objekt.gltf`, ( gltf ) => { const mergedGeometry = new THREE.BufferGeometry(); let singleMaterial = null; gltf.scene.traverse( (object) => { if (object.isMesh) { // 先把几何体转成BufferGeometry,确保格式统一 object.geometry = object.geometry.toBufferGeometry(); // 记录第一个Mesh的材质作为合并后的材质 if (!singleMaterial) { singleMaterial = object.material; } // 把Mesh的世界矩阵应用到几何体上,保证位置缩放正确 object.geometry.applyMatrix4(object.matrixWorld); mergedGeometry.merge(object.geometry); } }); // 创建合并后的单个Mesh const mergedMesh = new THREE.Mesh(mergedGeometry, singleMaterial); this.scene.add(mergedMesh); // 移除原来的模型,避免场景里有重复对象 gltf.scene.removeFromParent(); // 现在计算合并后模型的尺寸 const box = new THREE.Box3().setFromObject(mergedMesh); console.log('合并后模型尺寸:', box.getSize(new THREE.Vector3())); });
情况2:模型有多种材质
如果模型用了多种材质,你可以用Three.js的BufferGeometryUtils工具来合并,同时保留材质索引,这样合并后的Mesh依然能显示多种材质:
// 先引入工具类(如果是CDN引入Three.js,记得单独引入这个文件) import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; var loader = new THREE.GLTFLoader(); loader.load( `objekt.gltf`, ( gltf ) => { const geometries = []; const materialIndices = []; const materials = []; gltf.scene.traverse( (object) => { if (object.isMesh) { object.geometry = object.geometry.toBufferGeometry(); object.geometry.applyMatrix4(object.matrixWorld); geometries.push(object.geometry); // 记录材质的索引,避免重复添加材质 let matIndex = materials.indexOf(object.material); if (matIndex === -1) { matIndex = materials.length; materials.push(object.material); } materialIndices.push(matIndex); } }); // 合并几何体并保留材质索引 const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, false); // 添加材质索引属性,让Mesh知道每个面用哪种材质 mergedGeometry.setAttribute('materialIndex', new THREE.Uint16BufferAttribute(materialIndices, 1)); // 创建支持多材质的Mesh const mergedMesh = new THREE.Mesh(mergedGeometry, materials); this.scene.add(mergedMesh); gltf.scene.removeFromParent(); });
三、拖拽时独立移动的问题解决
合并成单个Mesh后,你直接拖拽这个mergedMesh就可以让整个模型一起移动了——因为它已经是一个独立的对象,不会再出现子对象各自乱跑的情况。如果之前用了DragControls这类拖拽工具,记得把拖拽目标换成合并后的mergedMesh,而不是原来的gltf.scene。
内容的提问来源于stack exchange,提问作者Krizs
相关产品推荐
相关产品推荐

