webglCom.vue 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. <template src="./webglCom.html">
  2. </template>
  3. <script>
  4. import * as THREE from 'three';
  5. // import Stats from 'three/addons/libs/stats.module.js';
  6. import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
  7. import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
  8. import spaceTypes from '@/static/spaceTypesIE.js';
  9. import TWEEN from 'three/addons/libs/tween.module.js';
  10. import router from "@/router";
  11. import {setStorage,getStorage} from '@/utils/localStorage';
  12. import wallType from '@/static/wallData.js';
  13. import screenshot from '@/mixins/screenshot.js';
  14. import floorMethod from '@/mixins/floorMethod.js';
  15. import wallMethod from '@/mixins/wallMethod.js';
  16. import loadModel from '@/mixins/loadModel.js';
  17. // import commonPageMethod from '@/mixins/commonPageMethod.js';
  18. // import viewShell from'@/components/newBottomCom/viewShell/viewShell.vue';
  19. var requestId = "";
  20. const util = require('@/utils/util.js').default;
  21. export default {
  22. name:"webglComponent",
  23. mixins:[screenshot,floorMethod,wallMethod,loadModel],
  24. data: function() {
  25. return {
  26. spaceList:[], // 空间列表
  27. spaceListBackup:[], // 空间列表原始尺寸备份,用于墙体比例计算
  28. tempSpaceList:[], // 全部空间临时数组,寻找关联空间,递归使用
  29. gltfSpaces:[], // 场景中地板模型数组
  30. gltfSpaceRoofs:[], // 屋顶模型数组
  31. curSpaceObj:null, // 当前选中的空间
  32. curWallDirection:"", // 当前选中的墙面
  33. curWallValue:0, // 当前墙面的滑动值
  34. curWallMaxValue:300, // 当前墙体形变的最大值
  35. curWallHidden:false, // 当前墙面的状态
  36. wallIds:[], // 当前户型下所有空间墙体id的数组
  37. wallList:[], // 当前户型下所有空间的墙体数据
  38. gltfWalls:[], // 当前户型下所有空间的墙体模型(webgl几何体模型)数组
  39. gltfAutoWalls:[],// 空间自动补墙模型数组
  40. layoutIds:[], // 当前户型下所有空间的布局id数组
  41. leftSpaces:[], // 移动空间左边数组
  42. rightSpaces:[],// 移动空间右边数组
  43. changeSpaces:[],// 尺寸变化涉及到的全部空间
  44. spaces1 : [], //相对核心点的四个象限数组对象
  45. spaces2 : [], //相对核心点的四个象限数组对象
  46. spaces3 : [], //相对核心点的四个象限数组对象
  47. spaces4 : [], //相对核心点的四个象限数组对象
  48. loader:null, //webgl相关对象
  49. scene:null,
  50. sky:null,
  51. camera:null,
  52. controlStarPosition : { x:0, y:0, z:0}, //控制器初始位置
  53. cameraStarPosition : { x:0, y:20, z:0} ,//摄像头初始位置
  54. canvas:null, //webgl的画布对象
  55. lastCanvasHeight:200,
  56. canvasHeight:200, //canvas视图的高度-计算得出
  57. chooseMesh:null, //标记鼠标拾取到的空间模型对象-webgl几何体mesh
  58. instancedMeshList: [], // webgl墙体模型的实例化数组对象-相同mesh只会实例化一个
  59. instancedSpaceMeshList: [],// webgl空间模型的实例化数组对象-相同mesh只会实例化一个
  60. curLayoutStruct:null,//当前户型大类下所有楼层数据-户型存在多层结构时使用
  61. // houseList:[], //当前项目下所有户型数据(以户型类型分组)-户型存在多层结构时使用
  62. // curHouseType: null, //当前选中的户型类型-户型存在多层结构时使用 数字 1、2、3等区分
  63. // curHouseName:'', //当前选中的户型类型名称-户型存在多层结构时使用 例如:大平层、大庭院
  64. curHouseFloor: null,//当前选中的户型楼层数-户型存在多层结构时使用 1F等
  65. curHouseObj: null, //当前选中的户型具体楼层的数据对象-户型存在多层结构时使用
  66. gltfLayouts:[], // 场景中家具模型的对象数组
  67. shottingImg: '', //截图
  68. progress:1, //进度条
  69. repeatFlag:false, //防止重复点击
  70. lableItem:[], //空间悬浮tips数组
  71. showLables:false, //是否显示空间悬浮tips
  72. screenshotResolve:null,//截图条件成熟后的异步回调
  73. overChange:false, //是否形变中,true 表示空间正在形变中
  74. currentChangeSpaceId:null, //当前变化中的空间id-页面依据这个有细微提示或者变化
  75. isIOS:false, //是否ios手机。默认不是
  76. styleType:1, //页面状态-本组件不需要用到这个状态
  77. sumArea:0, //总面积
  78. changeArea:0, //当次变化的面积
  79. fixedArea:0, //初始面积值
  80. layoutArea:0, //总面积
  81. houseId:'',
  82. showArea:true, //显示面积
  83. circleGroup:null,//圆形地标
  84. showWebgl:true,
  85. }
  86. },
  87. props: {
  88. },
  89. watch:{
  90. curSpaceObj(newVal, oldVal) {
  91. console.log("当前空间数据webglCom-watch:", newVal);
  92. if (newVal == null) {
  93. return;
  94. }
  95. },
  96. },
  97. computed: {
  98. aiData() {
  99. return this.$store.state.aiData;
  100. },
  101. userId() {
  102. return this.$store.state.userId;
  103. },
  104. },
  105. async mounted() {
  106. console.warn("***webglCom***",this.$route.query,this.$route.name);
  107. if(this.$route.name=="webgl_rxdz" || this.$route.name=="webgl_rxdz_roam" || this.$route.name=="webgl_rxdz_look"
  108. || this.$route.name=="webgl_rxdz_test" || this.$route.name=="webgl_rxdz_test_roam" || this.$route.name=="webgl_rxdz_test_look"){//去往其他页面
  109. this.showWebgl = true;//隐藏webgl
  110. }else{
  111. this.showWebgl = false;//隐藏webgl
  112. }
  113. var that = this;
  114. let isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  115. this.isIOS = isIOS;
  116. this.houseId = this.$store.state.houseId || '';
  117. let screenWidth = window.screen.width;
  118. let screenHeight = window.screen.height;
  119. if(window.innerWidth && window.screen.width){
  120. screenWidth = Math.min(window.innerWidth,window.screen.width)
  121. }
  122. if(window.innerHeight && window.screen.height){
  123. screenHeight = Math.min(window.innerHeight,window.screen.height)
  124. }
  125. let unit = screenWidth / 750;//单位rpm 对应 px 的值
  126. this.canvasHeight = screenHeight - (200 * unit) + (20 * unit);
  127. this.lastCanvasHeight = this.canvasHeight;
  128. let container = that.$refs.webgl;
  129. let canvas3d = that.canvas = that.$refs.glcanvas;
  130. let camera = null, renderer = null, controls= null;
  131. let loader = that.loader = new GLTFLoader();
  132. let scene = that.scene = new THREE.Scene();
  133. let chooseMesh = that.chooseMesh;//标记鼠标拾取到的mesh
  134. let isUserContorl = false; //是否漫游状态 false不是
  135. let tweenCameraAnma = false; //表示当前是否处在动画过程中
  136. let needRender = false; //是否需要渲染 false表示不需要渲染;true 表示需要渲染
  137. let frustumSize = 30;//正交相机的视窗宽度距离
  138. let stats;//安卓时的资源情况
  139. let raycaster = null;
  140. let mouse = new THREE.Vector2();
  141. //空间漫游时变量
  142. let onPointerDownMouseX = 0, onPointerDownMouseY = 0,lon = 0,startTime = 0,boundary=null;
  143. let light = null;//平行光的
  144. // let lastPosition = null;
  145. this.progress = 1;
  146. this.clearEvent = clearEvent;
  147. this.attendEvent = attendEvent;
  148. this.updateLables = updateLables;
  149. // this.enableRenderHandle = enableRender;
  150. this.tweenCameraAnmaChange = tweenCameraAnmaChange;
  151. this.gradientResize = gradientResize;
  152. this.moveMeshCenterHandle = moveMeshCenterHandle;
  153. this.starRender = starRender;//对外暴露启动渲染的方法
  154. this.stopRender = stopRender;//对外暴露停止渲染的方法
  155. this.cameraInit = cameraInit;
  156. // this.resetControl = resetControl;
  157. this.setHeight = setHeight;
  158. this.enterRoom = enterRoom;
  159. this.leaveRoom = leaveRoom;
  160. this.positionCamer = positionCamer;
  161. this.saveState = saveState;
  162. this.reset = reset;
  163. init();
  164. function init(){
  165. scene.background = new THREE.Color("#FFFFFF");
  166. // scene.environment = new THREE.Color("#F2F2F2");
  167. // 创建相机位置-投影相机
  168. camera = new THREE.PerspectiveCamera( 80, screenWidth / that.canvasHeight, 0.1, 10000 );
  169. // let aspect = screenWidth / that.canvasHeight;
  170. // camera = new THREE.OrthographicCamera( frustumSize * aspect / - 2, frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, 0.1,1000);
  171. camera.up.set(0, 1, 0);//俯视状态,将相机的up向量设置为z轴负方向
  172. scene.add(camera);
  173. that.camera = camera;
  174. // 环境光会均匀的照亮场景中的所有物体
  175. const ambientLight = new THREE.AmbientLight(0xFFEFE0, 3);
  176. scene.add(ambientLight);
  177. //平行光
  178. light = new THREE.DirectionalLight(0xFFF8E5, 3);
  179. light.position.set(-3, 9, 3); //default; light shining from top
  180. if(!that.isIOS){
  181. light.castShadow = true; // default false
  182. // 默认情况下光投影相机区域是一个长宽高为10x10x500的长方体区域,光源投射方向为通过坐标原点
  183. light.shadow.camera.left = -100; // 这个区域内产生阴影
  184. light.shadow.camera.right = 100; // 这个区域内产生阴影
  185. light.shadow.camera.top = 100; // 这个区域内产生阴影
  186. light.shadow.camera.bottom = -100; // 这个区域内产生阴影
  187. light.shadow.mapSize.width = 8192; // 影响阴影的清晰度
  188. light.shadow.mapSize.height = 8192; // 影响阴影的清晰度
  189. }
  190. scene.add(light);
  191. //antialias 这个值得设置为false,不然IOS上截图会失效
  192. renderer = that.renderer = new THREE.WebGLRenderer({
  193. canvas:canvas3d,
  194. alpha: true,
  195. antialias:false,
  196. // 如果想保存three.js canvas画布上的信息,注意设置preserveDrawingBuffer
  197. preserveDrawingBuffer: true,
  198. });
  199. if(!that.isIOS){
  200. renderer.shadowMap.enabled = true;//产生阴影
  201. renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 阴影属性
  202. }
  203. renderer.outputEncoding = THREE.sRGBEncoding;
  204. renderer.outputColorSpace = THREE.SRGBColorSpace;
  205. // renderer.toneMappingExposure = 0.1;//色调映射的曝光级别。默认是1
  206. renderer.toneMapping = THREE.NoToneMapping;//色调映射
  207. renderer.physicallyCorrectLights = true;//关键参数,模拟物理光照影响,必须设置为true
  208. renderer.setPixelRatio( window.devicePixelRatio );
  209. renderer.setSize( screenWidth, that.canvasHeight );
  210. container.appendChild( renderer.domElement );
  211. controls = new OrbitControls(camera, renderer.domElement);
  212. controls.screenSpacePanning = false;//设置为false,则双指平移时是不会翻转垂直的
  213. controls.enableDamping = true;
  214. controls.minDistance = 1;
  215. controls.maxDistance = 400;
  216. controls.minPolarAngle = 0;// 默认0
  217. controls.maxPolarAngle = Math.PI / 2; // 默认Math.PI,即可以向下旋转到的视角。
  218. controls.target.set(that.controlStarPosition.x, that.controlStarPosition.y, that.controlStarPosition.z);
  219. controls.enableZoom = true;//启用摄像机的缩放
  220. // stats = new Stats();
  221. // container.appendChild(stats.dom);
  222. // stats.domElement.style.top = '100px';
  223. attendEvent(); //注册监听事件
  224. starRender(); //启动渲染
  225. cameraInit(); //初始化摄像头
  226. // controls.saveState();//保存当前控制器的状态
  227. }
  228. function saveState(){
  229. controls.saveState();//保存当前控制器的状态
  230. }
  231. function reset(){
  232. controls.reset();//保存当前控制器的状态
  233. }
  234. //添加状态位置
  235. function addStatus(name){
  236. let position = new THREE.Vector3();
  237. position.copy(camera.position);
  238. let _data = {
  239. name:name,
  240. position:position,
  241. }
  242. }
  243. //初始化相机位置
  244. function cameraInit(){
  245. camera.position.set(that.cameraStarPosition.x, that.cameraStarPosition.y, that.cameraStarPosition.z);
  246. camera.lookAt(that.controlStarPosition.x,that.controlStarPosition.y,that.controlStarPosition.z);
  247. controls.target.set(that.controlStarPosition.x, that.controlStarPosition.y, that.controlStarPosition.z);
  248. }
  249. //初始状态-
  250. // function resetControl(){
  251. // controls.reset();
  252. // }
  253. function onWindowResize() {
  254. camera.aspect = screenWidth / that.canvasHeight;
  255. camera.updateProjectionMatrix();
  256. renderer.setSize( screenWidth, that.canvasHeight );
  257. console.warn("****onWindowResize**")
  258. }
  259. function attendEvent () {
  260. window.addEventListener('resize', onWindowResize);
  261. }
  262. function setHeight(height){
  263. that.canvasHeight = height;//变更canvas的高度
  264. camera.aspect = screenWidth / that.canvasHeight;
  265. camera.updateProjectionMatrix();
  266. renderer.setSize(screenWidth, that.canvasHeight);
  267. }
  268. function enterRoom(){
  269. // 监听相机移动事件-限制只能在当前空间范围内移动
  270. that.lastCanvasHeight = that.canvasHeight;//记录下当前的canvas的高度
  271. that.canvasHeight = screenHeight - (600 * unit) + (40 * unit);//变更canvas的高度
  272. camera.aspect = screenWidth / that.canvasHeight;
  273. camera.updateProjectionMatrix();
  274. renderer.setSize(screenWidth, that.canvasHeight);
  275. raycaster = new THREE.Raycaster();
  276. controls.addEventListener('change', onControlChange,false);
  277. renderer && renderer.domElement && renderer.domElement.addEventListener('touchstart', onPointerStart, false);
  278. renderer && renderer.domElement && renderer.domElement.addEventListener('touchend', onPointerUp, false);
  279. }
  280. function leaveRoom(type=true){//取消监听的事件
  281. raycaster = null;
  282. that.circleGroup = null;
  283. if(that.lastCanvasHeight&&type){
  284. that.canvasHeight = that.lastCanvasHeight;//还原回去之前的高度
  285. camera.aspect = screenWidth / that.canvasHeight;
  286. camera.updateProjectionMatrix();
  287. renderer.setSize(screenWidth, that.canvasHeight);
  288. }
  289. console.warn("leaveRoom",that.lastCanvasHeight,type);
  290. controls.removeEventListener('change', onControlChange,false);
  291. renderer && renderer.domElement && renderer.domElement.removeEventListener('touchstart', onPointerStart, false);
  292. renderer && renderer.domElement && renderer.domElement.removeEventListener('touchend', onPointerUp, false);
  293. }
  294. function onControlChange(){
  295. // 检查相机位置是否超出边界框
  296. if (boundary && !boundary.containsPoint(camera.position)) {
  297. let clampedPosition = new THREE.Vector3( );
  298. boundary.clampPoint(camera.position,clampedPosition);
  299. if(clampedPosition){
  300. camera.position.copy(clampedPosition);
  301. }
  302. }
  303. }
  304. // 手指移动开始
  305. function onPointerStart(event){
  306. startTime = (new Date()).getTime();
  307. let fingerCount = event.touches.length;//手指个数
  308. console.log('开始触摸事件:',lon,fingerCount,camera.position.y)
  309. if (fingerCount === 1) {
  310. // 只有一个手指时记录当前点的坐标作为平移起始点
  311. onPointerDownMouseX = event.changedTouches[0].clientX;
  312. onPointerDownMouseY = event.changedTouches[0].clientY;
  313. }
  314. }
  315. //触摸结束
  316. function onPointerUp(event) {
  317. let fingerCount = event.touches.length;//手指个数
  318. console.warn("***触摸结束***",fingerCount,startTime)
  319. if(fingerCount==0){
  320. let now = new Date().getTime()
  321. if (Math.abs(event.changedTouches[0].clientX - onPointerDownMouseX) < 10
  322. && Math.abs(event.changedTouches[0].clientY - onPointerDownMouseY) < 10
  323. && (now - startTime) < 300 ){
  324. checkIntersection(event);
  325. }
  326. }
  327. }
  328. //射线检测handle
  329. function checkIntersection(event) {
  330. let x = (event.changedTouches[0].clientX / screenWidth) * 2 - 1;
  331. let y = -(event.changedTouches[0].clientY / that.canvasHeight) * 2 + 1;
  332. mouse.x = x;
  333. mouse.y = y;
  334. //更新射线
  335. raycaster.setFromCamera(mouse, camera);
  336. let intersects = raycaster.intersectObjects(scene.children,true);
  337. console.warn("***checkIntersection***",intersects.length)
  338. if (intersects.length > 0) {
  339. //找到最近的那个网格模型物体
  340. let mesh = intersects.find((it) => {
  341. if(it.object && it.object.isMesh == true
  342. && it.object.parent && it.object.parent.name == 'actor'
  343. && it.object.parent.visible == true){
  344. return true;
  345. }
  346. });
  347. //拾取到了视角,就不继续拾取了
  348. if(mesh){
  349. // moveActor(mesh.object.parent);
  350. return false;
  351. }
  352. mesh = intersects.find((it) => {
  353. if(it.object && it.object.isInstancedMesh
  354. && (it.object.name == '地板' || it.object.name == '花园') && it.object.visible == true){
  355. return true;
  356. }
  357. });
  358. //拾取到了地板
  359. if(mesh){
  360. let floor = mesh.object;
  361. let index = mesh.instanceId;//射线相交是的实例序号
  362. let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
  363. if(floor.name == "花园"){//花园
  364. return false;
  365. let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType==14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
  366. spaceId = selectMesh.spaceId;
  367. }else{//室内
  368. // floor.name = "地板";
  369. let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType!=14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
  370. spaceId = selectMesh.spaceId;
  371. }
  372. // let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
  373. console.warn("***checkIntersection-地板***",floor,index,spaceId,that.curSpaceObj.spaceId)
  374. //当前拾取到的是本空间的底部-意味着用户点击了地板
  375. if(floor && spaceId == that.curSpaceObj.spaceId){
  376. moveCarmer(mesh.point);
  377. return false;
  378. }
  379. }
  380. }
  381. }
  382. function tweenCameraAnmaChange (value) {
  383. tweenCameraAnma = value
  384. }
  385. //开启渲染-帧率优化,不触发时停止渲染
  386. // function enableRender() {
  387. // }
  388. //取消事件监听-避免二次进入时触发多次事件
  389. function clearEvent(){
  390. console.warn("**clearEvent****")
  391. }
  392. function creatMoveTip(position){
  393. if(!that.circleGroup){
  394. that.circleGroup = new THREE.Group();
  395. let geometry = new THREE.CircleGeometry( 0.2, 32 );
  396. let material = new THREE.MeshBasicMaterial( { transparent: true } );
  397. let circle = new THREE.Mesh( geometry, material );
  398. circle.position.set(position.x,0.01,position.z);
  399. circle.rotation.x = -Math.PI / 2;
  400. // 使用贴图
  401. const textureLoader = new THREE.TextureLoader();
  402. textureLoader.load('https://dm.static.elab-plus.com/miniProgram/circlemap1.png', function(texture) {
  403. material.map = texture; // 将贴图应用于材质的map属性
  404. material.needsUpdate = true; // 更新材质
  405. });
  406. that.circleGroup.add(circle);
  407. scene.add(that.circleGroup);
  408. that.circleGroup.visible = false;
  409. }
  410. }
  411. //移动地标
  412. function moveTip(position){
  413. if(!that.circleGroup){
  414. that.circleGroup = new THREE.Group();
  415. let geometry = new THREE.CircleGeometry( 0.2, 32 );
  416. let material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
  417. let circle = new THREE.Mesh( geometry, material );
  418. circle.position.set(position.x,0.01,position.z);
  419. circle.rotation.x = -Math.PI / 2;
  420. // let geometry1 = new THREE.CircleGeometry( 0.4, 32 );
  421. // let circle2 = new THREE.Mesh( geometry1, material );
  422. // circle2.position.set(position.x,0.01,position.z);
  423. that.circleGroup.add(circle);
  424. scene.add(that.circleGroup);
  425. }else{
  426. that.circleGroup.visible = true;
  427. that.circleGroup.children[0].position.set(position.x,0.01,position.z);
  428. }
  429. }
  430. //初始化点位视角
  431. function initActor(){
  432. if(!chooseMesh){
  433. console.error("[drawActor],没有选中的空间数据")
  434. return false;
  435. }
  436. let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
  437. if(!spaceObj.actors){
  438. return false;
  439. }
  440. let defaulIndex = spaceObj.actors.findIndex(it=>it.isSelected==true);
  441. if(defaulIndex == -1){
  442. defaulIndex = 0;
  443. }
  444. // that.actors = [];
  445. spaceObj.actors.forEach((actor,index)=>{
  446. let cube = {};
  447. cube.name = "actor";
  448. cube.userType = "mesh";
  449. //新的摄像机的位置-新的摄像机角度是倾斜角度,所以z值需要计算,高度设置为模型高度的2倍
  450. let _actorLoaction = actor.actorLocation.split(',');//x y z
  451. let _actorTransform = actor.actorTransform.split(',');//旋转角度,取第三个值
  452. let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]));//将度转化为弧度。
  453. let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
  454. let X_C = parseInt(_actorLoaction[0]);//X轴偏移量
  455. let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反,UE里面的Y轴方向跟Three.js相反
  456. let px = spaceObj.centerX + X_C;
  457. let py = -spaceObj.centerY + Y_C;//UE里面的centerY值跟Three.js Y轴相反;获得真实的坐标值
  458. let position = {
  459. x:(parseInt(px))/100,
  460. y:1.5,
  461. z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
  462. }
  463. //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为1.5
  464. let targetNewPosition = {
  465. x:position.x + Math.sin(_hd),
  466. y:1.5 + Math.tan(_hdY),
  467. z:(position.z - Math.cos(_hd)),
  468. }
  469. cube.position = position;
  470. cube.userIndex = index;
  471. cube.actorEum = index;
  472. cube.targetNewPosition = targetNewPosition;
  473. // console.warn("*actors*",cube,defaulIndex)
  474. // that.actors.push(cube);//添加视角
  475. if(index == defaulIndex){//隐藏当前视角
  476. // that.currentActor = cube;//记录下当前的视角对象 mesh网格模型
  477. let param = {
  478. type: 'CLK', //埋点类型
  479. clkId: 'clk_2cmina_23080411', //点击ID
  480. clkName: 'visualangle_clk', //点击前往的页面名称
  481. clkParams: {
  482. locusName: "预制视角",
  483. type:cube.actorEum
  484. }
  485. };
  486. util.trackRequest(param);
  487. }
  488. })
  489. }
  490. //移动到选中的位置-地板
  491. function moveCarmer (point) {
  492. //还在动画中,不能点击切换
  493. if(tweenCameraAnma == true){
  494. return false;
  495. }
  496. let _x = point.x - camera.position.x;//x轴移动的距离
  497. let _z = point.z - camera.position.z;//z轴移动的距离
  498. let cameraNewPosition = {x:camera.position.x + _x,y:1.5,z:camera.position.z + _z};
  499. let targetNewPosition = {x:controls.target.x + _x,y:1.5,z:controls.target.z + _z};
  500. let oldUp = {x:0,y:1,z:0};
  501. let newUp = {x:0,y:1,z:0};
  502. moveTip(cameraNewPosition)
  503. // console.warn("**moveCarmer***",lon,JSON.stringify(cameraNewPosition),JSON.stringify(targetNewPosition))
  504. tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
  505. setTimeout(()=> {
  506. that.circleGroup.visible = false;
  507. }, 2000);
  508. }
  509. //计算当前选中空间的平视时的观察点和摄像机的放置点位
  510. function roamPositionHandle(lon=''){
  511. if(!chooseMesh){
  512. console.error("[roamPositionHandle],没有选中的空间数据")
  513. return false;
  514. }
  515. let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
  516. //获取视角
  517. let defaultActor = null;
  518. if(spaceObj.actors && spaceObj.actors.length>0){
  519. defaultActor = spaceObj.actors.find(it=>it.isSelected==true);
  520. if(!defaultActor){
  521. defaultActor = spaceObj.actors[0];
  522. }
  523. }
  524. let _actorLoaction = defaultActor.actorLocation.split(',');//x y z
  525. let _actorTransform = defaultActor.actorTransform.split(',');//旋转角度,取第三个值
  526. let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]) + lon);//将度转化为弧度。
  527. let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
  528. let X_C = parseInt(_actorLoaction[0]);//X轴偏移量-UE原因
  529. let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反,UE里面的Y轴方向跟Three.js相反
  530. let px = spaceObj.centerX + X_C;
  531. let py = -spaceObj.centerY + Y_C;
  532. //新的摄像机的位置-新的摄像机角度是倾斜角度,所以z值需要计算,高度设置为模型高度的2倍
  533. let cameraNewPosition = {
  534. x:(parseInt(px))/100,
  535. y:1.5,
  536. z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
  537. }
  538. if(cameraNewPosition){
  539. let minX = 0,maxX = 0,minY = 0,maxY = 0;//0.1 是模型墙壁厚度
  540. minX = (spaceObj.centerX - (spaceObj.spaceWidth/2))/100 + 0.1;
  541. maxX = (spaceObj.centerX + (spaceObj.spaceWidth/2))/100 - 0.1;
  542. maxY = ((-spaceObj.centerY + (spaceObj.spaceHeight/2))/100 - 0.1);
  543. minY = ((-spaceObj.centerY - (spaceObj.spaceHeight/2))/100 + 0.1);
  544. //新的坐标轴不在房间范围内,则不能移动
  545. if(cameraNewPosition.x<minX || cameraNewPosition.x>maxX
  546. ||cameraNewPosition.z<minY || cameraNewPosition.z>maxY){//不在房间范围
  547. let _x = ((spaceObj.spaceWidth/2) - 15)*defaultActor.presentX + spaceObj.centerX;
  548. let _z = ((spaceObj.spaceHeight/2) - 15)*defaultActor.presentY + (-spaceObj.centerY);
  549. cameraNewPosition.x = _x/100;
  550. cameraNewPosition.z = _z/100;
  551. console.warn("**roamPositionHandle-观察点不在空间范围-强制修正观察点位置****",JSON.stringify(cameraNewPosition))
  552. }
  553. }
  554. //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为1.5
  555. let targetNewPosition = {
  556. x:cameraNewPosition.x + Math.sin(_hd),
  557. y:1.5 + Math.tan(_hdY),
  558. z:(cameraNewPosition.z - Math.cos(_hd)),
  559. }
  560. let lookPosition = {
  561. x:cameraNewPosition.x + (Math.sin(_hd)*0.01),
  562. y:1.5 + Math.tan(_hdY),
  563. z:(cameraNewPosition.z - (Math.cos(_hd))*0.01),
  564. }
  565. return {cameraNewPosition,targetNewPosition,lookPosition}
  566. }
  567. //直接定位到摄像头位置
  568. function positionCamer(mesh=null,needAni=false){
  569. if(mesh){//如果传入了模型,则取模型
  570. chooseMesh = mesh;
  571. }
  572. if(!chooseMesh){
  573. console.error("[positionCamer],没有选中的空间数据")
  574. return false;
  575. }
  576. if(!chooseMesh.actors || chooseMesh.actors.length==0){
  577. chooseMesh.actors = [{
  578. actorLocation:chooseMesh.actorLocation,
  579. actorTransform:chooseMesh.actorTransform,
  580. isSelected:true,
  581. presentX:chooseMesh.presentX,
  582. presentY:chooseMesh.presentY,
  583. }]
  584. }
  585. boundary = new THREE.Box3(
  586. new THREE.Vector3(chooseMesh.centerX/100 - chooseMesh.spaceWidth/100/2 + 0.1, 0, -chooseMesh.centerY/100 - chooseMesh.spaceHeight/100/2 + 0.1), // 边界框的最小点
  587. new THREE.Vector3(chooseMesh.centerX/100 + chooseMesh.spaceWidth/100/2 - 0.1, 2.7, -chooseMesh.centerY/100 + chooseMesh.spaceHeight/100/2 - 0.1) // 边界框的最大点
  588. );
  589. initActor();//初始化空间的视角
  590. let data = roamPositionHandle();
  591. let cameraNewPosition = data.cameraNewPosition;
  592. let targetNewPosition = data.targetNewPosition;
  593. targetNewPosition.z = targetNewPosition.z;//增加偏差,防止极点翻转问题?不知道为啥会有用
  594. let lookPosition = data.lookPosition;
  595. creatMoveTip(cameraNewPosition);//创建移动的地标
  596. if(needAni){
  597. let oldUp = {x:0,y:1,z:0}; //俯视
  598. let newUp = {x:0,y:1,z:0}; //正视
  599. tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
  600. }else{
  601. camera.position.set(cameraNewPosition.x, cameraNewPosition.y, cameraNewPosition.z);
  602. controls.target.set(lookPosition.x,lookPosition.y,lookPosition.z);
  603. // controls.target.set(cameraNewPosition.x,cameraNewPosition.y,cameraNewPosition.z);
  604. // controls.target.copy(camera.position);
  605. camera.lookAt(targetNewPosition.x,targetNewPosition.y,targetNewPosition.z);
  606. }
  607. }
  608. //把摄像机移动的选中模型的正上方,观察点也变更为模型中心点,同时选中模型
  609. function moveMeshCenterHandle(mesh = null,noChangeColor = true){
  610. if(mesh){//如果传入了模型,则取模型
  611. let spaceId = mesh.spaceId;//空间id
  612. // if(chooseMesh && spaceId == chooseMesh.spaceId){
  613. // console.warn("**moveMeshCenterHandle-重复选中了***")
  614. // return false;
  615. // }
  616. chooseMesh = mesh;
  617. }
  618. if(!chooseMesh){
  619. console.warn("**moveMeshCenterHandle-没有数据***")
  620. return false;
  621. }
  622. that.showLables = false;//隐藏
  623. // controls.enable = false;//控制器不响应用户的操作
  624. let spaceObj = chooseMesh;//获取空间模型的相关数据
  625. // controls.panTo(spaceObj.centerX/100, camera.position.y, -spaceObj.centerY/100);
  626. let cameraNewPosition ={};
  627. let targetNewPosition ={};
  628. let oldUp = {};
  629. let newUp = {};
  630. if (isUserContorl === false) { // 非漫游状态
  631. cameraNewPosition = {
  632. x:spaceObj.centerX/100,
  633. y:camera.position.y,
  634. z:-spaceObj.centerY/100 + 0.5,//增加偏差,防止极点翻转问题?不知道为啥会有用
  635. }
  636. //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为0
  637. targetNewPosition = {
  638. x:spaceObj.centerX/100,
  639. y:0,
  640. z:-spaceObj.centerY/100,
  641. }
  642. oldUp = camera.up;//俯视状态
  643. newUp = camera.up;
  644. }
  645. console.warn("**moveMeshCenter***",isUserContorl,spaceObj,
  646. JSON.stringify(camera.position),JSON.stringify(controls.target)
  647. ,cameraNewPosition,targetNewPosition,JSON.stringify(camera.up))
  648. tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,1000);
  649. setTimeout(()=>{
  650. that.showLables = true;
  651. // camera.up = new THREE.Vector3(0,1,0);
  652. // updateLables();
  653. },1001);//动画结束后回复原始状态
  654. }
  655. // oldP 相机原来的位置
  656. // oldT target原来的位置
  657. // newP 相机新的位置
  658. // newT target新的位置
  659. function tweenCamera(oldP, oldT, newP, newT, oldUp, newUp, time=1000) {
  660. if(JSON.stringify(oldP) == JSON.stringify(newP) && JSON.stringify(oldT) == JSON.stringify(newT)){
  661. return false;
  662. }
  663. if (!chooseMesh) {
  664. return false;
  665. }
  666. tweenCameraAnma = true;
  667. var tween = new TWEEN.Tween({
  668. x1: oldP.x, // 相机x
  669. y1: oldP.y, // 相机y
  670. z1: oldP.z, // 相机z
  671. x2: oldT.x, // 控制点的中心点x
  672. y2: oldT.y, // 控制点的中心点y
  673. z2: oldT.z, // 控制点的中心点z
  674. x3: oldUp.x, // 控制点的中心点x
  675. y3: oldUp.y, // 控制点的中心点y
  676. z3: oldUp.z // 控制点的中心点z
  677. })
  678. .to({
  679. x1: newP.x,
  680. y1: newP.y,
  681. z1: newP.z,
  682. x2: newT.x,
  683. y2: newT.y,
  684. z2: newT.z,
  685. x3: newUp.x, // up向量
  686. y3: newUp.y, // 控制点的中心点y
  687. z3: newUp.z // 控制点的中心点z
  688. }, time)
  689. .easing(TWEEN.Easing.Quadratic.InOut)
  690. .onUpdate((object)=> {
  691. camera.position.set(object.x1, object.y1, object.z1);
  692. let newTarget = new THREE.Vector3(object.x3,object.y3,object.z3);
  693. camera.up.copy(newTarget);
  694. camera.lookAt(object.x2,object.y2,object.z2);
  695. }).onComplete(()=>{
  696. controls.target.set(newT.x,newT.y,newT.z);
  697. //修正最后的视角
  698. let up = new THREE.Vector3(newUp.x,newUp.y,newUp.z);
  699. camera.up.copy(up);
  700. camera.lookAt(newT.x,newT.y,newT.z);
  701. tweenCameraAnma = false;
  702. })
  703. // 开始动画
  704. tween.start();
  705. }
  706. //高度持续变化处理 time 动画持续时间 单位秒
  707. function gradientResize (time,startHeight,endHeight) {
  708. let unit = screenWidth / 750;//单位rpx 对应 px 的值
  709. let _height = startHeight - endHeight;//高度变化-单位rpx
  710. let _jisua = that.canvasHeight;
  711. let lastHeight = _jisua + (_height * unit);//动画结束时的高度值; 单位 px
  712. that.canvasHeight = lastHeight;//触发css动画
  713. console.warn("***gradientResize***",lastHeight,_jisua,startHeight,endHeight);
  714. if(window.currentPage){
  715. window.currentPage.canvasHeight = endHeight;
  716. }
  717. // that.showLables = false;
  718. var tween = new TWEEN.Tween({
  719. h1: _jisua,
  720. })
  721. .to({
  722. h1: lastHeight,
  723. }, 1000)
  724. .easing(TWEEN.Easing.Linear.None)
  725. .onUpdate((object)=> {
  726. if(camera.isOrthographicCamera){//正交相机
  727. let aspect = screenWidth / object.h1;
  728. camera.left = frustumSize * aspect / - 2;
  729. camera.right = frustumSize * aspect / 2;
  730. camera.top = frustumSize / 2;
  731. camera.bottom = frustumSize / -2;
  732. camera.updateProjectionMatrix();
  733. // that.canvasHeight = object.h1;
  734. }
  735. else if(camera.isPerspectiveCamera){//透视相机
  736. camera.aspect = screenWidth / object.h1;
  737. camera.updateProjectionMatrix();
  738. renderer.setSize( screenWidth, object.h1 );
  739. // that.canvasHeight = object.h1;
  740. }
  741. }).onComplete(()=>{
  742. camera.aspect = screenWidth / that.canvasHeight;
  743. camera.updateProjectionMatrix();
  744. renderer.setSize( screenWidth, that.canvasHeight );
  745. tweenCameraAnma = false;
  746. });
  747. // 开始动画
  748. tween.start();
  749. tweenCameraAnma = true;
  750. }
  751. //更新lables
  752. function updateLables(){
  753. if(!that.showLables){
  754. return false;
  755. }
  756. that.lableItem.forEach(lable =>{
  757. if(!that.gltfSpaces[lable.cubeIndex] || !that.gltfSpaces[lable.cubeIndex].instancedMeshIndexList){
  758. return false;
  759. }
  760. let item = that.gltfSpaces[lable.cubeIndex].instancedMeshIndexList[0];//获取地板模型的第一个geometry实例
  761. let _index = item.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
  762. let instancedMesh = that.instancedSpaceMeshList[_index];//获取具体的网格实例
  763. let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
  764. instancedMesh.getMatrixAt(item.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  765. let position = new THREE.Vector3();//当前几何体的位置参数
  766. position.setFromMatrixPosition(stratMatrix);//从四维向量中提取位置信息
  767. // console.warn("***updateLables***",item.instancedAtIndex,JSON.stringify(position));
  768. position.project(camera);
  769. const x = (position.x * .5 + .5) * screenWidth;
  770. const y = (position.y * -.5 + .5) * that.canvasHeight;
  771. lable.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
  772. })
  773. }
  774. function stopRender () {
  775. needRender = false;
  776. }
  777. function starRender () {
  778. if(needRender==true){//如果已经在渲染中了,则不能再次开启,避免渲染过多
  779. false;
  780. }
  781. needRender = true;
  782. render();//开始渲染
  783. }
  784. function render() {
  785. if(needRender==false){
  786. return false;
  787. }
  788. TWEEN && TWEEN.update();
  789. // stats.update();
  790. //不处在动画过程中,则可以处理移动等动作
  791. if(tweenCameraAnma==false){
  792. controls.update();
  793. updateLables();//更新lable
  794. }
  795. requestId = requestAnimationFrame(render, canvas3d);
  796. renderer.render(scene, camera);//单次渲染
  797. if (that.screenshotResolve) {
  798. stopRender();
  799. that.screenshotResolve()
  800. that.screenshotResolve = null;//释放Promise
  801. }
  802. }
  803. },
  804. // 页面被展示时执行
  805. onPageShow: function() {
  806. console.warn("***onPageShow-webglCom***")
  807. },
  808. //页面被隐藏时执行
  809. onPageHide: function() {
  810. // console.warn("***detached-hide***")
  811. },
  812. methods: {
  813. setHeight(){},
  814. positionCamer(){},
  815. //户型大类发生了变更-针对多层户型
  816. curHouseTypeChange(item){
  817. //获取当前户型大类下的所有户型信息-用于用户提交
  818. this.curLayoutStruct = item.layoutStruct;
  819. this.curLayoutStruct.forEach(it=>{
  820. this.layoutArea += it.houseArea
  821. })
  822. setStorage('curLayoutStruct', this.curLayoutStruct);//把楼层的数据存入缓存中
  823. console.warn("***curLayoutStruct***",this.curLayoutStruct)
  824. },
  825. clearWebGl(){
  826. let that = this;
  827. let deleList = that.scene && that.scene.children.filter(object=>{
  828. //&& (object.userType=="mesh" || object.userType=="layoutMesh")
  829. if(object instanceof THREE.Mesh || object instanceof THREE.InstancedMesh){
  830. return object
  831. }
  832. })
  833. // console.warn("***deleList***",deleList)
  834. if(deleList && deleList.length>0){
  835. that.showLables = false;//隐藏lable
  836. that.scene.remove(...deleList);
  837. }
  838. // this.scene.traverse(function(object) {
  839. // if (object instanceof THREE.Mesh) {
  840. // if(object.geometry && typeof(object.geometry.dispose)=='function'){
  841. // object.geometry.dispose();
  842. // }
  843. // if(object.material && typeof(object.material.dispose)=='function'){
  844. // object.material.dispose();
  845. // }
  846. // if(object.texture && typeof(object.texture.dispose)=='function'){
  847. // object.texture.dispose();
  848. // }
  849. // object.dispose();
  850. // }
  851. // if (object instanceof THREE.InstancedMesh) {
  852. // if(object.geometry && typeof(object.geometry.dispose)=='function'){
  853. // object.geometry.dispose();
  854. // }
  855. // if(object.material && typeof(object.material.dispose)=='function'){
  856. // object.material.dispose();
  857. // }
  858. // if(object.texture && typeof(object.texture.dispose)=='function'){
  859. // object.texture.dispose();
  860. // }
  861. // object.dispose();
  862. // }
  863. // });
  864. this.progress = 0;
  865. this.gltfWalls = [];
  866. this.gltfSpaces = [];
  867. this.gltfSpaceRoofs = [];
  868. this.gltfAutoWalls = [];
  869. this.instancedMeshList = [];
  870. this.instancedSpaceMeshList = [];
  871. this.instancedFurList = [];
  872. this.lableItem = [];
  873. this.gltfLayouts = [];
  874. this.wallList = [];
  875. this.changeArea = 0;
  876. },
  877. //户型楼层发生了变更-针对多层户型
  878. curHouseFloorChange(item){
  879. let that = this;
  880. this.curHouseFloor = item.houseFloor || 1;//当前选中的户型楼层
  881. this.curHouseObj = item;//更新当前具体的户型数据
  882. if(this.$route.name!="webgl_rxdz_look" && this.$route.name!="webgl_rxdz_test_look"){
  883. this.$store.dispatch('setCurHouseObj', this.curHouseObj);
  884. }
  885. // this.id = this.curHouseObj.id;
  886. // 遍历场景中的所有子对象,找到类型为Mesh的对象并移除
  887. this.clearWebGl();
  888. this.houseInit();
  889. },
  890. //绘制并且渲染当前户型-初始化
  891. houseInit(){
  892. // this.reset();
  893. setTimeout(()=>{
  894. this.loadSpace();//加载户型的空间
  895. }, 100);
  896. console.warn("***curHouseObj***",this.curHouseObj,this.aiData)
  897. // this.navbar.title = this.curHouseObj.name + " " + this.curHouseObj.houseArea + "㎡";
  898. if(window.currentPage && window.currentPage.navbar && window.currentPage.pvCurPageName=='home_show'){
  899. window.currentPage.navbar.title = "空间定制";
  900. document.title = '空间定制';
  901. }
  902. this.sumArea = this.curHouseObj.houseArea || '';
  903. this.fixedArea = this.curHouseObj.houseArea || '';
  904. if(this.curHouseObj.houseArea<=100){//面积小于100平米,则摄像头靠近一点
  905. this.cameraStarPosition.y = 20;
  906. }else if(this.curHouseObj.houseArea>100){
  907. this.cameraStarPosition.y = 30;
  908. }
  909. this.cameraInit();
  910. },
  911. moveMeshCenterIm(houseObj){
  912. const spaceDetail = houseObj;
  913. const spaceList = typeof(spaceDetail.houseJson)=="string" ? JSON.parse(spaceDetail.houseJson) : spaceDetail.houseJson;
  914. let element = this.spaceList[0];
  915. spaceList.forEach(it=>{
  916. if(it.isSelected){ // 默认选中空间
  917. element = it;
  918. }
  919. })
  920. this.moveMeshCenter(element);
  921. },
  922. // 绘制地板
  923. async loadSpace(){
  924. this.spaceList = [];
  925. this.wallIds = [];
  926. this.layoutIds = [];
  927. this.gltfSpaces = [];
  928. this.progress = 0;
  929. if(!this.curHouseObj){//减少重复请求
  930. return false
  931. }
  932. let type=[];
  933. if(this.curHouseObj){
  934. const spaceDetail = this.curHouseObj;
  935. const spaceList = typeof(spaceDetail.houseJson)=="string" ? JSON.parse(spaceDetail.houseJson) : spaceDetail.houseJson;
  936. // 交换centerX, centerY;上一页面已经处理过了,这里不在需要处理
  937. for (let index = 0; index < spaceList.length; index++) {
  938. var element = spaceList[index];
  939. element.wallMoveValue = "[0,0,0,0]"
  940. this.spaceList.push(element);
  941. this.wallIds.push(element.wallId);
  942. this.layoutIds.push(element.layoutId);
  943. type.push(element.spaceType);
  944. if(element.isSelected){ // 默认选中空间
  945. this.curSpaceObj = element;
  946. }
  947. }
  948. if(!this.curSpaceObj && this.spaceList.length > 0){
  949. this.curSpaceObj = this.spaceList[0];
  950. }
  951. }
  952. console.log("该户型空间数据:", this.spaceList, this.layoutIds,type);
  953. console.log("当前选中的空间:", this.curSpaceObj,this.curHouseObj);
  954. let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
  955. let title = this.curSpaceObj.spaceName + " " + curSpaceArea + "㎡";
  956. if(window.currentPage && window.currentPage.navbar && window.currentPage.pvCurPageName=='room_show'){
  957. window.currentPage.navbar.title = title;
  958. document.title = title;
  959. }
  960. this.spaceListBackup = JSON.parse(JSON.stringify(this.spaceList));
  961. this.$store.state.curSpaceId = this.curSpaceObj.spaceId;
  962. this.currentChangeSpaceId = this.curSpaceObj.spaceId;
  963. this.loaderSpaceArr(this.spaceList);
  964. // 绘制墙体
  965. this.getHouseTypeSpaceWalls();
  966. },
  967. // 获取墙体数据
  968. async getHouseTypeSpaceWalls(){
  969. let data = {id:this.wallIds}
  970. const res = await requestConfig('getHouseTypeSpaceWalls', data, true);
  971. console.log("墙体数据:", res.list)
  972. let wallList = [];
  973. if(res.success){
  974. wallList = this.wallList = res.list;
  975. }
  976. let wallArr = []
  977. for (let index = 0; index < wallList.length; index++) {//每个空间对应一个数据
  978. let element = JSON.parse(wallList[index].wallJson);
  979. let space = this.spaceList.find(space=>space.spaceId==element.spaceId);
  980. this.computeWallHandleOld(space,element);//提前计算
  981. for (let i = 0; i < element.wallData.length; i ++) {//对应空间里面的4个方向的墙壁数据
  982. let wallData = element.wallData[i];
  983. //对应方向的墙壁的墙体模型数据列表,每一面墙可能有多个模型
  984. for (let j = 0; j < wallData.wallModelData.length; j ++) {
  985. let wallModelData = wallData.wallModelData[j];
  986. wallArr.push({spaceId:element.spaceId, wallModelData:wallModelData, wallDirection:wallData.wallDirection})
  987. }
  988. }
  989. }
  990. this.loadSpaceObjWalls(wallArr, wallList);
  991. this.getOverallArrangementDetailsList(2);
  992. },
  993. // 加载单个空间墙体资源
  994. async loadSpaceObjWalls(wallArr, wallList){
  995. // 加载远程墙体模型资源
  996. let startTime = new Date().getTime();
  997. // console.log("wallArr:", wallArr)
  998. let promise_list = [];
  999. let realWallArr = this.preWallData(wallArr);
  1000. let arrLength = realWallArr.length;
  1001. realWallArr && realWallArr.forEach((item,index) => {
  1002. promise_list.push(
  1003. new Promise((resolve, reject) => {
  1004. this.loadWallModels(item, wallList, arrLength , resolve);
  1005. })
  1006. )
  1007. });
  1008. Promise.all(promise_list).then(()=>{
  1009. let endTime = new Date().getTime();
  1010. console.log("模型全部加载完成,时间:",endTime - startTime);
  1011. this.progress = 100;
  1012. // 设置空间数组的墙体信息
  1013. // this.setSpaceListWallInfo();
  1014. this.$nextTick(()=>{
  1015. this.moveMeshCenter(this.curSpaceObj);
  1016. // if(this.$route.name!="webgl_rxdz_look" && this.$route.name!="webgl_rxdz_test_look"){
  1017. setTimeout(()=>{
  1018. this.addWordLabel(); // 添加文字标签
  1019. }, 610);
  1020. // }
  1021. // 设置空间数组的墙体信息
  1022. })
  1023. })
  1024. },
  1025. //空间面积等变更后-同步更新其他数据对象
  1026. updataPageData(){
  1027. let sumArea = 0;
  1028. this.spaceList.forEach(space=>{
  1029. let curSpaceArea = parseFloat((
  1030. (space.spaceWidth * space.spaceHeight) * space.spaceRatio / 10000
  1031. ).toFixed(2));
  1032. sumArea +=curSpaceArea;
  1033. })
  1034. this.changeArea = parseFloat((sumArea - this.fixedArea).toFixed(2));
  1035. this.sumArea = parseFloat(sumArea.toFixed(2));
  1036. let str = JSON.stringify(this.spaceList)
  1037. //更新当前空间对象
  1038. this.curHouseObj.houseJson = str;
  1039. this.$store.dispatch('setCurHouseObj', this.curHouseObj);//更新当前户型数据(单层)
  1040. if(this.curLayoutStruct){ //更新提交的数据
  1041. let layoutStruct = this.curLayoutStruct.find(it=>{
  1042. return it.houseFloor == this.curHouseFloor
  1043. })
  1044. if(layoutStruct){
  1045. layoutStruct.houseJson = str;
  1046. }
  1047. setStorage('curLayoutStruct', this.curLayoutStruct);//把楼层的数据存入缓存中
  1048. }
  1049. this.currentChangeSpaceId = null;//变化结束后
  1050. console.warn("***curLayoutStruct-updataPageData***",this.changeArea,this.sumArea,this.curHouseFloor,this.curHouseObj)
  1051. },
  1052. // 添加文字标签
  1053. addWordLabel(){
  1054. if(!this.gltfSpaces || this.gltfSpaces.length <= 0){
  1055. return false;
  1056. }
  1057. // 方案二
  1058. this.lableItem = [];
  1059. this.gltfSpaces.forEach((cube,index) =>{
  1060. // 给地板加上空间类型标注, 空间为链接空间的不显示
  1061. if(cube.spaceName && !cube.isSizeLock){
  1062. let spaceIndex = this.spaceList.filter(it=>it.spaceName && !it.isSizeLock).findIndex(item=>item.spaceId==cube.spaceId);
  1063. let name = spaceTypes[cube.spaceType - 1];
  1064. if(cube.spaceType==15){ //更改空间显示名称 X空间 类型 根据布局所属类型来显示
  1065. let layoutId = this.spaceList.find(it => it.spaceId == cube.spaceId).layoutId;
  1066. let layout = this.arrFrunList.find(it=>it.id == layoutId);
  1067. if(layout){
  1068. name = spaceTypes[layout.type - 1];
  1069. }
  1070. }
  1071. this.lableItem.push(
  1072. {
  1073. text:name,
  1074. spaceId:cube.spaceId,
  1075. spaceType:cube.spaceType,
  1076. transform:'',
  1077. spaceIndex:spaceIndex,
  1078. cubeIndex:index,
  1079. }
  1080. )
  1081. }
  1082. })
  1083. this.showLables = true;
  1084. // this.updateLables();//更新lable
  1085. },
  1086. //AI生成页面切换空间
  1087. changeSpace(spaceId){
  1088. console.warn("***changeSpace***",spaceId,this.curSpaceObj.spaceId)
  1089. if(spaceId == this.curSpaceObj.spaceId){
  1090. return false;
  1091. }
  1092. // this.curSpaceObj = this.spaceList.find(it=>it.spaceId == spaceId);
  1093. // if(this.isIOS){
  1094. // this.furnSingleSpaceHandle(this.curSpaceObj);
  1095. // }
  1096. this.curSpaceSelect(spaceId,false);
  1097. this.positionCamer(this.curSpaceObj,true);
  1098. let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
  1099. let title = this.curSpaceObj.spaceName + " " + curSpaceArea + "㎡";
  1100. if(window.currentPage && window.currentPage.navbar && window.currentPage.pvCurPageName=='room_show'){
  1101. window.currentPage.navbar.title = title;
  1102. document.title = title;
  1103. }
  1104. },
  1105. //用户手动点击空间名称
  1106. selectSpaceHandle(gltf){
  1107. if(gltf.spaceType==13){//楼梯不处理
  1108. return false
  1109. }
  1110. this.curSpaceSelect(gltf.spaceId,false)
  1111. },
  1112. //选中当前空间
  1113. curSpaceSelect(spaceId,moveCenter=true){
  1114. console.warn("***curSpaceSelect***",spaceId,this.lableItem);
  1115. if(!spaceId){
  1116. return false
  1117. }
  1118. if(this.curSpaceObj){
  1119. this.changeSpaceColor(this.curSpaceObj.spaceId,2);//取消上一个空间的颜色
  1120. }
  1121. let space = this.spaceList.find(it=>it.spaceId==spaceId);
  1122. this.curSpaceObj = space;
  1123. this.currentChangeSpaceId = spaceId;
  1124. this.$store.state.curSpaceId = spaceId;
  1125. if(window.currentPage.pvCurPageName == 'home_show'){
  1126. this.changeSpaceColor(spaceId,1);//设置选中空间的颜色
  1127. }
  1128. if(moveCenter){
  1129. this.moveMeshCenter(space);//移动到当前空间
  1130. }
  1131. },
  1132. //当前空间面积发送了变化
  1133. curSpaceChange(data){
  1134. console.warn("***空间面积变化***",this.overChange,data);
  1135. this.overChange = true;//变形开始 防止在形变结束前,再次形变
  1136. this.$store.state.overChange = true;
  1137. this.curSpaceSelect(data.spaceId);
  1138. // this.currentChangeSpaceId = data.spaceId;
  1139. // this.$store.state.curSpaceId = data.spaceId;
  1140. // let space = this.spaceList.find(it=>it.spaceId==this.currentChangeSpaceId);
  1141. // this.moveMeshCenter(space);
  1142. this.changCurSpaceArea(data);//空间移动
  1143. },
  1144. //用户选择的布局id-需要切换到这个布局去
  1145. userSelectPlot(layoutObj,space=null){
  1146. if(!layoutObj){
  1147. console.warn("***userSelectPlot***数据错误")
  1148. return false
  1149. }
  1150. let spaceId = space ? space.spaceId : this.curSpaceObj.spaceId;
  1151. console.warn("***userSelectPlot***",spaceId,layoutObj)
  1152. this.changeSingleLayout(space,layoutObj);
  1153. this.updataLable(spaceId,layoutObj);
  1154. },
  1155. //更改空间显示名称 X空间 类型 根据布局所属类型来显示
  1156. updataLable(spaceId,layoutObj){
  1157. let list = this.arrFrunList;
  1158. let lable = this.lableItem.find(it=>it.spaceId == spaceId);
  1159. let name = spaceTypes[layoutObj.type - 1];
  1160. lable.text = name;
  1161. console.warn("***updataLable***",lable)
  1162. // this.$refs.viewShell.$refs.viewCareful.updataData(spaceId,layoutObj);
  1163. },
  1164. //obj 物体对象,type 是否改变颜色
  1165. moveMeshCenter(obj,type){
  1166. console.warn("**moveMeshCenter***",obj)
  1167. if(obj && this.gltfSpaces && this.gltfSpaces.length>0){
  1168. this.moveMeshCenterHandle(obj,type);
  1169. }
  1170. },
  1171. //截取webgl图
  1172. async creatShotImg(){
  1173. return new Promise(async (resolve) => {
  1174. let shottingImg = await this.shottingAction() + "?x-oss-process=image/auto-orient,1/quality,Q_46/format,jpg";//开始截图
  1175. resolve(shottingImg)
  1176. })
  1177. },
  1178. //进入具体空间时的处理
  1179. spaceEnter(){
  1180. this.showArea = false;
  1181. this.showLables = false;
  1182. if(this.curSpaceObj){
  1183. this.changeSpaceColor(this.curSpaceObj.spaceId,2);//取消上一个空间的颜色
  1184. }
  1185. this.enterRoom();
  1186. this.positionCamer(this.curSpaceObj);
  1187. let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
  1188. let title = this.curSpaceObj.spaceName + " " + curSpaceArea + "㎡";
  1189. if(window.currentPage && window.currentPage.navbar){
  1190. window.currentPage.navbar.title = title;
  1191. document.title = title;
  1192. }
  1193. },
  1194. //离开具体空间时的处理
  1195. spaceLeave(type=true){
  1196. this.showArea = true;
  1197. this.showLables = true;
  1198. this.leaveRoom(type);
  1199. }
  1200. }
  1201. }
  1202. </script>
  1203. <style lang="scss" scoped>
  1204. @import "./webglCom.scss";
  1205. /* @import "@/common/css/common.css"; */
  1206. </style>