// var app = getApp(); //获取应用实例 // const util = require('@/static/utils/util.js'); // const config = require('@/services/urlConfig.js'); // import requestConfig from '@/services/requestConfig.js'; import * as THREE from 'three'; import TWEEN from 'three/addons/libs/tween.module.js'; import spaceTypes from '@/static/spaceTypesIE.js'; let glbWidth = 300;//空间地板模型的真实尺寸 let glbHeight = 300; export default { data() { return { gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_AutoWall_WoodFloor1.glb", //模型地址 // gltfSpaceUrl: "https://dm.static.elab-plus.com/3d/model/20230607/diban/diban.gltf", //模型地址 // gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_L_carpet01-1.gltf", //模型地址 // gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01_1.gltf", //模型地址 gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01.glb", //模型地址 spaceTypes:spaceTypes, } }, watch: {}, methods: { // 加载地板模型 loaderSpaceArr(list){ if(!list || list.length==0){ return false; } this.instancedSpaceMeshList = []; this.gltfSpaces = []; let comlist = list.filter(it=>it.spaceType!=14);//过滤花园的空间 this.loaderCommonSpace(this.gltfSpaceUrl,comlist,1); let arrlist = list.filter(it=>it.spaceType==14);//花园的空间 // this.loaderCommonSpace(this.gltfSpace1Url,arrlist,2); if(arrlist && arrlist.length>0){ this.loaderGraseSpace(list);//加载草地的模型-所有地块都添加,填补房间里面的 } }, loaderCommonSpace(gltfSpaceUrl,list,type=1){ var that = this; this.loader.load(gltfSpaceUrl, ( gltf ) => { console.log("地板模型加载成功") // gltf.scene.receiveShadow = true;//材质是否接收阴影 gltf.scene.traverse((child)=> { if (child.isMesh && child.visible) { let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), list.length); this.instancedSpaceMeshList.push(instancedMesh); //设置每一块地板的实例值 list.forEach((obj,i)=>{ let positionX = obj.centerX / 100; let positionY = obj.centerY / 100; if(type==1){ // glbWidth = glbHeight = 1500; } let scaleX = obj.spaceWidth / glbWidth; let scaleY = obj.spaceHeight / glbHeight; gltf.scene.position.set(positionX, 0, -positionY); gltf.scene.scale.set(scaleX, 1, scaleY); gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了 instancedMesh.setMatrixAt(i, child.matrixWorld); instancedMesh.instanceMatrix.needsUpdate = true; instancedMesh.setColorAt(i, child.material.color); instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额 let gltfSpace = that.gltfSpaces.find(gltfSpace=>gltfSpace.spaceId == obj.spaceId);//判断是否已经添加过 if(!gltfSpace){ let position = new THREE.Vector3();//当前几何体的位置参数 let scale = new THREE.Vector3();//当前几何体的缩放参数 position.set(positionX, 0, -positionY); scale.set(scaleX, 1, scaleY); let md = { spaceId:obj.spaceId,//模型实例的唯一标识 instancedMeshIndexList:[//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号 {instancedMeshIndex: this.instancedSpaceMeshList.length - 1, instancedAtIndex : i, color:instancedMesh.material.color.clone(),}, ], spaceName:obj.spaceName,//几何体的id spaceType:obj.spaceType, position:position, scale:scale, isSizeLock:obj.isSizeLock, }; that.gltfSpaces.push(md); }else{//添加另外一组实例 gltfSpace.instancedMeshIndexList.push({ instancedMeshIndex:this.instancedSpaceMeshList.length - 1, instancedAtIndex:i, color:instancedMesh.material.color.clone(), }) } }) instancedMesh.userType = "mesh"; if(type==2){//花园 instancedMesh.name = "花园"; }else{//室内 instancedMesh.name = "地板"; } instancedMesh.receiveShadow = true;//材质是否接收阴影 that.scene.add(instancedMesh); } }); // this.pvCurPageName=="room_show" if(true){ //给地板模型添加天花板 list && list.forEach(obj=>{ if(obj.spaceType!=14){//花园不加上面的墙 let positionX = obj.centerX / 100; let positionY = obj.centerY / 100; // 天花板 const planeGeometry = new THREE.PlaneGeometry(obj.spaceWidth / 100,obj.spaceHeight / 100); const planeMaterial = new THREE.MeshStandardMaterial({ color:0xffffff, metalness: 0.4, // 设置金属度为1.0 roughness: 1 // 设置粗糙度为0.5 }); const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial) planeMesh.rotation.x = Math.PI / 2 ; // 旋转 180 度 planeMesh.position.set(positionX, 2.8, -positionY); planeMesh.userType = "mesh" const spaceObj = { spaceId:obj.spaceId, spaceWidth:obj.spaceWidth, spaceHeight:obj.spaceHeight } planeMesh.userData = spaceObj; that.scene.add(planeMesh); that.gltfSpaceRoofs.push(planeMesh); } }) } }); }, //草地加载 loaderGraseSpace(list){ let glbWidth = 300; let glbHeight = 300; var that = this; console.log("草地模型加载成功") //将模型添加到场景中 let texture = new THREE.TextureLoader().load("https://dm.static.elab-plus.com/miniProgram/grass.jpg"); // let texture = new THREE.TextureLoader().load( "https://dm.static.elab-plus.com/miniProgram/Avatar_male.png" ); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; list && list.forEach(obj=>{ // 暂时手动过滤 2楼 儿童房和次卫 不添加草地 if((obj.spaceId == 582 && obj.spaceName == "儿童房") || (obj.spaceId == 388 && obj.spaceName == "次卫")){ return } let positionX = obj.centerX / 100; let positionY = obj.centerY / 100; let scaleX = obj.spaceWidth / 100; let scaleY = obj.spaceHeight / 100; texture = texture.clone(); //使用纹理贴图材质 texture.repeat.set(scaleX, scaleY); // let geometry = new THREE.PlaneGeometry(obj.spaceWidth/100, obj.spaceHeight/100); // let material = new THREE.MeshBasicMaterial({ map: texture }); // let cube = new THREE.Mesh(geometry, material); let geometry = new THREE.BoxGeometry(obj.spaceWidth/100, 0.1, obj.spaceHeight/100); let colorMaterial = new THREE.MeshBasicMaterial({color: 0x626F44}); // 创建纯色材质对象 let material = new THREE.MeshBasicMaterial({ map: texture }); let cube = new THREE.Mesh(geometry, [colorMaterial, colorMaterial, material, colorMaterial, colorMaterial, colorMaterial]); // 使用 BoxGeometry 和纯色材质创建 Mesh 对象 cube.name = "地板"; cube.userType = "mesh"; cube.userData = obj;//位置数据 // 设置位置,旋转,缩放 cube.position.set(positionX, -0.11, -positionY); // cube.rotation.x = -Math.PI / 2 ; // 旋转 180 度 PlaneGeometry 生效 // cube.receiveShadow = true;//材质是否接收阴影 //注释掉,不让草地进入空间列表中,不触发空间变化的动画过程,规避掉动画过程中的问题 // let md = { // spaceId:obj.spaceId,//模型实例的唯一标识 // spaceName:obj.spaceName,//几何体的id // spaceType:obj.spaceType, // position:cube.position, // scale:cube.scale, // isSizeLock:obj.isSizeLock, // }; // that.gltfSpaces.push(md); that.scene.add(cube); }) }, //修改指定空间的颜色 changeSpaceColor(spaceId,type=1){ // 寻找地板 const cube = this.gltfSpaces.find((item)=>{ return item.spaceId == spaceId; }) if(cube.instancedMeshIndexList){ if(type==1){ cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置 let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例 instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额 let color = new THREE.Color(0xFF9F40); // 使用sRGB颜色值 // color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值 instancedMesh.setColorAt(instanced.instancedAtIndex, color);//修改这个几何体的颜色 }) }else{ cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局Instance let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例 instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额 instancedMesh.setColorAt(instanced.instancedAtIndex, instanced.color);//修改这个几何体的颜色 }); } } }, //修改当前空间的面积大小-动画方案2 changeSpacesAnim(curSpace){ // 寻找地板 const cube = this.gltfSpaces.find((item)=>{ return item.spaceId == curSpace.spaceId; }) console.log("空间移动目标",cube.spaceId, JSON.stringify(cube.position),JSON.stringify(cube.scale), curSpace.toPx, curSpace.toPz,curSpace.toScaleX, curSpace.toScaleZ); //初始形变值 let x = cube.position.x; let z = cube.position.z; let scaleX = cube.scale.x; let scaleZ = cube.scale.z; //最终形变值 let toPx = curSpace.toPx; let toPz = curSpace.toPz; let toScaleX = curSpace.toScaleX; let toScaleZ = curSpace.toScaleZ; if(cube.instancedMeshIndexList){ let spaceInitMatrix = [];//空间动画时的初始变换矩阵 cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//geometry实例 在 全局InstancedMesh实例的位置 let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例 let startMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(instanced.instancedAtIndex,startMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 spaceInitMatrix.push({ index:_index, matrix:startMatrix.clone(), color:instancedMesh.material.color.clone(), }) }); // console.warn("***cube***",cube.spaceId,Date.now(),JSON.stringify(spaceInitMatrix[0].matrix)) var tween = new TWEEN.Tween({ x: cube.position.x, z: cube.position.z, sx:cube.scale.x, sz:cube.scale.z }) .to({ x: curSpace.toPx, z: curSpace.toPz, sx:curSpace.toScaleX, sz:curSpace.toScaleZ }, 2000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate((object)=> { //获取地板模型的geometry实例 cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置 let instancedMesh = this.instancedSpaceMeshList[_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(object.sx / scaleX,1,object.sz / scaleZ); //获得缩放变化矩阵 panMatrix.makeTranslation(object.x - x,0,object.z - z); //获得平移变化矩阵 stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵 instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关 instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵 if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才变化颜色 instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额 let color = new THREE.Color(0xFF9F40); // 使用sRGB颜色值 // color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值 instancedMesh.setColorAt(instanced.instancedAtIndex, color);//修改这个几何体的颜色 } }); }).onComplete(()=>{//这个回调很可能会很慢 this.tweenCameraAnmaChange(false); console.warn("***changeSpacesAnim-over***") if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才恢复颜色 cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局Instance let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例 let tmp = spaceInitMatrix.find(it=>it.index==_index); instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额 instancedMesh.setColorAt(instanced.instancedAtIndex, tmp.color);//修改这个几何体的颜色 }); } }); // 开始动画 tween.start(); this.tweenCameraAnmaChange(true) cube.position.x = curSpace.toPx; cube.position.z = curSpace.toPz; cube.scale.x = curSpace.toScaleX; cube.scale.z = curSpace.toScaleZ; }else{//有点问题规避下 // 空间动画 var tween = new TWEEN.Tween({ x: scaleX, z: scaleZ, px:x, pz:z, }) .to({ x: toScaleX, z: toScaleZ, px:toPx, pz:toPz, }, 2000) .easing(TWEEN.Easing.Quadratic.InOut) .onUpdate((object)=> { cube.scale.x = object.x; cube.scale.z = object.z; cube.position.x = object.px; cube.position.z = object.pz; }); // 开始动画 tween.start(); } // 屋顶尺寸调整 const cubeRoof = this.gltfSpaceRoofs.find((item)=>{ return item.userData.spaceId == curSpace.spaceId; }) if(cubeRoof){ let roofScaleX = curSpace.spaceObj.spaceWidth / cubeRoof.userData.spaceWidth let roofScaleY = curSpace.spaceObj.spaceHeight / cubeRoof.userData.spaceHeight // console.log("屋顶尺寸变化", curSpace.spaceObj, cubeRoof, roofScaleX, roofScaleY) cubeRoof.scale.set(roofScaleX,roofScaleY,1);//缩小为原来0.5倍 cubeRoof.position.x = toPx; cubeRoof.position.z = toPz; } }, //所有空间整体缩放-同时同步到数据里面 allSpaceScale(){ const centerOffset = new THREE.Vector3(0, 0, 0); // 假设中心点在几何体的正中心 const scale = new THREE.Vector3(0.9, 1, 0.9); // 缩放尺度 //实例化的默认中心是就原点也就是0 0 0 这个点,所以centerOffset也必须是原点 // this.instancedMeshList.forEach((mesh)=>{ // mesh.scale.copy(scale); // mesh.updateMatrix(); // mesh.updateMatrixWorld(); // mesh.updateMorphTargets(); // mesh.geometry.computeVertexNormals(); // }) // this.instancedSpaceMeshList.forEach((mesh)=>{ // mesh.scale.copy(scale); // mesh.updateMatrix(); // mesh.updateMatrixWorld(); // mesh.updateMorphTargets(); // mesh.geometry.computeVertexNormals(); // }) // this.gltfLayouts.forEach((mesh)=>{ // // mesh.scale.copy(scale); // }) this.gltfSpaces.forEach(cube=>{ let dis = centerOffset.clone().sub(cube.position);//获得差值向量 // console.warn("***dis***",JSON.stringify(dis),JSON.stringify(cube.position),cube.spaceId); let x = dis.x * (1 - scale.x);//x轴需要移动的距离 let y = dis.y * (1 - scale.y);//y轴需要移动的距离 let z = dis.z * (1 - scale.z);//z轴需要移动的距离 let pi = new THREE.Vector3();//新的中心点位置 pi.x = cube.position.x + x; pi.y = cube.position.y + y; pi.z = cube.position.z + z; cube.scale.x = cube.scale.x * scale.x;//修改真实的比例 cube.scale.z = cube.scale.z * scale.z;// cube.position.copy(pi); //同步信息到空间列表中 let sapce = this.spaceList.find(it=>{ return it.spaceId==cube.spaceId}); if(sapce){ //更新空间中心点值 sapce.centerX = pi.x * 100; sapce.centerY = -1* pi.z * 100; //更新空间宽度高度值 sapce.spaceWidth = cube.scale.x * glbWidth; sapce.spaceHeight = cube.scale.z * glbHeight; } // let dir = new THREE.Vector3( 0, 10, 0 );;//当前几何体的位置参数 // console.warn("***dis1***",JSON.stringify(pi),JSON.stringify(dir)); // let length = 3; // let hex = 0xff0000; // let arrowHelper = new THREE.ArrowHelper( dir, pi, length, hex ); // this.scene.add( arrowHelper ); //这是矩阵运算处理缩放的方法-此为数学上的方案 cube.instancedMeshIndexList.forEach(instanced=>{ let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置 let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例 let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵 instancedMesh.getMatrixAt(instanced.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面 let scaleMatrix = new THREE.Matrix4().makeScale(scale.x, scale.y, scale.z); let inverseTranslationMatrix = new THREE.Matrix4().makeTranslation(x, y, z); stratMatrix.premultiply(inverseTranslationMatrix); stratMatrix.multiply(scaleMatrix); instancedMesh.instanceMatrix.needsUpdate = true; instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵 }); }) this.$nextTick(()=>{ this.updateAllWallHandle(); }) setTimeout(() =>{ this.updataPageData();//更新数据到各个对象里面 this.calculateLayoutModelSize();//重新计算家具位置 this.updateLables();//更新lable this.$nextTick(()=>{ this.updateCareFul();//更新精细调整里面的空间 this.updateSpanceData();//更新语音组件里面的空间 }) }, 100); } } }