// const util = require('@/static/utils/util.js'); // const config = require('@/static/config.js'); import wallType from '@/static/wallData.js'; // import requestConfig from '@/services/requestConfig.js'; import * as THREE from 'three'; import TWEEN from 'three/addons/libs/tween.module.js'; export default { data() { return { // gltfUrl:"https://dm.static.elab-plus.com/3d/model/230519/floor01.glb",//模型地址 // gltfName:"地板", //模型名称 // gltfWidth:10, //模型宽度 10米 // gltfHeight:10, //模型高度 10米 } }, watch: {}, methods: { // 加载所有墙体模型 // modelItem 变化后的 // wallObj 变化前的 drawModelOld(modelItem, spaceObj, wallObj, isAnimate=false){ let cube = wallObj.obj; let that = this; // console.log("模型参数", wallPositionX, wallPositionY, wallScaleX, wallScaleY, lastWallPosition, wallDirection) console.log("墙体动画", modelItem, spaceObj, wallObj, isAnimate,spaceObj.rightCenter); if(!wallObj.obj){//新的逻辑 //无变化则不需要启动动画 if(modelItem.wallPositionX == wallObj.wallPositionX && modelItem.wallPositionY == wallObj.wallPositionY && modelItem.wallScaleX == wallObj.wallScaleX && modelItem.wallScaleY == wallObj.wallScaleY){ return false; } wallObj.instancedMeshIndexList.forEach(item=>{ let _index = item.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵 let endMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(item.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 let position = new THREE.Vector3();//当前几何体的位置参数 let position1 = new THREE.Vector3();//计算后的位移参数 let scale = new THREE.Vector3();//当前几何体的位置参数 let scale1 = new THREE.Vector3();//计算后的形变参数 let quaternion = new THREE.Quaternion();//四元数 stratMatrix.decompose(position,quaternion,scale);//从当前几何体提取相关参数 // 计算变化后的位置:位移后的位置 是 当前几何体的位置参数 加上 模型移动后的位置偏移量 let x = position.x + modelItem.wallPositionX - wallObj.wallPositionX; let z = position.z + modelItem.wallPositionY - wallObj.wallPositionY; // 计算变化后的缩放:缩放后的值 是 当前几何体的缩放比例 同步 模型缩放后缩放比例 let scalex = scale.x * (modelItem.wallScaleX/ wallObj.wallScaleX); let scaley = scale.z * (modelItem.wallScaleY/ wallObj.wallScaleY); //x轴放大,则需要移动多一倍的距离 if(modelItem.wallScaleX!=wallObj.wallScaleX){ if(modelItem.wallRotateY>0){//说明旋转了 let _ch = modelItem.wallPositionY - wallObj.wallPositionY; if(spaceObj.rightCenter){//即形变几何体是右侧不变,由于中心点在左侧,所以要再加一倍变化的值 z = z + _ch; }else{//形变几何体是左侧不变,由于中心点在左侧,所以要减去变化的值 z = z - _ch; } // z = z + modelItem.wallPositionY - wallObj.wallPositionY }else{ let _ch = modelItem.wallPositionX - wallObj.wallPositionX; if(spaceObj.rightCenter){ x = x + _ch; }else{ x = x - _ch; } } } //Y轴缩小(这里理解是Z轴,映射原因),则需要移动多一倍的距离 //因为几何体的操作原点是左边中心点,不是几何中心点 所以计算的时候需要在多移动一倍 if(modelItem.wallScaleY!=wallObj.wallScaleY){ if(modelItem.wallRotateY>0){//说明旋转了 let _ch = modelItem.wallPositionX - wallObj.wallPositionX; if(spaceObj.rightCenter){ x = x + _ch; }else{ x = x - _ch; } // x = x + modelItem.wallPositionX - wallObj.wallPositionX; }else{ let _ch = modelItem.wallPositionY - wallObj.wallPositionY; if(spaceObj.rightCenter){ z = z + _ch; }else{ z = z - _ch; } // z = z + modelItem.wallPositionY - wallObj.wallPositionY } } position1.set(x, position.y, z); scale1.set(scalex,scale.y,scaley); //获取最终的几何体四维变化矩阵 endMatrix = endMatrix.compose(position1,quaternion,scale1); // console.warn("***drawModel-isAnimate0***",JSON.stringify(position),JSON.stringify(scale),wallObj.name,modelItem,wallObj); // console.warn(JSON.stringify(stratMatrix.elements),JSON.stringify(endMatrix.elements)); // instancedMesh.instanceMatrix.needsUpdate = true; // instancedMesh.setMatrixAt(item.instancedAtIndex,endMatrix);//更新几何体的世界矩阵 var tween = new TWEEN.Tween(stratMatrix.elements) .to(endMatrix.elements, 2000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate((matrixWorld)=> { let m4 = new THREE.Matrix4();//定义一个四维矩阵 m4.set(...matrixWorld);//注意:四维矩阵的显示和实际计算的行列优先规则不同 instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关 instancedMesh.setMatrixAt(item.instancedAtIndex,m4.transpose());//更新几何体的世界矩阵 }).onComplete(()=>{ instancedMesh.setMatrixAt(item.instancedAtIndex,endMatrix);//更新几何体的世界矩阵 this.tweenCameraAnmaChange(false) }); // 开始动画 tween.start(); this.tweenCameraAnmaChange(true) }) //更新模型的最新位置,确保计算结果正确 setTimeout(()=>{ let gltfWall = that.gltfWalls.find(gltfWall=>gltfWall.uniId==wallObj.uniId);//判断是否已经添加过 gltfWall.wallPositionX = modelItem.wallPositionX; gltfWall.wallPositionY = modelItem.wallPositionY; gltfWall.wallScaleX = modelItem.wallScaleX; gltfWall.wallScaleY = modelItem.wallScaleY; gltfWall.wallRotateY = modelItem.wallRotateY; }, 2000); }else{ console.warn("***drawModel-isAnimate-2***",JSON.stringify(cube.position),JSON.stringify(cube.scale),modelItem); var tween = new TWEEN.Tween({ x: cube.position.x, z: cube.position.z, sx:cube.scale.x, sz:cube.scale.z }) .to({ x: modelItem.wallPositionX, z: modelItem.wallPositionY, sx:modelItem.wallScaleX }, 2000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate((object)=> { cube.position.x = object.x; cube.position.z = object.z; cube.scale.x = object.sx; cube.scale.z = object.sz; }).onComplete(()=>{ this.tweenCameraAnmaChange(false) }); // 开始动画 tween.start(); this.tweenCameraAnmaChange(true) } }, // modelItem 变化后的 // wallObj 变化前的-一面墙下的某一段墙体 drawModel(modelItem, spaceObj, wallObj, isAnimate=false){ let that = this; //无变化则不需要启动动画 if(modelItem.wallPositionX == wallObj.wallPositionX && modelItem.wallPositionY == wallObj.wallPositionY && modelItem.wallScaleX == wallObj.wallScaleX && modelItem.wallScaleY == wallObj.wallScaleY){ return false; } let tx = wallObj.wallPositionX; let tz = wallObj.wallPositionY; let scaleX = wallObj.wallScaleX; let wallWidth = wallObj.wallWidth;//初始的墙体宽度-单位m //最终形变值 let toPx = modelItem.wallPositionX; let toPz = modelItem.wallPositionY; let toScaleX = modelItem.wallScaleX; if(modelItem.wallType !=0 && parseFloat(modelItem.wallWidth) == 0){ toScaleX = 0 } if(isAnimate){//需要动画 // console.log("墙体动画----", tx, tz, scaleX,toPx, toPz, toScaleX,); // console.log("墙体动画----", scaleX, toScaleX, wallObj.wallScaleX, wallObj); //初始形变值 let spaceInitMatrix = [];//记录下动画创建时的初始变换矩阵 wallObj.instancedMeshIndexList.forEach(item=>{ let _index = item.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 let startMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(item.instancedAtIndex,startMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 spaceInitMatrix.push({ index:_index, matrix:startMatrix.clone(), }) }); var tween = new TWEEN.Tween({ x: tx, z: tz, sx:scaleX, }) .to({ x: toPx, z: toPz, sx:toScaleX, }, 2000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate((object)=> { wallObj.instancedMeshIndexList.forEach(item=>{ let _index = item.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 let tmp = spaceInitMatrix.find(it=>it.index==_index); let stratMatrix = tmp.matrix.clone(); //获取初始变换矩阵 // // 计算变化后的位置:位移后的位置 是 当前几何体的位置参数 加上 模型移动后的位置偏移量 let moveX = object.x - tx; let moveZ = object.z - tz; let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵 let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵 scaleMatrix.makeScale(object.sx / scaleX,1,1); //获得缩放变化矩阵 panMatrix.makeTranslation(moveX,0,moveZ); //获得平移变化矩阵 stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵 instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关 instancedMesh.setMatrixAt(item.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵 // console.warn("***drawModel-isAnimate0***",JSON.stringify(position),JSON.stringify(scale),wallObj.name,modelItem,wallObj); }) }).onComplete(()=>{ this.tweenCameraAnmaChange(false); let gltfWall = this.gltfWalls.find(gltfWall=>gltfWall.uniId==wallObj.uniId);//判断是否已经添加过 if(gltfWall){ gltfWall.wallPositionX = modelItem.wallPositionX; gltfWall.wallPositionY = modelItem.wallPositionY; gltfWall.wallScaleX = modelItem.wallScaleX; gltfWall.wallScaleY = modelItem.wallScaleY; gltfWall.wallRotateY = modelItem.wallRotateY; gltfWall.wallWidth = modelItem.wallWidth; }else{ console.warn("***changeSpacesAnim-over-wall***", wallObj.uniId,wallObj) } // console.warn("***changeSpacesAnim-over-wall***", modelItem) }); // 开始动画 tween.start(); this.tweenCameraAnmaChange(true) }else{ // console.log("墙体变化", modelItem, wallObj, wallObj.wallWidth); wallObj.instancedMeshIndexList.forEach(item=>{ let _index = item.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 // let tmp = spaceInitMatrix.find(it=>it.index==_index); // let stratMatrix = tmp.matrix.clone(); //获取初始变换矩阵 let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(item.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 // // 计算变化后的位置:位移后的位置 是 当前几何体的位置参数 加上 模型移动后的位置偏移量 let moveX = toPx - tx; let moveZ = toPz - tz; let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵 let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵 scaleMatrix.makeScale(toScaleX / scaleX,1,1); //获得缩放变化矩阵 panMatrix.makeTranslation(moveX,0,moveZ); //获得平移变化矩阵 stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵 instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关 instancedMesh.setMatrixAt(item.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵 // console.warn("***drawModel-isAnimate0***",JSON.stringify(position),JSON.stringify(scale),wallObj.name,modelItem,wallObj); }) let gltfWall = this.gltfWalls.find(gltfWall=>gltfWall.uniId==wallObj.uniId);//判断是否已经添加过 gltfWall.wallPositionX = modelItem.wallPositionX; gltfWall.wallPositionY = modelItem.wallPositionY; gltfWall.wallScaleX = modelItem.wallScaleX; gltfWall.wallScaleY = modelItem.wallScaleY; gltfWall.wallRotateY = modelItem.wallRotateY; gltfWall.wallWidth = modelItem.wallWidth; gltfWall.lastWallType = 50; } }, //预处理需要加载墙体模型的数据-减少模型请求数 preWallData(wallArr){ let realWallArr = []; wallArr && wallArr.forEach((item, index) => { item.uniId = Date.now() + index;//唯一标识 //获取墙体对应的gltb模型的相关信息 let modelTypeItem = wallType.find(it=>it.type == item.wallModelData.wallType) //wallType[item.wallModelData.wallType]; let object = realWallArr.find(it=>it.index==item.wallModelData.wallType); //列表中还没有这个数据 if(!object){ let it = { url:modelTypeItem.url, list:[item], name:modelTypeItem.name, index:item.wallModelData.wallType,//在模型当中的类型编码 } realWallArr.push(it) }else{ object.list.push(item); } }); return realWallArr; }, // 加载墙体模型 loadWallModels(realData, wallList, arrLength,resolve){ var that = this; if(!realData.url){ console.warn("***模型wallType不存在***",realData); return false; } that.loader.load(realData.url, ( gltf ) => { that.progress = parseInt(100/arrLength) + that.progress; if(that.progress>100){ that.progress = 100; } this.$store.state.loadingMsg="加载中..." + that.progress+'%'; // console.log("模型加载成功",that.progress,realData,gltf); // 第一个方案:递归获取模型-并一一实例化,减少渲染次数,提高性能;因为实例化了几何体复用了geometry 和 material // DrawCall和内存都很低 gltf.scene.traverse((child)=> { if (child.isMesh && child.visible) { let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), realData.list.length); this.instancedMeshList.push(instancedMesh); //realData 该模型被重复使用时的每一次的形变参数等 realData.list && realData.list.forEach((it,i)=>{ let modelItem = JSON.parse(JSON.stringify(it.wallModelData)); gltf.scene.position.set(modelItem.wallPositionX, 0, modelItem.wallPositionY); gltf.scene.scale.set(modelItem.wallScaleX, 1, modelItem.wallScaleY); gltf.scene.rotation.y = modelItem.wallRotateY; gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了 instancedMesh.setMatrixAt(i, child.matrixWorld); instancedMesh.instanceMatrix.needsUpdate = true; // instancedMesh.setColorAt(i, child.material.color); // instancedMesh.instanceColor.needsUpdate = true; // console.log("***matrixWorld***",child.matrixWorld); let gltfWall = that.gltfWalls.find(gltfWall=>gltfWall.uniId==it.uniId);//判断是否已经添加过 if(!gltfWall){ let md = { uniId:it.uniId,//模型实例的唯一标识 spaceId:it.spaceId, instancedMeshIndexList:[//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号 {instancedMeshIndex:this.instancedMeshList.length-1,instancedAtIndex:i}, ], // id:child.id,//几何体的id // name:child.name,//几何体的id wallPositionX:modelItem.wallPositionX, wallPositionY:modelItem.wallPositionY, wallScaleX:modelItem.wallScaleX, wallScaleY:modelItem.wallScaleY, wallRotateY:modelItem.wallRotateY, wallWidth:modelItem.wallWidth, // lastWallType:51, wallModelData:modelItem, wallModelInitData:modelItem, // 保留初始化墙体数据,方便空间变形计算缩放比例 wallDirection:it.wallDirection, willCurWallType: -1, // 即将成为当前模型,作用于动画加载完替换 lastWallType: -1 // 上一次墙体模型 }; that.gltfWalls.push(md); }else{ gltfWall.instancedMeshIndexList.push({ instancedMeshIndex:this.instancedMeshList.length-1,instancedAtIndex:i }) } }) instancedMesh.userType = "mesh"; instancedMesh.receiveShadow = true;//材质是否接收阴影 that.scene.add(instancedMesh); } }); resolve(); }); }, //计算墙体对应位置和形变参数-提前计算 computeWallHandleOld(spaceObj,wallObj){ // let cube = wallObj.obj; let list = wallObj.wallData;//墙体列表 let scale = 100; let spaceWallInfo = {wallN:false, wallS:false, wallW:false, wallE:false}; spaceObj.spaceWallInfo = spaceWallInfo; list.forEach((item)=>{//空间下的四面墙壁 let lastWallPosition = 0; let wallDirection = item.wallDirection; item.wallModelData.forEach((modelItem,index)=>{//每个墙壁下的位置计算 // 默认空间中心点 let wallPositionX = spaceObj.centerX / 100; let wallPositionY = spaceObj.centerY / 100; let wallRotateY = 0; let wallHeight = 10;//item.wallHeight // 墙体厚度模型10cm if(wallDirection=="N"){ wallPositionY = wallPositionY *-1 - spaceObj.spaceHeight / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionY = wallPositionY + wallHeight2; spaceWallInfo.wallN = true; } else if(wallDirection=="S"){ wallPositionY = wallPositionY *-1 + spaceObj.spaceHeight / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionY = wallPositionY - wallHeight2; spaceWallInfo.wallS = true; } if(wallDirection=="E"){ // console.log("模型参数", wallPositionX, spaceObj.spaceWidth) wallPositionY = wallPositionY * -1; wallPositionX = wallPositionX + spaceObj.spaceWidth / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionX = wallPositionX - wallHeight2; // 减去墙体本身的厚度 wallRotateY = Math.PI/2; // 东西墙 模型旋转90度 spaceWallInfo.wallE = true; }else if(wallDirection=="W"){ wallPositionY = wallPositionY *-1; wallPositionX = wallPositionX - spaceObj.spaceWidth / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionX = wallPositionX + wallHeight2; // 减去墙体本身的厚度 wallRotateY = Math.PI/2; // 东西墙 模型旋转90度 spaceWallInfo.wallW = true; } let wallScaleX = 1; let wallScaleY = 1; let modelWidth = 10; if(modelItem.wallType == '7') { modelWidth = 150 }else if(modelItem.wallType == '21'){ modelWidth = 100 }else if(modelItem.wallType == '22'){ modelWidth = 200 }else if(modelItem.wallType == '23'){ modelWidth = 300 }else if(modelItem.wallType == '24'){ modelWidth = 400 }else if(modelItem.wallType == '25'){ modelWidth = 500 }else if(modelItem.wallType == '26'){ modelWidth = 600 } let tmdWidth = modelItem.wallWidth;//记录 // console.log("XXXXXXXXXXXXXXXX", modelWidth, spaceObj) // 计算墙体的 X Y W H //说明该面墙壁只使用了一个模型-独占形式 if(modelItem.isStepAsideTopRight == 'true' && modelItem.isStepAsideBottomLeft == 'true'){ if(wallDirection=="S" || wallDirection=="N"){//南北 wallScaleX = spaceObj.spaceWidth / modelWidth; }else{//东西 wallScaleX = spaceObj.spaceHeight / modelWidth; } if((parseInt(modelItem.wallType) >=21 && parseInt(modelItem.wallType) <=26) || parseInt(modelItem.wallType)== 7){ }else{ modelItem.wallWidth = wallScaleX * modelWidth; // 解决模型行拉伸定位问题, 先注释 } }else{//墙面是多端墙体组合而成的 if(modelItem.isFixedWidth == 'true'){//该墙体锁定宽度-即不可缩放 let wallWidth = modelItem.wallWidth; // 墙体宽度 // console.log("模型的尺寸",wallWidth, spaceObj.spaceWidth, spaceObj.centerX) //起始墙体-南北从左侧算,东西则从上侧计算 if(modelItem.isStepAsideBottomLeft == 'true' || modelItem.isStepAsideTopRight == 'true'){ if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = spaceObj.centerX - (spaceObj.spaceWidth - wallWidth) / 2; wallPositionX = wallPositionX / scale; // 转换成m }else{ wallPositionY = -spaceObj.centerY - (spaceObj.spaceHeight - wallWidth) / 2; wallPositionY = wallPositionY / scale; // 转换成m } }else{ if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = lastWallPosition + (wallWidth / 2 / scale); }else{ wallPositionY = lastWallPosition + (wallWidth / 2 / scale); } } // console.log("模型的尺寸",wallWidth, wallPositionX) if(modelItem.wallType == 0){ wallScaleX = modelItem.wallWidth / wallHeight; } //计算当前墙体占据的整面墙体的大小-方便下一段墙体的计算 if(wallDirection=="S" || wallDirection=="N"){//南北 lastWallPosition = wallPositionX + wallWidth / 2 / scale; }else{ lastWallPosition = wallPositionY + wallWidth / 2 / scale; } }else{//可变墙体-UE编辑器通常把它放到最后一段墙体 let wallWidth = 0; //墙体的宽度是计算得出的 if(wallDirection=="S" || wallDirection=="N"){//南北 wallWidth = (spaceObj.centerX + spaceObj.spaceWidth / 2) - lastWallPosition * scale; // 墙体宽度 // console.log("最后一个模型",spaceObj.centerX, spaceObj.spaceWidth / 2, lastWallPosition) }else{ wallWidth = (-spaceObj.centerY + spaceObj.spaceHeight / 2) - lastWallPosition * scale; // 墙体宽度 } wallWidth = wallWidth / scale; // cm转换成m if(modelItem.wallType == 0){ wallScaleX = wallWidth * wallHeight; if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = lastWallPosition + wallWidth / 2; }else{ wallPositionY = lastWallPosition + wallWidth / 2; } } modelItem.wallWidth = wallWidth*scale;//确保单位一致 } } //计算得出墙体相应的位置和变形属性 modelItem.wallPositionX = wallPositionX; modelItem.wallPositionY = wallPositionY; modelItem.wallScaleX = wallScaleX; modelItem.wallScaleY = wallScaleY; modelItem.wallRotateY = wallRotateY; // console.log("XXXXXXXXXXXXXXXX", modelWidth, modelItem) //新版下,符合条件的不止一个了,因为新版下是以模型里面的几何体为单元,个数较多 this.gltfWalls.forEach(gltfItem=>{ if(gltfItem.spaceId == spaceObj.spaceId && wallDirection == gltfItem.wallDirection && modelItem.id == gltfItem.wallModelData.id){ gltfItem.wallModelData = JSON.parse(JSON.stringify(modelItem)); } }) }) spaceObj.spaceWallInfo = spaceWallInfo; }) }, // 新计算墙体逻辑 computeWallHandle(oldSpaceObj, spaceObj, wallObj, moveOut, direction){ var that = this; let list = wallObj.wallData;//墙体列表 let scale = 100; console.log("墙体数据1",direction, list, moveOut, that.gltfWalls, wallObj); console.log("旧空间+++", oldSpaceObj.spaceId, oldSpaceObj.centerX, oldSpaceObj.centerY,oldSpaceObj.spaceWidth, oldSpaceObj.spaceHeight); console.log("新空间+++", spaceObj.spaceId, spaceObj.centerX, spaceObj.centerY,spaceObj.spaceWidth, spaceObj.spaceHeight); list.forEach((item)=>{//空间下的四面墙壁 let lastWallPosition = 0; let wallDirection = item.wallDirection; let spaceSize = 0 let oldSpaceSize = 0 let minWallWidth = 10; // 实墙最小宽度 let wallCount = item.wallModelData.length; let isCurWall = true; let isCreateNewWall = false; let newWallType = null; if(wallDirection=="N" || wallDirection=="S"){ spaceSize = spaceObj.spaceWidth; oldSpaceSize = oldSpaceObj.spaceWidth; }else{ spaceSize = spaceObj.spaceHeight; oldSpaceSize = oldSpaceObj.spaceHeight; } let isComputeWall = true; if((direction=="S" || direction=="N") && (wallDirection == "S" || wallDirection == "N")){ isComputeWall = false; } if((direction=="E" || direction=="W") && (wallDirection == "E" || wallDirection == "W")){ isComputeWall = false; } if(wallCount > 2 && isComputeWall){ // 墙体个数,判断是否有墙体模型 const modelItem0 = item.wallModelData[0]; // 固定尺寸实体墙 const modelItem1 = item.wallModelData[1]; // 取出模型的宽度 const modelItem2 = item.wallModelData[2]; // 伸缩实体墙 const leftWallChangeValue = spaceSize - minWallWidth - parseFloat(modelItem1.wallWidth) - parseFloat(modelItem0.wallWidth); console.log("当前模型的类型信息", modelItem1, leftWallChangeValue) if(moveOut){ // 放大 // 1.判断是否是从无到有 // 是 // 2 先还原窗户,找到最合适的窗户 // 3 最后还原第一面实体墙 // 否 // 4 找到最合适的窗户 // 5 最后还原第一面实体墙 const curWallType = wallType.find(it=>it.type == modelItem1.wallType) const wallTypeGroups = wallType.filter(it=>it.group == curWallType.group) const wallWidth = spaceSize - 2 * minWallWidth; if(wallWidth > curWallType.width){ newWallType = curWallType; } for (let index = 0; index < wallTypeGroups.length; index++) { const element = wallTypeGroups[index]; if(!newWallType){ if(element.width <= wallWidth){ newWallType = element; } }else{ if(element.width <= wallWidth && newWallType.width <= element.width ){ newWallType = element; } } try{ console.log("寻找最大的窗户",index, wallWidth, newWallType.width,element.width) }catch(e){ console.error("***rrrrr***",e,element,newWallType) } } item.wallModelData[1].wallWidth = newWallType.width; if(newWallType != curWallType){ // 新模型 console.log("添加新模型") item.wallModelData[1].willCurWallType = newWallType.type; item.wallModelData[1].lastWallType = curWallType.type; isCreateNewWall = true; }else{ console.log("还原老模型") } // 初始化模型的尺寸 const initWallModel = this.gltfWalls.find(it=>{ return it.spaceId == spaceObj.spaceId && it.wallDirection == wallDirection && it.wallModelData.wallType == 0 && it.wallModelData.isFixedWidth == 'true' }) const item0Width = Math.min((spaceSize - newWallType.width - minWallWidth), initWallModel.wallModelInitData.wallWidth); item.wallModelData[0].wallWidth = item0Width console.log("还原第一面墙的宽度", item0Width ,spaceSize, newWallType.width, minWallWidth); }else{ // 缩小 // 初始化模型的尺寸 const initWallModel = this.gltfWalls.find(it=>{ return it.spaceId == spaceObj.spaceId && it.wallDirection == wallDirection && it.wallModelData.wallType == 0 && it.wallModelData.isFixedWidth == 'true' }) const firstWallW = initWallModel.wallModelInitData.wallWidth; // 计算最右边墙体尺寸 const modelItem2W = oldSpaceSize - parseFloat(firstWallW) - parseFloat(modelItem1.wallWidth); if(modelItem2W > 10){ } // 计算最右边墙体的比例 const modelItem0Scale = firstWallW / oldSpaceSize; const modelItem2Scale = modelItem2W / oldSpaceSize; const modelItem0NewW = modelItem0Scale * spaceSize; const modelItem2NewW = modelItem2Scale * spaceSize; console.log("墙体模型比例数据", oldSpaceSize,spaceSize, initWallModel.wallModelInitData.wallWidth,modelItem0Scale, modelItem0NewW, modelItem2NewW); if(leftWallChangeValue < 0){ const newWallWidth = Math.max(parseFloat(modelItem0.wallWidth) + leftWallChangeValue, minWallWidth); item.wallModelData[0].wallWidth = Math.floor(newWallWidth) console.log("缩放左边实体墙",spaceObj.spaceId, newWallWidth, leftWallChangeValue); if(modelItem1.wallWidth > spaceSize - 2 * minWallWidth){ console.log("无法放置墙体模型", newWallWidth, leftWallChangeValue); // 寻找合适的模型 const curWallType = wallType.find(it=>it.type == modelItem1.wallType) // 可显示的最大模型 if(curWallType){ const wallTypeGroups = wallType.filter(it=>it.group == curWallType.group) const wallWidth = spaceSize - 2 * minWallWidth; for (let index = 0; index < wallTypeGroups.length; index++) { const element = wallTypeGroups[index]; if(!newWallType){ if(element.width <= wallWidth && element.width <= curWallType.width){ newWallType = element; } }else{ if(newWallType.width <= element.width && element.width <= wallWidth && element.width <= curWallType.width){ newWallType = element; } } } console.log("是否需要替换墙体模型",spaceObj.spaceHeight, wallDirection, newWallType, curWallType.type) if(newWallType){ if(curWallType.type != newWallType.type){ console.log("最合适的墙体模型", spaceObj.spaceId, wallWidth, direction, wallDirection) item.wallModelData[1].wallWidth = newWallType.width; item.wallModelData[1].willCurWallType = newWallType.type; item.wallModelData[1].lastWallType = curWallType.type; item.wallModelData[0].wallWidth = Math.floor((spaceSize - newWallType.width) / 2) isCurWall = false; // 添加新模型 const index = this.gltfWalls.findIndex(it=>{ // console.log("最合适的墙体模型", it.spaceId, spaceObj.spaceId, it.wallDirection, wallDirection, newWallType.wallType, it.wallModelData.wallType) return it.spaceId == spaceObj.spaceId && it.wallDirection == wallDirection && newWallType.wallType == it.wallModelData.wallType }) if(index!=-1){ console.log("不需要加载新模型", spaceObj.spaceId, direction, wallDirection) isCreateNewWall = false; }else{ console.log("需要加载新模型", index) isCreateNewWall = true; } }else{ console.log("保持当前模型的尺寸", spaceObj.spaceHeight, direction, wallDirection) item.wallModelData[1].wallWidth = 0.0001; item.wallModelData[1].willCurWallType = -1; } }else{ console.log("没有合适的模型替换", spaceObj.spaceId, direction, wallDirection) item.wallModelData[1].wallWidth = 0.0001; item.wallModelData[1].willCurWallType = -1; } } }else{ console.log("不需要添加"); } }else{ item.wallModelData[0].wallWidth = Math.floor(modelItem0NewW) console.log("等比缩放"); } } }else{ console.log("没有缩放墙体") } // 判断是否有下一级 item.wallModelData.forEach((modelItem,index)=>{//每个墙壁下的位置计算 // 默认空间中心点 let wallPositionX = spaceObj.centerX / 100; let wallPositionY = spaceObj.centerY / 100; let wallRotateY = 0; let wallHeight = 10;//item.wallHeight // 墙体厚度模型10cm if(wallDirection=="N"){ wallPositionY = wallPositionY *-1 - spaceObj.spaceHeight / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionY = wallPositionY + wallHeight2; } else if(wallDirection=="S"){ wallPositionY = wallPositionY *-1 + spaceObj.spaceHeight / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionY = wallPositionY - wallHeight2; } if(wallDirection=="E"){ // console.log("模型参数", wallPositionX, spaceObj.spaceWidth) wallPositionY = wallPositionY * -1; wallPositionX = wallPositionX + spaceObj.spaceWidth / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionX = wallPositionX - wallHeight2; // 减去墙体本身的厚度 wallRotateY = Math.PI/2; // 东西墙 模型旋转90度 }else if(wallDirection=="W"){ wallPositionY = wallPositionY *-1; wallPositionX = wallPositionX - spaceObj.spaceWidth / 2 / scale; let wallHeight2 = wallHeight / 2 / scale; wallPositionX = wallPositionX + wallHeight2; // 减去墙体本身的厚度 wallRotateY = Math.PI/2; // 东西墙 模型旋转90度 } let wallScaleX = 1; let wallScaleY = 1; let modelWidth = 10; if(modelItem.wallType == '7') { modelWidth = 150 }else if(modelItem.wallType == '21'){ modelWidth = 100 }else if(modelItem.wallType == '22'){ modelWidth = 200 }else if(modelItem.wallType == '23'){ modelWidth = 300 }else if(modelItem.wallType == '24'){ modelWidth = 400 }else if(modelItem.wallType == '25'){ modelWidth = 500 }else if(modelItem.wallType == '26'){ modelWidth = 600 } let tmdWidth = modelItem.wallWidth;//记录 // console.log("XXXXXXXXXXXXXXXX", modelWidth, spaceObj) let wallWidth = 0; // 墙体宽度 // 计算墙体的 X Y W H //说明该面墙壁只使用了一个模型-独占形式 if(modelItem.isStepAsideTopRight == 'true' && modelItem.isStepAsideBottomLeft == 'true'){ if(wallDirection=="S" || wallDirection=="N"){//南北 wallScaleX = spaceObj.spaceWidth / modelWidth; }else{//东西 wallScaleX = spaceObj.spaceHeight / modelWidth; } if((parseInt(modelItem.wallType) >=21 && parseInt(modelItem.wallType) <=26) || parseInt(modelItem.wallType)== 7){ }else{ modelItem.wallWidth = wallScaleX * modelWidth; // 解决模型行拉伸定位问题, 先注释 } }else{//墙面是多端墙体组合而成的 if(modelItem.isFixedWidth == 'true'){//该墙体锁定宽度-即不可缩放 wallWidth = modelItem.wallWidth; // 墙体宽度 // console.log("模型的尺寸",wallWidth, spaceObj.spaceWidth, spaceObj.centerX) //起始墙体-南北从左侧算,东西则从上侧计算 if(modelItem.isStepAsideBottomLeft == 'true' || modelItem.isStepAsideTopRight == 'true'){ if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = spaceObj.centerX - (spaceObj.spaceWidth - wallWidth) / 2; wallPositionX = wallPositionX / scale; // 转换成m }else{ wallPositionY = -spaceObj.centerY - (spaceObj.spaceHeight - wallWidth) / 2; wallPositionY = wallPositionY / scale; // 转换成m } }else{ if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = lastWallPosition + (wallWidth / 2 / scale); }else{ wallPositionY = lastWallPosition + (wallWidth / 2 / scale); } } // console.log("模型的尺寸",wallWidth, wallPositionX) if(modelItem.wallType == 0){ wallScaleX = modelItem.wallWidth / wallHeight; }else{ console.log("墙体模型的缩放", spaceObj.spaceId,wallDirection, modelItem); // if(!moveOut){ const curWallType = wallType.find(it=>it.type == modelItem.wallType) wallScaleX = modelItem.wallWidth / curWallType.width; console.log("墙体模型的缩小", wallScaleX); // }else{ // console.log("墙体模型的放大", wallScaleX); // } } //计算当前墙体占据的整面墙体的大小-方便下一段墙体的计算 if(wallDirection=="S" || wallDirection=="N"){//南北 lastWallPosition = wallPositionX + wallWidth / 2 / scale; }else{ lastWallPosition = wallPositionY + wallWidth / 2 / scale; } // wallPositionY = 1; }else{//可变墙体-UE编辑器通常把它放到最后一段墙体 wallWidth = 0; //墙体的宽度是计算得出的 if(wallDirection=="S" || wallDirection=="N"){//南北 wallWidth = (spaceObj.centerX + spaceObj.spaceWidth / 2) - lastWallPosition * scale; // 墙体宽度 // console.log("最后一个模型",spaceObj.centerX, spaceObj.spaceWidth / 2, lastWallPosition) }else{ wallWidth = (-spaceObj.centerY + spaceObj.spaceHeight / 2) - lastWallPosition * scale; // 墙体宽度 } wallWidth = wallWidth / scale; // cm转换成m if(modelItem.wallType == 0){ wallScaleX = wallWidth * wallHeight; if(wallDirection=="S" || wallDirection=="N"){//南北 wallPositionX = lastWallPosition + wallWidth / 2; }else{ wallPositionY = lastWallPosition + wallWidth / 2; } } modelItem.wallWidth = wallWidth*scale;//确保单位一致 // wallPositionY = 1; } } console.log("移动墙体模型-空间信息", spaceObj.spaceWidth, spaceObj.centerX, spaceObj.centerY, spaceObj) console.log("移动墙体模型-墙体信息",spaceObj.spaceId,direction, wallDirection, modelItem.wallType, wallWidth, this.wallList) //计算得出墙体相应的位置和变形属性 modelItem.wallPositionX = wallPositionX; modelItem.wallPositionY = wallPositionY; modelItem.wallScaleX = wallScaleX; modelItem.wallScaleY = wallScaleY; modelItem.wallRotateY = wallRotateY; modelItem.wallWidth = wallWidth; // 更新数据 if(isComputeWall || direction == wallDirection){ this.gltfWalls.forEach(gltfItem=>{ if(gltfItem.spaceId == spaceObj.spaceId && wallDirection == gltfItem.wallDirection && modelItem.id == gltfItem.wallModelData.id){ console.log("墙体更新", gltfItem.spaceId, spaceObj.spaceId, wallDirection, gltfItem.wallDirection, modelItem.id, gltfItem.wallModelData.id, isComputeWall, direction) gltfItem.wallModelData = JSON.parse(JSON.stringify(modelItem)); gltfItem.willCurWallType = modelItem.willCurWallType if(gltfItem.wallModelData.wallType != 0){ gltfItem.isDidWall = isCreateNewWall; } } }) } console.log("移动墙体模型-墙体信息++++++++",spaceObj.spaceId, direction, wallDirection, isComputeWall, modelItem) //数据更新到wallList中,确保数据一致性 this.wallList.forEach(wallItem=>{ const walls = JSON.parse(wallItem.wallJson); // console.log("墙体数据2----------", walls, modelItem); walls.wallData.forEach(wall=>{ wall.wallModelData.forEach(wallmodel=>{ //从wallList找到这段墙体 if(wall.wallDirection == wallDirection && wallmodel.id == modelItem.id && walls.spaceId == spaceObj.spaceId){ if(wallmodel.wallType == 0 && wallmodel.isFixedWidth == 'true'){ wallmodel.wallWidth = modelItem.wallWidth; console.log("墙体数据31----实体墙------",spaceObj.spaceId, modelItem.wallWidth, modelItem); } if(wallmodel.wallType != 0){ wallmodel.wallWidth = modelItem.wallWidth; const curWallType = wallType.find(it=>it.type == modelItem.willCurWallType) if(curWallType){ wallmodel.wallType = curWallType.type; } } } }) }) wallItem.wallJson = JSON.stringify(walls); }) }) }) // console.log("墙体数据2", this.gltfWalls, this.wallList); }, //更新墙体模型的位置 updateAllWallHandle(){//spaceList gltfSpaces console.warn("***updateAllWallHandle***") this.spaceList.forEach((spaceObj)=>{ // 根据空间,更新前提数据 let wallObj = this.wallList.find((item)=>{ return item.id == spaceObj.wallId; }) if(wallObj){ let element = JSON.parse(wallObj.wallJson); // console.warn("****wallObj**",element) this.computeWallHandleOld(spaceObj, element); // 重新计算-并把空间的计算结果同步到gltfWalls中 } }) for (let index = 0; index < this.gltfWalls.length; index++) { const element = this.gltfWalls[index]; this.drawModel(element.wallModelData, null, element, false) } }, loadChangeWallModels(item, resolve){ var that = this; let wallObj = item; // console.log("处理模型替换", item.wallModelData); if(item.wallModelData.wallWidth == 0){ // 模型隐藏 return resolve(); } if(item.wallModelData.willCurWallType && item.wallModelData.willCurWallType != -1){ const curWallType = wallType.find(it=>it.type == item.wallModelData.willCurWallType) // console.log("加载的模型", item, item.wallModelData.willCurWallType, curWallType); if(!curWallType){ return resolve(); } that.loader.load(curWallType.url, ( gltf ) => { // 旧的模型 let spaceInitMatrix = [];//记录下动画创建时的初始变换矩阵 wallObj.instancedMeshIndexList.forEach(it=>{ let _index = it.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 let startMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(it.instancedAtIndex,startMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 spaceInitMatrix.push({ index:_index, matrix:startMatrix.clone(), }) }); wallObj.instancedMeshIndexList.forEach(it=>{ let _index = it.instancedMeshIndex; let instancedMesh = this.instancedMeshList[_index];//获取网格实例 let tmp = spaceInitMatrix.find(it=>it.index==_index); let stratMatrix = tmp.matrix.clone(); //获取初始变换矩阵 // // 计算变化后的位置:位移后的位置 是 当前几何体的位置参数 加上 模型移动后的位置偏移量 let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵 let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵 scaleMatrix.makeScale(0,0,0); //获得缩放变化矩阵 panMatrix.makeTranslation(0,0,0); //获得平移变化矩阵 stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵 instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关 instancedMesh.setMatrixAt(it.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵 }) let newWallObj = JSON.parse(JSON.stringify(item)) const wallType = item.wallModelData.willCurWallType; console.log("重新组合新模型数据", newWallObj, item.wallModelData, wallType); newWallObj.willCurWallType = -1; let wallModelData = newWallObj.wallModelData; wallModelData.wallScaleX = 1; wallModelData.wallScaleY = 1; wallModelData.lastWallType = item.wallModelData.wallType; wallModelData.wallType = wallType; wallModelData.willCurWallType = -1; newWallObj.wallModelData = wallModelData; newWallObj.wallScaleX = 1; newWallObj.wallScaleY = 1; let realWallArr = this.preWallData([newWallObj]); const realData = realWallArr[0]; // 新的模型 gltf.scene.traverse((child)=> { if (child.isMesh && child.visible) { let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), realData.list.length); this.instancedMeshList.push(instancedMesh); //realData 该模型被重复使用时的每一次的形变参数等 realData.list && realData.list.forEach((it,i)=>{ gltf.scene.position.set(item.wallPositionX, 0, item.wallPositionY); gltf.scene.scale.set(1, 1, 1); gltf.scene.rotation.y = item.wallRotateY; gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了 instancedMesh.setMatrixAt(i, child.matrixWorld); instancedMesh.instanceMatrix.needsUpdate = true; // instancedMesh.setColorAt(i, child.material.color); // instancedMesh.instanceColor.needsUpdate = true; // console.log("***matrixWorld***",child.matrixWorld); let gltfWall = that.gltfWalls.find(gltfWall=>gltfWall.uniId==it.uniId);//判断是否已经添加过 if(!gltfWall){ let md = { uniId:it.uniId,//模型实例的唯一标识 spaceId:it.spaceId, instancedMeshIndexList:[//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号 {instancedMeshIndex:this.instancedMeshList.length-1,instancedAtIndex:i}, ], // id:child.id,//几何体的id // name:child.name,//几何体的id wallPositionX:item.wallPositionX, wallPositionY:item.wallPositionY, wallScaleX:1, wallScaleY:1, wallRotateY:item.wallRotateY, wallWidth:item.wallWidth, wallModelData:wallModelData, wallModelInitData:item, // 保留初始化墙体数据,方便空间变形计算缩放比例 wallDirection:it.wallDirection, willCurWallType: -1, // 即将成为当前模型,作用于动画加载完替换 lastWallType:wallModelData.lastWallType // 上一次墙体模型 }; that.gltfWalls.push(md); }else{ gltfWall.instancedMeshIndexList.push({ instancedMeshIndex:this.instancedMeshList.length-1,instancedAtIndex:i }) } }) instancedMesh.userType = "mesh"; that.scene.add(instancedMesh); } }); resolve(); }) } resolve(); } } }