floorMethod.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // var app = getApp(); //获取应用实例
  2. // const util = require('@/static/utils/util.js');
  3. // const config = require('@/services/urlConfig.js');
  4. // import requestConfig from '@/services/requestConfig.js';
  5. import * as THREE from 'three';
  6. import TWEEN from 'three/addons/libs/tween.module.js';
  7. let glbWidth = 300;//空间地板模型的真实尺寸
  8. let glbHeight = 300;
  9. export default {
  10. data() {
  11. return {
  12. gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_AutoWall_WoodFloor1.glb", //模型地址
  13. // gltfSpaceUrl: "https://dm.static.elab-plus.com/3d/model/20230607/diban/diban.gltf", //模型地址
  14. // gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_L_carpet01-1.gltf", //模型地址
  15. // gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01_1.gltf", //模型地址
  16. gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01.glb", //模型地址
  17. instancedSpaceMeshList:[],//地板实例对象 当地板复杂是就会存在多个
  18. spaceTypes : ["卧室","客厅","餐厅","厨房","玄关","卫生间","衣帽间","收纳","阳台","飘窗","链接空间","自定义","楼梯","花园"],
  19. }
  20. },
  21. watch: {},
  22. methods: {
  23. // 加载地板模型
  24. loaderSpaceArr(list){
  25. if(!list || list.length==0){
  26. return false;
  27. }
  28. this.instancedSpaceMeshList = [];
  29. this.gltfSpaces = [];
  30. let comlist = list.filter(it=>it.spaceType!=14);//过滤花园的空间
  31. this.loaderCommonSpace(this.gltfSpaceUrl,comlist,1);
  32. let arrlist = list.filter(it=>it.spaceType==14);//花园的空间
  33. this.loaderCommonSpace(this.gltfSpace1Url,arrlist,2);
  34. },
  35. loaderCommonSpace(gltfSpaceUrl,list,type=1){
  36. var that = this;
  37. this.loader.load(gltfSpaceUrl, ( gltf ) => {
  38. console.log("地板模型加载成功",list)
  39. // gltf.scene.receiveShadow = true;//材质是否接收阴影
  40. gltf.scene.traverse((child)=> {
  41. if (child.isMesh && child.visible) {
  42. let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), list.length);
  43. this.instancedSpaceMeshList.push(instancedMesh);
  44. //设置每一块地板的实例值
  45. list.forEach((obj,i)=>{
  46. let positionX = obj.centerX / 100;
  47. let positionY = obj.centerY / 100;
  48. if(type==1){
  49. // glbWidth = glbHeight = 1500;
  50. }
  51. let scaleX = obj.spaceWidth / glbWidth;
  52. let scaleY = obj.spaceHeight / glbHeight;
  53. gltf.scene.position.set(positionX, 0, -positionY);
  54. gltf.scene.scale.set(scaleX, 1, scaleY);
  55. gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了
  56. instancedMesh.setMatrixAt(i, child.matrixWorld);
  57. instancedMesh.instanceMatrix.needsUpdate = true;
  58. instancedMesh.setColorAt(i, child.material.color);
  59. instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
  60. let gltfSpace = that.gltfSpaces.find(gltfSpace=>gltfSpace.spaceId == obj.spaceId);//判断是否已经添加过
  61. if(!gltfSpace){
  62. let position = new THREE.Vector3();//当前几何体的位置参数
  63. let scale = new THREE.Vector3();//当前几何体的缩放参数
  64. position.set(positionX, 0, -positionY);
  65. scale.set(scaleX, 1, scaleY);
  66. let md = {
  67. spaceId:obj.spaceId,//模型实例的唯一标识
  68. instancedMeshIndexList:[//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号
  69. {instancedMeshIndex: this.instancedSpaceMeshList.length - 1, instancedAtIndex : i},
  70. ],
  71. spaceName:obj.spaceName,//几何体的id
  72. spaceType:obj.spaceType,
  73. position:position,
  74. scale:scale,
  75. isSizeLock:obj.isSizeLock,
  76. };
  77. that.gltfSpaces.push(md);
  78. }else{//添加另外一组实例
  79. gltfSpace.instancedMeshIndexList.push({
  80. instancedMeshIndex:this.instancedSpaceMeshList.length - 1, instancedAtIndex:i
  81. })
  82. }
  83. })
  84. instancedMesh.userType = "mesh";
  85. if(type==2){//花园
  86. instancedMesh.name = "花园";
  87. }else{//室内
  88. instancedMesh.name = "地板";
  89. }
  90. instancedMesh.receiveShadow = true;//材质是否接收阴影
  91. that.scene.add(instancedMesh);
  92. }
  93. });
  94. // this.pvCurPageName=="room_show"
  95. if(true){
  96. //给地板模型添加天花板
  97. list && list.forEach(obj=>{
  98. if(obj.spaceType!=14){//花园不加上面的墙
  99. let positionX = obj.centerX / 100;
  100. let positionY = obj.centerY / 100;
  101. // 天花板
  102. const planeGeometry = new THREE.PlaneGeometry(obj.spaceWidth / 100,obj.spaceHeight / 100);
  103. const planeMaterial = new THREE.MeshStandardMaterial({
  104. color:0xffffff,
  105. metalness: 0.4, // 设置金属度为1.0
  106. roughness: 1 // 设置粗糙度为0.5
  107. });
  108. const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
  109. planeMesh.rotation.x = Math.PI / 2 ; // 旋转 180 度
  110. planeMesh.position.set(positionX, 2.8, -positionY);
  111. planeMesh.userType = "mesh";
  112. that.scene.add(planeMesh);
  113. }
  114. })
  115. }
  116. });
  117. },
  118. //修改当前空间的面积大小
  119. changeSpacesAnimOld(curSpace){
  120. // 寻找地板
  121. const cube = this.gltfSpaces.find((item)=>{
  122. return item.spaceId == curSpace.spaceId;
  123. })
  124. console.log("空间移动目标",cube.spaceId, JSON.stringify(cube.position),JSON.stringify(cube.scale),curSpace.toScaleX, curSpace.toScaleZ, curSpace.toPx, curSpace.toPz);
  125. //获取地板模型的geometry实例
  126. cube.instancedMeshIndexList.forEach(instanced=>{
  127. let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
  128. let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
  129. let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
  130. instancedMesh.getMatrixAt(instanced.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  131. let endMatrix = stratMatrix.clone();//复制一个四维矩阵
  132. let scaleMatrix = new THREE.Matrix4();//定义一个缩放变化矩阵
  133. let panMatrix = new THREE.Matrix4();//定义一个平移变化矩阵
  134. scaleMatrix.makeScale(curSpace.toScaleX / cube.scale.x,1,curSpace.toScaleZ / cube.scale.z); //获得缩放变化矩阵
  135. panMatrix.makeTranslation(curSpace.toPx - cube.position.x,0,curSpace.toPz - cube.position.z); //获得平移变化矩阵
  136. endMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的矩阵
  137. // console.warn("***drawModel-isAnimate-space***",JSON.stringify(endMatrix1),JSON.stringify(endMatrix),JSON.stringify(stratMatrix));
  138. var tween = new TWEEN.Tween(stratMatrix.elements)
  139. .to(endMatrix.elements, 2000)
  140. .easing(TWEEN.Easing.Quadratic.InOut)
  141. .onUpdate((matrixWorld)=> {
  142. let m4 = new THREE.Matrix4();//定义一个四维矩阵
  143. m4.set(...matrixWorld);//注意:四维矩阵的显示和实际计算的行列优先规则不同
  144. instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
  145. instancedMesh.setMatrixAt(instanced.instancedAtIndex,m4.transpose());//更新几何体的世界矩阵
  146. }).onComplete(()=>{
  147. instancedMesh.setMatrixAt(instanced.instancedAtIndex,endMatrix);//更新几何体的世界矩阵
  148. this.tweenCameraAnmaChange(false)
  149. });
  150. // 开始动画
  151. tween.start();
  152. this.tweenCameraAnmaChange(true)
  153. cube.position.x = curSpace.toPx;
  154. cube.position.z = curSpace.toPz;
  155. cube.scale.x = curSpace.toScaleX;
  156. cube.scale.z = curSpace.toScaleZ;
  157. });
  158. },
  159. //修改当前空间的面积大小-动画方案2
  160. changeSpacesAnim(curSpace){
  161. // 寻找地板
  162. const cube = this.gltfSpaces.find((item)=>{
  163. return item.spaceId == curSpace.spaceId;
  164. })
  165. console.log("空间移动目标",cube.spaceId, JSON.stringify(cube.position),JSON.stringify(cube.scale),
  166. curSpace.toPx, curSpace.toPz,curSpace.toScaleX, curSpace.toScaleZ);
  167. //初始形变值
  168. let x = cube.position.x;
  169. let z = cube.position.z;
  170. let scaleX = cube.scale.x;
  171. let scaleZ = cube.scale.z;
  172. //最终形变值
  173. let toPx = curSpace.toPx;
  174. let toPz = curSpace.toPz;
  175. let toScaleX = curSpace.toScaleX;
  176. let toScaleZ = curSpace.toScaleZ;
  177. let spaceInitMatrix = [];//空间动画时的初始变换矩阵
  178. cube.instancedMeshIndexList.forEach(instanced=>{
  179. let _index = instanced.instancedMeshIndex;//geometry实例 在 全局InstancedMesh实例的位置
  180. let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
  181. let startMatrix = new THREE.Matrix4();//定义一个四维矩阵
  182. instancedMesh.getMatrixAt(instanced.instancedAtIndex,startMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  183. spaceInitMatrix.push({
  184. index:_index,
  185. matrix:startMatrix.clone(),
  186. color:instancedMesh.material.color.clone(),
  187. })
  188. });
  189. // console.warn("***cube***",cube.spaceId,Date.now(),JSON.stringify(spaceInitMatrix[0].matrix))
  190. var tween = new TWEEN.Tween({
  191. x: cube.position.x,
  192. z: cube.position.z,
  193. sx:cube.scale.x,
  194. sz:cube.scale.z
  195. })
  196. .to({
  197. x: curSpace.toPx,
  198. z: curSpace.toPz,
  199. sx:curSpace.toScaleX,
  200. sz:curSpace.toScaleZ
  201. }, 2000)
  202. .easing(TWEEN.Easing.Quadratic.InOut)
  203. .onUpdate((object)=> {
  204. //获取地板模型的geometry实例
  205. cube.instancedMeshIndexList.forEach(instanced=>{
  206. let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
  207. let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
  208. //获取对象实例的初始变换矩阵
  209. let tmp = spaceInitMatrix.find(it=>it.index==_index);
  210. let stratMatrix = tmp.matrix.clone(); //获取初始变换矩阵
  211. let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵
  212. let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵
  213. scaleMatrix.makeScale(object.sx / scaleX,1,object.sz / scaleZ); //获得缩放变化矩阵
  214. panMatrix.makeTranslation(object.x - x,0,object.z - z); //获得平移变化矩阵
  215. stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵
  216. instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
  217. instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵
  218. if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才变化颜色
  219. instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
  220. let color = new THREE.Color(0xFF9F40); // 使用sRGB颜色值
  221. // color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值
  222. instancedMesh.setColorAt(instanced.instancedAtIndex, color);//修改这个几何体的颜色
  223. }
  224. });
  225. }).onComplete(()=>{//这个回调很可能会很慢
  226. this.tweenCameraAnmaChange(false);
  227. console.warn("***changeSpacesAnim-over***")
  228. if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才恢复颜色
  229. cube.instancedMeshIndexList.forEach(instanced=>{
  230. let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局Instance
  231. let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
  232. let tmp = spaceInitMatrix.find(it=>it.index==_index);
  233. instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
  234. instancedMesh.setColorAt(instanced.instancedAtIndex, tmp.color);//修改这个几何体的颜色
  235. });
  236. }
  237. });
  238. // 开始动画
  239. tween.start();
  240. this.tweenCameraAnmaChange(true)
  241. cube.position.x = curSpace.toPx;
  242. cube.position.z = curSpace.toPz;
  243. cube.scale.x = curSpace.toScaleX;
  244. cube.scale.z = curSpace.toScaleZ;
  245. },
  246. //所有空间整体缩放-同时同步到数据里面
  247. allSpaceScale(){
  248. const centerOffset = new THREE.Vector3(0, 0, 0); // 假设中心点在几何体的正中心
  249. const scale = new THREE.Vector3(0.9, 1, 0.9); // 缩放尺度
  250. //实例化的默认中心是就原点也就是0 0 0 这个点,所以centerOffset也必须是原点
  251. // this.instancedMeshList.forEach((mesh)=>{
  252. // mesh.scale.copy(scale);
  253. // mesh.updateMatrix();
  254. // mesh.updateMatrixWorld();
  255. // mesh.updateMorphTargets();
  256. // mesh.geometry.computeVertexNormals();
  257. // })
  258. // this.instancedSpaceMeshList.forEach((mesh)=>{
  259. // mesh.scale.copy(scale);
  260. // mesh.updateMatrix();
  261. // mesh.updateMatrixWorld();
  262. // mesh.updateMorphTargets();
  263. // mesh.geometry.computeVertexNormals();
  264. // })
  265. // this.gltfLayouts.forEach((mesh)=>{
  266. // // mesh.scale.copy(scale);
  267. // })
  268. this.gltfSpaces.forEach(cube=>{
  269. let dis = centerOffset.clone().sub(cube.position);//获得差值向量
  270. // console.warn("***dis***",JSON.stringify(dis),JSON.stringify(cube.position),cube.spaceId);
  271. let x = dis.x * (1 - scale.x);//x轴需要移动的距离
  272. let y = dis.y * (1 - scale.y);//y轴需要移动的距离
  273. let z = dis.z * (1 - scale.z);//z轴需要移动的距离
  274. let pi = new THREE.Vector3();//新的中心点位置
  275. pi.x = cube.position.x + x;
  276. pi.y = cube.position.y + y;
  277. pi.z = cube.position.z + z;
  278. cube.scale.x = cube.scale.x * scale.x;//修改真实的比例
  279. cube.scale.z = cube.scale.z * scale.z;//
  280. cube.position.copy(pi);
  281. //同步信息到空间列表中
  282. let sapce = this.spaceList.find(it=>{ return it.spaceId==cube.spaceId});
  283. if(sapce){
  284. //更新空间中心点值
  285. sapce.centerX = pi.x * 100;
  286. sapce.centerY = -1* pi.z * 100;
  287. //更新空间宽度高度值
  288. sapce.spaceWidth = cube.scale.x * glbWidth;
  289. sapce.spaceHeight = cube.scale.z * glbHeight;
  290. }
  291. // let dir = new THREE.Vector3( 0, 10, 0 );;//当前几何体的位置参数
  292. // console.warn("***dis1***",JSON.stringify(pi),JSON.stringify(dir));
  293. // let length = 3;
  294. // let hex = 0xff0000;
  295. // let arrowHelper = new THREE.ArrowHelper( dir, pi, length, hex );
  296. // this.scene.add( arrowHelper );
  297. //这是矩阵运算处理缩放的方法-此为数学上的方案
  298. cube.instancedMeshIndexList.forEach(instanced=>{
  299. let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
  300. let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
  301. let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
  302. instancedMesh.getMatrixAt(instanced.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  303. let scaleMatrix = new THREE.Matrix4().makeScale(scale.x, scale.y, scale.z);
  304. let inverseTranslationMatrix = new THREE.Matrix4().makeTranslation(x, y, z);
  305. stratMatrix.premultiply(inverseTranslationMatrix);
  306. stratMatrix.multiply(scaleMatrix);
  307. instancedMesh.instanceMatrix.needsUpdate = true;
  308. instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵
  309. });
  310. })
  311. this.$nextTick(()=>{
  312. this.updateAllWallHandle();
  313. })
  314. setTimeout(() =>{
  315. this.updataPageData();//更新数据到各个对象里面
  316. this.calculateLayoutModelSize();//重新计算家具位置
  317. this.updateLables();//更新lable
  318. this.$nextTick(()=>{
  319. this.updateCareFul();//更新精细调整里面的空间
  320. this.updateSpanceData();//更新语音组件里面的空间
  321. })
  322. }, 100);
  323. }
  324. }
  325. }