loadModel.js 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  1. // const util = require('@/static/utils/util.js');
  2. const config = require('@/services/urlConfig.js');
  3. import modelData from '@/static/layoutModelData.js';
  4. import globlShowModel from '@/static/globlShowModel.js';
  5. import spaceTypes from '@/static/spaceTypesIE.js';
  6. // import requestConfig from '@/services/requestConfig.js';
  7. import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
  8. import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
  9. import * as THREE from 'three';
  10. // import { TWEEN } from '@/webgl/jsm/libs/tween.module.min.js';
  11. export default {
  12. data() {
  13. return {
  14. gltfLayouts: [],
  15. instancedFurList:[],
  16. // graderGltfLayouts: [],//花园地块的模型对象
  17. // graderInstancedFurList:[],//花园地块的模型
  18. arrFrunList:[],
  19. promise_list:[],
  20. dracoLoader:null,
  21. type:1,
  22. tmpList:[],
  23. realList:[],
  24. nextString:'_simple',//精简模型后缀
  25. loadLayFlag:false, //是否处在加载家具过程中
  26. isIOS:false,
  27. // lastFrunList:[],
  28. }
  29. },
  30. watch: {},
  31. mounted() {
  32. console.warn("***loadmodel-mounted****")
  33. this.dracoLoader = new DRACOLoader();
  34. this.dracoLoader.setDecoderPath('./gltf/');
  35. this.dracoLoader.setDecoderConfig( { type: 'js' } );
  36. this.dracoLoader.preload();
  37. let isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  38. this.isIOS = isIOS;
  39. },
  40. methods: {
  41. // 设置空间数组的墙体信息
  42. async setSpaceListWallInfo(){
  43. for (let index = 0; index < this.spaceList.length; index++) {
  44. let spaceWallInfo = {wallN:false, wallS:false, wallW:false, wallE:false}
  45. const element = this.spaceList[index];
  46. const wallWIndex = this.gltfWalls.findIndex(item=>{
  47. return element.spaceId == item.spaceId && item.wallDirection == "W"
  48. })
  49. spaceWallInfo.wallW = wallWIndex == -1 ? false : true;
  50. const wallEIndex = this.gltfWalls.findIndex(item=>{
  51. return element.spaceId == item.spaceId && item.wallDirection == "E"
  52. })
  53. spaceWallInfo.wallE = wallEIndex == -1 ? false : true;
  54. const wallNIndex = this.gltfWalls.findIndex(item=>{
  55. return element.spaceId == item.spaceId && item.wallDirection == "N"
  56. })
  57. spaceWallInfo.wallN = wallNIndex == -1 ? false : true;
  58. const wallSIndex = this.gltfWalls.findIndex(item=>{
  59. return element.spaceId == item.spaceId && item.wallDirection == "S"
  60. })
  61. spaceWallInfo.wallS = wallSIndex == -1 ? false : true;
  62. element.spaceWallInfo = spaceWallInfo;
  63. }
  64. },
  65. //更改空间显示名称 X空间 类型 根据布局所属类型来显示
  66. updataLableList(list){
  67. // let lable = this.lableItem.find(it=>it.spaceId == spaceId);
  68. // let name = spaceTypes[layoutObj.type - 1];
  69. // lable.text = name;
  70. this.lableItem && this.lableItem.forEach(lable=>{
  71. if(lable.spaceType==15){
  72. let layoutId = this.spaceList.find(it => it.spaceId == lable.spaceId).layoutId;
  73. let layout = list.find(it=>it.id == layoutId);
  74. if(layout){
  75. let name = spaceTypes[layout.type - 1];
  76. lable.text = name
  77. }
  78. }
  79. })
  80. this.spaceList.forEach(space=>{
  81. if(space.spaceType==15){//X空间才赋值
  82. let layout = list.find(it=>it.id == space.layoutId);
  83. if(layout){
  84. space.layoutSpaceType = layout.type;//更新布局信息到空间对象里面
  85. space.layoutSpaceName = layout.spacexName || layout.name;//更新布局信息到空间对象里面
  86. if(this.$refs && this.$refs.viewShell){
  87. this.$refs.viewShell.$refs.viewCareful.updataData(space.spaceId,layout);
  88. }
  89. if(this.updataPageData && typeof(this.updataPageData)=='function'){
  90. this.updataPageData();//更新数据
  91. }
  92. }
  93. }
  94. });
  95. },
  96. // 批量获取空间模型信息
  97. async getOverallArrangementDetailsList(type=1) {
  98. // 设置空间数组的墙体信息
  99. // this.setSpaceListWallInfo();
  100. this.type = type;//加载类型,1空间加载 2 全局精简加载
  101. let arr = this.spaceList.map(it => it.layoutId).filter(it => it != 0);
  102. // let arr = [533]
  103. let parmas = {
  104. ids: arr,
  105. };
  106. // 默认的布局
  107. let res = await requestConfig("getOverallArrangementDetailsList", parmas);
  108. if (!res.success || !res.list || res.list.length == 0) {
  109. return false;
  110. }
  111. // let list1 = [];
  112. // let list2 = [];
  113. // res.list.forEach(singel=>{
  114. // let spaceType = this.spaceList.find(it => it.layoutId == signel.id).spaceType;
  115. // if(spaceType!=14){//花园地块
  116. // list1.push(singel);
  117. // }else{
  118. // list2.push(singel);
  119. // }
  120. // });
  121. this.promise_list = [];
  122. this.arrFrunList = res.list;
  123. this.gltfLayouts = []; //模型列表,所有空间里面的每个模型(家具)对应一条记录
  124. this.updataLableList(res.list)
  125. // 通过默认布局
  126. this.furnHandle(this.arrFrunList,[]);
  127. },
  128. //加载其他空间的家具模型
  129. loadLastSpaceModel(){
  130. if(!this.changeSpaces || this.changeSpaces.length==0){
  131. return false;
  132. }
  133. let spaceIds = this.changeSpaces.map(it=>it.spaceId);
  134. let layoutIds = this.spaceList.filter(item=>spaceIds.includes(item.spaceId)).map(it=>it.layoutId);
  135. let list = this.arrFrunList.filter(item=>{
  136. return !layoutIds.includes(item.id)
  137. })
  138. let spaceList = this.spaceList.filter(item=>{
  139. return !spaceIds.includes(item.spaceId)
  140. })
  141. // console.warn("***layoutIds***",layoutIds,spaceIds,this.gltfLayouts)
  142. this.furnHandle(list,spaceList)
  143. this.changeSpaces = []
  144. },
  145. //加载单个空间的家具模型
  146. furnSingleSpaceHandle(space){
  147. let arrFrunList = this.arrFrunList;
  148. // let space = this.curSpaceObj;
  149. let allowSpaceId = [space.spaceId];
  150. if(!arrFrunList || arrFrunList.length == 0){
  151. return
  152. }
  153. this.clearAllLayoutData();//清空家具模型
  154. this.promise_list = [];
  155. this.gltfLayouts = []; //模型列表,所有空间里面的每个模型(家具)对应一条记录
  156. let startTime = new Date().getTime();
  157. let tmpList = [];//临时数据-精简模型数据
  158. let curSpaceList = [];//当前空间的数据对象
  159. console.warn("重新加载布局", arrFrunList,this.gltfLayouts,allowSpaceId);
  160. //每个空间都处理下,确保空间不遗漏,arrFrunList遍历,如果不同空间使用同一个布局,会出现只处理第一个空间
  161. let spaceId = space.spaceId;
  162. let signel = arrFrunList.find(it => it.id == space.layoutId);
  163. if(signel){//只加载允许的空间的布局,其他不加载
  164. let md = JSON.parse(signel.modelJson); //获取布局里面的模型信息
  165. //遍历模型信息,获取模型列表
  166. for (let i = 0; i < md.modelData.length; i++) {
  167. let item = md.modelData[i];
  168. item.spaceId = spaceId;
  169. item.layoutId = signel.id;
  170. item.h5Id = signel.id+""+item.id;//唯一标识
  171. if(item.modelName=='BP_furnitureBase_C'){
  172. continue;
  173. }else{
  174. if(spaceId==this.curSpaceObj.spaceId){
  175. curSpaceList.push(item);
  176. }else{
  177. tmpList.push(item);
  178. }
  179. }
  180. }
  181. }
  182. this.realList = []
  183. this.tmpList = tmpList;
  184. this.fliterList(tmpList);//精简模式下,只计算白名单里面的模型位置等信息
  185. console.warn("***fliterList***",this.type,this.realList.length);
  186. tmpList = this.realList;
  187. tmpList = tmpList.concat(curSpaceList);//合并详细空间的模型
  188. let realFurArr = this.preFurnitureData(tmpList);//统一处理家具模型
  189. this.calculateLayoutModelSize() // 提前计算模型的位置
  190. tmpList = [];
  191. this.realList = [];
  192. this.tmpList = []
  193. console.log("***realFurArr***", realFurArr,this.gltfLayouts);
  194. realFurArr && realFurArr.forEach((item,index) => {
  195. this.loadLayFlag = true;
  196. this.promise_list.push(
  197. new Promise((resolve, reject) => {
  198. this.loadLayoutModels(item, resolve);
  199. })
  200. )
  201. });
  202. Promise.all(this.promise_list).then(() => {
  203. let endTime = new Date().getTime();
  204. this.loadLayFlag = false;
  205. realFurArr = [];
  206. console.log("家具模型全部加载完成,时间:", endTime - startTime, this.gltfLayouts);
  207. this.loadLastSpaceModel();//加载剩余空间的家具模型
  208. })
  209. },
  210. //拆分家具模型加载逻辑
  211. furnHandle(arrFrunList, tmpSpaceList=[]){
  212. if(!arrFrunList || arrFrunList.length == 0){
  213. return
  214. }
  215. let startTime = new Date().getTime();
  216. let tmpList = [];//临时数据-精简模型数据
  217. let allowSpaceId = [this.curSpaceObj.spaceId];
  218. let curSpaceList = [];//当前空间的数据对象
  219. if(this.type == 2){//全局精简模型;需要的是所有空间的模型
  220. allowSpaceId = this.spaceList.map(it=>it.spaceId)
  221. }else{//空间模型模式
  222. if(this.isIOS){
  223. allowSpaceId = [this.curSpaceObj.spaceId];
  224. if(this.curSpaceObj.spaceName=='主卧'){//主卧
  225. let list = this.spaceList.filter(it=>it.spaceName=='休闲小客厅')
  226. allowSpaceId.push(...list.map(it=>it.spaceId));//休闲小客厅
  227. }
  228. if(this.curSpaceObj.spaceName=='休闲小客厅'){//休闲小客厅
  229. let list = this.spaceList.filter(it=>it.spaceName=='主卧')
  230. allowSpaceId.push(...list.map(it=>it.spaceId));//主卧
  231. }
  232. }else{
  233. allowSpaceId = this.spaceList.map(it=>it.spaceId);//当前空间 精模加载,其他空间用 简模加载
  234. }
  235. }
  236. console.warn("重新加载布局", arrFrunList,this.spaceList,this.gltfLayouts,allowSpaceId);
  237. //每个空间都处理下,确保空间不遗漏,arrFrunList遍历,如果不同空间使用同一个布局,会出现只处理第一个空间
  238. this.spaceList.forEach(space=>{
  239. let spaceId = space.spaceId;
  240. let signel = arrFrunList.find(it => it.id == space.layoutId);
  241. if(allowSpaceId.includes(spaceId) && signel){//只加载允许的空间的布局,其他不加载
  242. let md = JSON.parse(signel.modelJson); //获取布局里面的模型信息
  243. console.warn("***布局信息***",this.type,md,md.modelData.map(it=>it.modelName));
  244. //遍历模型信息,获取模型列表
  245. for (let i = 0; i < md.modelData.length; i++) {
  246. let item = md.modelData[i];
  247. item.spaceId = spaceId;
  248. item.layoutId = signel.id;
  249. item.h5Id = signel.id+""+item.id;//唯一标识
  250. if(item.modelName=='BP_furnitureBase_C'){
  251. continue;
  252. }else{
  253. if(this.type==1){//详细空间
  254. if(spaceId==this.curSpaceObj.spaceId){
  255. curSpaceList.push(item);
  256. }else{
  257. tmpList.push(item);
  258. }
  259. }else{//首页
  260. tmpList.push(item);
  261. }
  262. }
  263. }
  264. }
  265. });
  266. this.tmpList = tmpList;
  267. if(this.type==2){//全局精简模型;需要的是所有空间的模型
  268. this.fliterList(tmpList);//精简模式下,只计算白名单里面的模型位置等信息
  269. console.warn("***fliterList***",this.type,this.realList.length);
  270. tmpList = this.realList;
  271. }else{
  272. this.fliterList(tmpList);//精简模式下,只计算白名单里面的模型位置等信息
  273. console.warn("***fliterList***",this.type,this.realList.length);
  274. tmpList = this.realList;
  275. tmpList = tmpList.concat(curSpaceList);//合并详细空间的模型
  276. }
  277. console.log("***realFurArr0***", tmpList.map(it=>it.modelName));
  278. let realFurArr = this.preFurnitureData(tmpList);//统一处理家具模型
  279. if(tmpSpaceList && tmpSpaceList.length>0){
  280. this.calculateLayoutModelSizeBySpace(tmpSpaceList) // 提前计算模型的位置
  281. }else{
  282. this.calculateLayoutModelSize() // 提前计算模型的位置
  283. }
  284. tmpList = [];
  285. this.realList = [];
  286. this.tmpList = []
  287. console.log("***realFurArr***", realFurArr,this.gltfLayouts);
  288. realFurArr && realFurArr.forEach((item,index) => {
  289. this.loadLayFlag = true;
  290. this.promise_list.push(
  291. new Promise((resolve, reject) => {
  292. this.loadLayoutModels(item, resolve);
  293. })
  294. )
  295. });
  296. Promise.all(this.promise_list).then(() => {
  297. let endTime = new Date().getTime();
  298. this.loadLayFlag = false;
  299. realFurArr = [];
  300. console.log("家具模型全部加载完成,时间:", endTime - startTime, this.gltfLayouts);
  301. this.loadLastSpaceModel();//加载剩余空间的家具模型
  302. // alert("JavaScript 堆大小限制: "+performance
  303. // +"\n已使用的 JavaScript 堆大小: "+performance
  304. // +"\nJavaScript 堆的总大小: "+performance.memory);
  305. })
  306. },
  307. //过滤掉不需要的家具
  308. fliterList(list){
  309. this.realList = [];
  310. let tempList = globlShowModel.map(it=>it.replace(this.nextString,''));
  311. //找到直接的家具模型
  312. list && list.forEach((mod)=>{
  313. let name = mod.modelName.substring(0,mod.modelName.length-2);
  314. if(tempList.includes(name)){
  315. this.realList.push(mod);
  316. }
  317. })
  318. this.realList.forEach((ref)=>{
  319. this.recursionFliter(ref)
  320. })
  321. },
  322. //递归处理不需要的家具
  323. recursionFliter(item){
  324. let _list = [];//
  325. if(parseInt(item.referenceModelBottom) > 0){
  326. _list.push(item.referenceModelBottom)
  327. }
  328. if(parseInt(item.referenceModelLeft) > 0){
  329. _list.push(item.referenceModelLeft)
  330. }
  331. if(parseInt(item.referenceModelRight) > 0){
  332. _list.push(item.referenceModelRight)
  333. }
  334. if(parseInt(item.referenceModelTop) > 0){
  335. _list.push(item.referenceModelTop)
  336. }
  337. if(_list.length==0){
  338. return false;
  339. }else{
  340. this.tmpList.forEach(tmp=>{
  341. if(_list.includes(tmp.id)){
  342. if(!this.realList.find(it=>it.h5Id==tmp.h5Id)){
  343. this.realList.push(tmp);
  344. this.recursionFliter(tmp);
  345. }
  346. }
  347. })
  348. }
  349. },
  350. //预处理需要加载墙体模型的数据-减少模型请求数
  351. preFurnitureData(list){
  352. let realFurnitureArr = [];//家具列表
  353. list && list.forEach((item, index) => {
  354. item.uniId = Date.now() + index;//唯一标识
  355. //获取墙体对应的gltb模型的相关信息
  356. let modelName = item.modelName;
  357. // console.log("布局模型名称", modelName);
  358. let layoutModel = modelData.find(it => modelName.indexOf(it.modelName) == 0); //模型地址
  359. // if(layoutModel.modelName=='BP_L_book01'){
  360. // debugger
  361. // }
  362. // console.log("要加载的模型数据", item.modelName, layoutModel)
  363. if (layoutModel && layoutModel.url) {//该数据存在模型地址
  364. let url = layoutModel.url;
  365. //说明当前模型存在精简模型对象,则应该使用精简模型数据
  366. if(this.type ==2 || this.isIOS){
  367. if(globlShowModel.includes(layoutModel.modelName + this.nextString)){
  368. if(!url.includes(this.nextString)){
  369. let idx = url.lastIndexOf('.');
  370. url = url.substr(0,idx) + this.nextString + url.substr(idx);//修改为精简模型地址
  371. }
  372. }
  373. } else {
  374. //不是本空间的
  375. if(item.spaceId != this.curSpaceObj.spaceId){
  376. //匹配到白名单里面的精简模型
  377. if(globlShowModel.includes(layoutModel.modelName + this.nextString)){
  378. if(!url.includes(this.nextString)){
  379. let idx = url.lastIndexOf('.');
  380. url = url.substr(0,idx) + this.nextString + url.substr(idx);//修改为精简模型地址
  381. }
  382. }
  383. }
  384. }
  385. let object = realFurnitureArr.find(it=>(it.url==url));
  386. //列表中还没有这个数据
  387. if(!object){
  388. let it = {
  389. url:url,
  390. name:layoutModel.modelName,
  391. list:[item],
  392. }
  393. realFurnitureArr.push(it)
  394. }else{
  395. object.list.push(item);
  396. }
  397. let position = new THREE.Vector3();//当前几何体的位置参数
  398. let scale = new THREE.Vector3();//当前几何体的缩放参数
  399. let rotation = new THREE.Vector3();//当前几何体的缩放参数
  400. let md = {
  401. uniId:item.uniId,//家具模型实例的唯一标识
  402. spaceId:item.spaceId,
  403. id:item.id,
  404. userData:item,
  405. position:position,
  406. scale:scale,
  407. rotation:rotation,
  408. loaded:false,
  409. };
  410. this.gltfLayouts.push(md);
  411. }
  412. });
  413. return realFurnitureArr;
  414. },
  415. //加载家具模型-实例化方案
  416. loadLayoutModels(realData, resolve){
  417. var that = this;
  418. if(!realData.url){
  419. console.warn("***家具模型不存在***",realData);
  420. resolve();
  421. return false;
  422. }
  423. if(realData.name.includes('BP_XSPACE_deng_01')){//灯光
  424. resolve();
  425. }else{
  426. //不在白名单里面的,不加载
  427. if(this.type==2 || this.isIOS){
  428. if(!globlShowModel.includes(realData.name)
  429. && !globlShowModel.includes(realData.name + this.nextString)){
  430. resolve();
  431. return false;
  432. }
  433. }
  434. that.loader.setDRACOLoader(this.dracoLoader);
  435. that.loader.setMeshoptDecoder(MeshoptDecoder);
  436. //关键代码,如果是ios手机,则请求图片时压缩尺寸,当前最高是256
  437. that.loader.manager.resolveURL = (url)=>{
  438. let redirectUrl = url;
  439. if(that.isIOS && url.startsWith('http') &&
  440. (url.endsWith('.jpg') || url.endsWith('.png') || url.endsWith('.gif'))){
  441. // redirectUrl = url + "?imageMogr2/auto-orient/thumbnail/!256x256r/gravity/Center/crop/256x256/interlace/1/format/jpg/blur/1x0/quality/75|imageslim"
  442. redirectUrl = url + "?imageMogr2/auto-orient/format/webp/blur/1x0/quality/75"
  443. }
  444. return redirectUrl;
  445. }
  446. that.loader.load(realData.url, ( gltf ) => {
  447. gltf.scene.traverse((child)=> {
  448. if (child.isMesh && child.visible) {
  449. if(realData.name=='BP_B_verysmallbed'){
  450. console.warn("***child.material***",child.material)
  451. }
  452. let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), realData.list.length);
  453. this.instancedFurList.push(instancedMesh);
  454. //realData 该模型被重复使用时的每一次的形变参数等
  455. realData.list && realData.list.forEach((it,i)=>{
  456. let gltfFurn = that.gltfLayouts.find(itme=>itme.uniId==it.uniId);//判断是否已经添加过
  457. if(gltfFurn){
  458. gltf.scene.rotation.y = gltfFurn.rotation.y;
  459. gltf.scene.position.set(gltfFurn.position.x,0,gltfFurn.position.z);
  460. gltf.scene.scale.set(gltfFurn.scale.x,1,gltfFurn.scale.z);
  461. gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了
  462. instancedMesh.setMatrixAt(i, child.matrixWorld);
  463. instancedMesh.instanceMatrix.needsUpdate = true;
  464. gltfFurn.loaded = true;
  465. if(!gltfFurn.instancedMeshIndexList){//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号
  466. gltfFurn.instancedMeshIndexList = [
  467. {instancedMeshIndex:this.instancedFurList.length-1,instancedAtIndex:i},
  468. ]
  469. }else{
  470. gltfFurn.instancedMeshIndexList.push({
  471. instancedMeshIndex:this.instancedFurList.length-1,instancedAtIndex:i
  472. })
  473. }
  474. }
  475. })
  476. instancedMesh.material.opacity = 0.8;
  477. instancedMesh.userType = "layoutMesh";
  478. if(realData.name.includes("BP_L_carpet01")){//地毯接收阴影
  479. instancedMesh.receiveShadow = true;//对象是否接收阴影
  480. }else{
  481. instancedMesh.castShadow = true;//对象是否产生阴影
  482. }
  483. this.scene.add(instancedMesh);//添加到场景中
  484. }
  485. });
  486. resolve();
  487. });
  488. }
  489. },
  490. //加载模型
  491. loadLayoutModelsOld(modelObj, resolve) {
  492. let that = this;
  493. const modelName = modelObj.modelName;
  494. console.log("布局模型名称", modelName);
  495. let layoutModel = modelData.find(it => modelName.indexOf(it.modelName) == 0); //模型地址
  496. if (!layoutModel || !layoutModel.url) {
  497. resolve();
  498. return false
  499. }
  500. let url = layoutModel.url;
  501. console.log("布局模型数据", layoutModel);
  502. that.loader.load(url, (gltf) => {
  503. // console.log("布局模型加载成功", gltf);
  504. let model = gltf.scene; // 获取模型
  505. model.name = layoutModel.modelName;
  506. model.userType = "layoutMesh";
  507. model.userData = modelObj;
  508. // model.rotation.y = Math.PI / 2 ; // 旋转 90 度
  509. this.gltfLayouts.push(model);
  510. resolve();
  511. });
  512. },
  513. //清除当前楼层下的所有家具模型
  514. clearAllLayoutData(){
  515. let deleList = this.scene && this.scene.children.filter(object=>{
  516. if(object.userType=="layoutMesh"){
  517. return object
  518. }
  519. })
  520. // console.warn("***deleList***",deleList)
  521. if(deleList && deleList.length>0){
  522. this.scene.remove(...deleList);
  523. }
  524. this.gltfLayouts = [];
  525. this.instancedFurList = [];
  526. },
  527. // 切换家具的显示隐藏
  528. changeLayoutModelState(isShow=false){
  529. if(isShow){
  530. this.instancedFurList.forEach(it=>{
  531. if(it){
  532. it.visible = isShow;
  533. }
  534. })
  535. console.log("移动过程中显示隐藏空间家具", this.gltfLayouts,isShow,this.changeSpaces)
  536. return false;
  537. }
  538. const changeSpaceList = this.leftSpaces.concat(this.rightSpaces); // 只改变空间尺寸变化的家具模型
  539. console.log("移动过程中显示隐藏空间家具", this.gltfLayouts,isShow, this.leftSpaces, this.rightSpaces,this.changeSpaces);
  540. for (let index = 0; index < changeSpaceList.length; index++) {
  541. let element = changeSpaceList[index];
  542. let gltfLayoutModels = this.gltfLayouts.filter(item => {
  543. return element.layoutId == item.userData.layoutId && element.spaceId == item.userData.spaceId;
  544. })
  545. if (!gltfLayoutModels || gltfLayoutModels.length == 0) {
  546. continue;
  547. }
  548. console.warn("***隐藏空间家具***",element,gltfLayoutModels)
  549. for (let j = 0; j < gltfLayoutModels.length; j++) {
  550. let cube = gltfLayoutModels[j];
  551. this.changeCubeState(cube, isShow);
  552. }
  553. }
  554. },
  555. // 显示隐藏指定cube的状态
  556. changeCubeState(cube, isShow){
  557. let lay = this.gltfLayouts.find(it=>it.uniId==cube.uniId);
  558. if(cube.instancedMeshIndexList && cube.instancedMeshIndexList.length>0){
  559. cube.instancedMeshIndexList.forEach(item=>{
  560. let index = item.instancedMeshIndex;
  561. let instancedMesh = this.instancedFurList[index];//网格实例对象
  562. // let curMeshIndex = item.instancedAtIndex;//当前家具模型在网格实例对象里面的序号
  563. // let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
  564. // instancedMesh.getMatrixAt(curMeshIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  565. // instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
  566. if(instancedMesh && instancedMesh.hasOwnProperty('visible')){
  567. instancedMesh.visible = isShow;
  568. }
  569. // instancedMesh.setMatrixAt(curMeshIndex,stratMatrix);//更新几何体的世界矩阵
  570. })
  571. }
  572. },
  573. // 删除对应空间家具模型
  574. deleteLayoutModel(spaceObj, layoutObj){
  575. const oldLayoutIndex = this.arrFrunList.findIndex((item)=>{
  576. return item.id == spaceObj.layoutId
  577. })
  578. //对应空间的布局替换为新的布局数据
  579. if(oldLayoutIndex!=-1 && layoutObj){
  580. this.arrFrunList[oldLayoutIndex] = layoutObj;
  581. // spaceObj.layoutId = layoutObj.id;
  582. }
  583. if(!layoutObj){//当前空间不存在布局了
  584. this.arrFrunList.splice(oldLayoutIndex,1)
  585. spaceObj.layoutId = null;//为了确保传递到下一页的空间里面也没有布局信息,确保布局一致
  586. }
  587. console.log("准备删除模型", spaceObj,oldLayoutIndex, this.gltfLayouts);
  588. //寻找当前空间下的所有家具模型对象
  589. const gltfLayoutModels = this.gltfLayouts.filter(item => {
  590. return spaceObj.layoutId == item.userData.layoutId && spaceObj.spaceId == item.userData.spaceId;
  591. })
  592. //不存在则不处理
  593. if (!gltfLayoutModels || gltfLayoutModels.length == 0) {
  594. return;
  595. }
  596. let deleList = []
  597. for (let j = 0; j < gltfLayoutModels.length; j++) {
  598. const cube = gltfLayoutModels[j];
  599. this.gltfLayouts.splice(this.gltfLayouts.findIndex(it=>it.uniId==cube.uniId),1);//删除gltfLayouts里面的数据
  600. if(cube.instancedMeshIndexList && cube.instancedMeshIndexList.length>0){
  601. cube.instancedMeshIndexList.forEach(item=>{
  602. let index = item.instancedMeshIndex;
  603. let instancedMesh = this.instancedFurList[index];//网格实例对象
  604. if(instancedMesh){
  605. instancedMesh.dispose();
  606. deleList.push(instancedMesh);//等待释放资源
  607. this.instancedFurList[index] = null;
  608. // if(instancedMesh.count>1){//表示其他空间还存在这个模型,应该重新加入计算中
  609. // if(!this.lastFrunList.includes(cube.userData.modelName)){
  610. // this.lastFrunList.push(cube.userData.modelName);
  611. // }
  612. // }
  613. }
  614. })
  615. }
  616. }
  617. this.scene.remove(...deleList);//释放家具的资源,this.instancedFurList
  618. console.log("删除模型了", spaceObj, this.gltfLayouts);
  619. },
  620. // 计算家具的位置
  621. calculateLayoutModelSize() {
  622. console.log("计算家具的位置", this.gltfLayouts,this.changeSpaces);
  623. // 有改变空间,只刷新改变空间的模型数据
  624. const spaceList = (!this.changeSpaces || this.changeSpaces.length ==0) ? this.spaceList : this.changeSpaces;
  625. for (let index = 0; index < spaceList.length; index++) {
  626. const element = spaceList[index];
  627. const gltfLayoutModels = this.gltfLayouts.filter(item => {
  628. return element.layoutId == item.userData.layoutId && element.spaceId == item.userData.spaceId;
  629. })
  630. //空间下不存在家具模型,则该空间不需要进行下一步处理
  631. if (!gltfLayoutModels || gltfLayoutModels.length == 0) {
  632. continue;
  633. }
  634. gltfLayoutModels.sort(function(a, b) {
  635. return a.userData.level - b.userData.level
  636. });
  637. let newSpace = this.spaceList.find(item => {
  638. return element.spaceId == item.spaceId;
  639. })
  640. // console.log("对应空间ID的模型数组", this.gltfLayouts, element.spaceId, gltfLayoutModels)
  641. for (let j = 0; j < gltfLayoutModels.length; j++) {
  642. const cube = gltfLayoutModels[j];
  643. this.drawLayoutModel(newSpace, cube);
  644. }
  645. }
  646. },
  647. // 计算家具的位置
  648. calculateLayoutModelSizeBySpace(spaceList) {
  649. for (let index = 0; index < spaceList.length; index++) {
  650. const element = spaceList[index];
  651. const gltfLayoutModels = this.gltfLayouts.filter(item => {
  652. return element.layoutId == item.userData.layoutId && element.spaceId == item.userData.spaceId;
  653. })
  654. // console.log("计算指定空间的家具的位置", element, element.layoutId, gltfLayoutModels);
  655. //空间下不存在家具模型,则该空间不需要进行下一步处理
  656. if (!gltfLayoutModels || gltfLayoutModels.length == 0) {
  657. continue;
  658. }
  659. gltfLayoutModels.sort(function(a, b) {
  660. return a.userData.level - b.userData.level
  661. });
  662. // console.log("对应空间ID的模型数组", this.gltfLayouts, element.spaceId, gltfLayoutModels)
  663. for (let j = 0; j < gltfLayoutModels.length; j++) {
  664. const cube = gltfLayoutModels[j];
  665. this.drawLayoutModel(element, cube);
  666. }
  667. }
  668. },
  669. // 绘制模型
  670. drawLayoutModel(curSpace, cube) {
  671. const {
  672. centerX,
  673. spaceId
  674. } = curSpace;
  675. const cubeInfo = this.resetModelParameters(curSpace, cube.userData);
  676. // const cubeInfo = cube.userData;
  677. let centerY = curSpace.centerY * -1; // UE和ThreeJS坐标做相反
  678. // 默认空间中心点
  679. let positionX = centerX;
  680. let positionY = centerY;
  681. let rotationY = Math.PI / 2;
  682. let scaleX = 1;
  683. let scaleY = 1;
  684. // 空间尺寸
  685. let spaceWidth = curSpace.spaceWidth;
  686. let spaceHeight = curSpace.spaceHeight;
  687. // 模型尺寸
  688. let modelWidth = cubeInfo.modelWidth;
  689. let modelHeight = cubeInfo.modelHeight;
  690. // 判断旋转
  691. if (parseFloat(cubeInfo.rotation) == 90) {
  692. rotationY = 0;
  693. // 交换尺寸
  694. // modelWidth = cubeInfo.modelHeight;
  695. // modelHeight = cubeInfo.modelWidth;
  696. }
  697. if (parseFloat(cubeInfo.rotation) == 180) {
  698. rotationY = -Math.PI / 2;
  699. // modelWidth = cubeInfo.modelHeight;
  700. // modelHeight = cubeInfo.modelWidth;
  701. }
  702. if (parseFloat(cubeInfo.rotation) == -90) {
  703. rotationY = -Math.PI;
  704. // 交换尺寸
  705. // modelWidth = cubeInfo.modelHeight;
  706. // modelHeight = cubeInfo.modelWidth;
  707. }
  708. // 判断靠墙
  709. if (cubeInfo.isStepAsideLeft == 'true') {
  710. positionX = centerX - (spaceWidth / 2 - modelWidth / 2);
  711. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  712. positionX = centerX - (spaceWidth / 2 - modelWidth / 2);
  713. }
  714. positionX += parseFloat(cubeInfo.marginLeft);
  715. positionX += curSpace.spaceWallInfo.wallW ? 10 : 0;
  716. }
  717. if (cubeInfo.isStepAsideRight == 'true') {
  718. positionX = centerX + (spaceWidth / 2 - modelWidth / 2);
  719. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  720. positionX = centerX + (spaceWidth / 2 - modelWidth / 2);
  721. }
  722. positionX -= parseFloat(cubeInfo.marginRight);
  723. positionX -= curSpace.spaceWallInfo.wallE ? 10 : 0;
  724. }
  725. if (cubeInfo.isStepAsideTop == 'true') {
  726. positionY = centerY - (spaceHeight / 2 - modelHeight / 2);
  727. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  728. positionY = centerY - (spaceHeight / 2 - modelHeight / 2);
  729. }
  730. positionY += parseFloat(cubeInfo.marginTop);
  731. positionY += curSpace.spaceWallInfo.wallN ? 10 : 0;
  732. }
  733. if (cubeInfo.isStepAsideBottom == 'true') {
  734. positionY = centerY + (spaceHeight / 2 - modelHeight / 2);
  735. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  736. positionY = centerY + (spaceHeight / 2 - modelHeight / 2);
  737. }
  738. positionY -= parseFloat(cubeInfo.marginBottom);
  739. positionY -= curSpace.spaceWallInfo.wallS ? 10 : 0;
  740. }
  741. // 参照物
  742. if (parseInt(cubeInfo.referenceModelTop) > 0) {
  743. const referenceModel = this.gltfLayouts.find(item => {
  744. const layoutModelData = item.userData;
  745. return layoutModelData.id == parseInt(cubeInfo.referenceModelTop) && layoutModelData
  746. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  747. })
  748. if(!referenceModel){
  749. console.warn("***no-data***",cubeInfo.referenceModelTop,cubeInfo)
  750. return false
  751. }
  752. positionY = referenceModel.position.z * 100 + (referenceModel.userData.modelHeight / 2 + cubeInfo
  753. .modelHeight / 2);
  754. positionY = positionY + parseFloat(cubeInfo.marginTop);
  755. }
  756. if (parseInt(cubeInfo.referenceModelBottom) > 0) {
  757. const referenceModel = this.gltfLayouts.find(item => {
  758. const layoutModelData = item.userData;
  759. return layoutModelData.id == parseInt(cubeInfo.referenceModelBottom) && layoutModelData
  760. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  761. })
  762. if(!referenceModel){
  763. console.warn("***no-data***",cubeInfo.referenceModelBottom,cubeInfo)
  764. return false
  765. }
  766. positionY = referenceModel.position.z * 100 - (referenceModel.userData.modelHeight / 2 + cubeInfo
  767. .modelHeight / 2);
  768. positionY = positionY - parseFloat(cubeInfo.marginBottom);
  769. }
  770. if (parseInt(cubeInfo.referenceModelLeft) > 0) {
  771. const referenceModel = this.gltfLayouts.find(item => {
  772. const layoutModelData = item.userData;
  773. return layoutModelData.id == parseInt(cubeInfo.referenceModelLeft) && layoutModelData
  774. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  775. })
  776. if(!referenceModel){
  777. console.warn("***no-data***",cubeInfo.referenceModelLeft,cubeInfo)
  778. return false
  779. }
  780. positionX = referenceModel.position.x * 100 + (referenceModel.userData.modelWidth / 2 + cubeInfo
  781. .modelWidth / 2);
  782. positionX = positionX + parseFloat(cubeInfo.marginLeft);
  783. }
  784. if (parseInt(cubeInfo.referenceModelRight) > 0) {
  785. const referenceModel = this.gltfLayouts.find(item => {
  786. const layoutModelData = item.userData;
  787. return layoutModelData.id == parseInt(cubeInfo.referenceModelRight) && layoutModelData
  788. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  789. })
  790. if(!referenceModel){
  791. console.warn("***no-data***",cubeInfo.referenceModelRight,cubeInfo)
  792. return false
  793. }
  794. positionX = referenceModel.position.x * 100 - (referenceModel.userData.modelWidth / 2 + cubeInfo
  795. .modelWidth / 2);
  796. positionX = positionX - parseFloat(cubeInfo.marginRight);
  797. }
  798. if (cubeInfo.isFixedWidth == "false" || cubeInfo.isFixedHeight == "false") { // 固定尺寸
  799. // 靠墙拉伸
  800. if (cubeInfo.isStepAsideTop == 'true' && cubeInfo.isStepAsideBottom == 'true') {
  801. // console.log("高度拉伸", spaceHeight / modelHeight)
  802. positionY = centerY;
  803. if (curSpace.spaceWallInfo.wallN && curSpace.spaceWallInfo.wallS) {
  804. spaceHeight -= 20 + parseFloat(cubeInfo.marginTop) + parseFloat(cubeInfo.marginBottom);
  805. positionY += parseFloat(cubeInfo.marginTop) / 2 ;
  806. positionY -= parseFloat(cubeInfo.marginBottom) / 2;
  807. } else if (curSpace.spaceWallInfo.wallN) {
  808. spaceHeight -= 10 + parseFloat(cubeInfo.marginTop) + parseFloat(cubeInfo.marginBottom);
  809. positionY += 10 / 2;
  810. positionY += parseFloat(cubeInfo.marginTop) / 2;
  811. positionY -= parseFloat(cubeInfo.marginBottom) / 2;
  812. } else if (curSpace.spaceWallInfo.wallS) {
  813. spaceHeight -= 10 + parseFloat(cubeInfo.marginTop) + parseFloat(cubeInfo.marginBottom);
  814. positionY -= 10 / 2;
  815. positionY += parseFloat(cubeInfo.marginTop) / 2 ;
  816. positionY -= parseFloat(cubeInfo.marginBottom) / 2;
  817. }else {
  818. spaceHeight -= parseFloat(cubeInfo.marginTop) + parseFloat(cubeInfo.marginBottom);
  819. positionY += parseFloat(cubeInfo.marginTop) / 2 ;
  820. positionY -= parseFloat(cubeInfo.marginBottom) / 2;
  821. }
  822. // 计算缩放
  823. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  824. scaleY = spaceHeight / modelHeight;
  825. } else {
  826. scaleX = spaceHeight / modelHeight;
  827. }
  828. }
  829. // console.log("模型计算位置x--", cubeInfo.isStepAsideLeft, cubeInfo.isStepAsideRight)
  830. if (cubeInfo.isStepAsideLeft == 'true' && cubeInfo.isStepAsideRight == 'true') {
  831. // console.log("宽度拉伸11111", spaceWidth / modelWidth)
  832. positionX = centerX;
  833. if (curSpace.spaceWallInfo.wallW && curSpace.spaceWallInfo.wallE) {
  834. spaceWidth -= 20 + parseFloat(cubeInfo.marginLeft) + parseFloat(cubeInfo.marginRight);
  835. positionX += parseFloat(cubeInfo.marginLeft) / 2;
  836. positionX -= parseFloat(cubeInfo.marginRight) / 2;
  837. } else if (curSpace.spaceWallInfo.wallW) {
  838. spaceWidth -= 10 + parseFloat(cubeInfo.marginLeft) + parseFloat(cubeInfo.marginRight);
  839. positionX += 10 / 2;
  840. positionX += parseFloat(cubeInfo.marginLeft) / 2;
  841. positionX -= parseFloat(cubeInfo.marginRight) / 2;
  842. } else if (curSpace.spaceWallInfo.wallE) {
  843. spaceWidth -= 10 + parseFloat(cubeInfo.marginLeft) + parseFloat(cubeInfo.marginRight);
  844. positionX -= 10 / 2;
  845. positionX += parseFloat(cubeInfo.marginLeft) / 2;
  846. positionX -= parseFloat(cubeInfo.marginRight) / 2;
  847. }else {
  848. spaceWidth -= parseFloat(cubeInfo.marginLeft) + parseFloat(cubeInfo.marginRight);
  849. positionX += parseFloat(cubeInfo.marginLeft) / 2;
  850. positionX -= parseFloat(cubeInfo.marginRight) / 2;
  851. }
  852. // console.log("模型计算位置--", spaceWidth, modelWidth, scaleX, cubeInfo)
  853. // 计算缩放
  854. if (parseFloat(cubeInfo.rotation) == 90 || parseFloat(cubeInfo.rotation) == -90) {
  855. scaleX = spaceWidth / modelWidth;
  856. } else {
  857. scaleY = spaceWidth / modelWidth;
  858. }
  859. // console.log("模型计算位置--", spaceWidth, modelWidth, scaleX, cubeInfo)
  860. }
  861. // 单个参照物和墙面拉伸
  862. if (cubeInfo.isStepAsideTop == 'true' && parseInt(cubeInfo.referenceModelBottom) > 0) {
  863. const referenceModel = this.gltfLayouts.find(item => {
  864. const layoutModelData = item.userData;
  865. return layoutModelData.id == parseInt(cubeInfo.referenceModelBottom) && layoutModelData
  866. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  867. })
  868. const referenceModelPositionY = referenceModel.position.z * 100 - referenceModel.userData
  869. .modelHeight / 2 - parseFloat(cubeInfo.marginBottom);
  870. const wallPositionY = centerY - spaceHeight / 2 + (curSpace.spaceWallInfo.wallN ? 10 : 0) +
  871. parseFloat(cubeInfo.marginTop);
  872. const newModelHeight = Math.abs(referenceModelPositionY - wallPositionY);
  873. // console.log("上边拉伸", referenceModelPositionY, wallPositionY, newModelHeight)
  874. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  875. scaleY = newModelHeight / modelHeight;
  876. } else {
  877. scaleX = newModelHeight / modelHeight;
  878. }
  879. positionY = wallPositionY + newModelHeight / 2;
  880. }
  881. if (cubeInfo.isStepAsideBottom == 'true' && parseInt(cubeInfo.referenceModelTop) > 0) {
  882. const referenceModel = this.gltfLayouts.find(item => {
  883. const layoutModelData = item.userData;
  884. return layoutModelData.id == parseInt(cubeInfo.referenceModelTop) && layoutModelData
  885. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  886. })
  887. const referenceModelPositionY = referenceModel.position.z * 100 + referenceModel.userData
  888. .modelHeight / 2 + parseFloat(cubeInfo.marginTop) + (curSpace.spaceWallInfo.wallN ? 10 : 0);
  889. const wallPositionY = centerY + spaceHeight / 2 - (curSpace.spaceWallInfo.wallS ? 10 : 0) -
  890. parseFloat(cubeInfo.marginBottom);
  891. const newModelHeight = Math.abs(referenceModelPositionY - wallPositionY);
  892. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  893. scaleY = newModelHeight / modelHeight;
  894. } else {
  895. scaleX = newModelHeight / modelHeight;
  896. }
  897. positionY = wallPositionY - newModelHeight / 2;
  898. }
  899. if (cubeInfo.isStepAsideLeft == 'true' && parseInt(cubeInfo.referenceModelRight) > 0) {
  900. // console.log("左边拉伸")
  901. // 墙的位置
  902. const wallPositionX = centerX - spaceWidth / 2 + (curSpace.spaceWallInfo.wallW ? 10 : 0) +
  903. parseFloat(cubeInfo.marginLeft);
  904. // 右边参照模型位置
  905. const referenceModel = this.gltfLayouts.find(item => {
  906. const layoutModelData = item.userData;
  907. return layoutModelData.id == parseInt(cubeInfo.referenceModelRight) && layoutModelData
  908. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  909. })
  910. const referenceModelPositionX = referenceModel.position.x * 100 - referenceModel.userData
  911. .modelWidth / 2 - parseFloat(cubeInfo.marginRight);
  912. const newModelWidth = Math.abs(referenceModelPositionX - wallPositionX);
  913. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  914. scaleX = newModelWidth / modelWidth;
  915. } else {
  916. scaleY = newModelWidth / modelWidth;
  917. }
  918. positionX = wallPositionX + newModelWidth / 2;
  919. }
  920. if (cubeInfo.isStepAsideRight == 'true' && parseInt(cubeInfo.referenceModelLeft) > 0) {
  921. const referenceModel = this.gltfLayouts.find(item => {
  922. const layoutModelData = item.userData;
  923. return layoutModelData.id == parseInt(cubeInfo.referenceModelLeft) && layoutModelData
  924. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  925. })
  926. const referenceModelPositionX = referenceModel.position.x * 100 + referenceModel.userData
  927. .modelWidth / 2 + parseFloat(cubeInfo.marginLeft);
  928. const wallPositionX = centerX + spaceWidth / 2 - (curSpace.spaceWallInfo.wallE ? 10 : 0) -
  929. parseFloat(cubeInfo.marginRight);
  930. const newModelWidth = Math.abs(referenceModelPositionX - wallPositionX);
  931. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  932. scaleX = newModelWidth / modelWidth;
  933. } else {
  934. scaleY = newModelWidth / modelWidth;
  935. }
  936. positionX = wallPositionX - newModelWidth / 2;
  937. // console.log("右边拉伸", Math.abs(parseFloat(cubeInfo.rotation)))
  938. }
  939. if(parseInt(cubeInfo.referenceModelBottom) > 0 && parseInt(cubeInfo.referenceModelTop) > 0){
  940. // 上边惨遭物
  941. const referenceModelTop = this.gltfLayouts.find(item => {
  942. const layoutModelData = item.userData;
  943. return layoutModelData.id == parseInt(cubeInfo.referenceModelTop) && layoutModelData
  944. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  945. })
  946. // 下边参照物
  947. const referenceModelBottom = this.gltfLayouts.find(item => {
  948. const layoutModelData = item.userData;
  949. return layoutModelData.id == parseInt(cubeInfo.referenceModelBottom) && layoutModelData
  950. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  951. })
  952. const referenceModelTopPositionY = referenceModelTop.position.z * 100 + referenceModelTop.userData
  953. .modelHeight / 2 + parseFloat(cubeInfo.marginTop);
  954. const referenceModelBottomPositionY = referenceModelBottom.position.z * 100 - referenceModelBottom.userData
  955. .modelHeight / 2 - parseFloat(cubeInfo.marginBottom);
  956. const newModelHeight = Math.abs(referenceModelTopPositionY - referenceModelBottomPositionY);
  957. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  958. scaleY = newModelHeight / modelHeight;
  959. } else {
  960. scaleX = newModelHeight / modelHeight;
  961. }
  962. positionY = referenceModelBottomPositionY - newModelHeight / 2;
  963. }
  964. if(parseInt(cubeInfo.referenceModelLeft) > 0 && parseInt(cubeInfo.referenceModelRight) > 0){
  965. const referenceModelLeft = this.gltfLayouts.find(item => {
  966. const layoutModelData = item.userData;
  967. return layoutModelData.id == parseInt(cubeInfo.referenceModelLeft) && layoutModelData
  968. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  969. })
  970. const referenceModelRight = this.gltfLayouts.find(item => {
  971. const layoutModelData = item.userData;
  972. return layoutModelData.id == parseInt(cubeInfo.referenceModelRight) && layoutModelData
  973. .spaceId == cubeInfo.spaceId && layoutModelData.layoutId == cubeInfo.layoutId;
  974. })
  975. const referenceModelLeftPositionX = referenceModelLeft.position.x * 100 + referenceModelLeft.userData
  976. .modelWidth / 2 + parseFloat(cubeInfo.marginLeft);
  977. const referenceModelRightPositionX = referenceModelRight.position.x * 100 - referenceModelRight.userData
  978. .modelWidth / 2 - parseFloat(cubeInfo.marginRight);
  979. const newModelWidth = Math.abs(referenceModelLeftPositionX - referenceModelRightPositionX);
  980. if (Math.abs(parseFloat(cubeInfo.rotation)) == 90) {
  981. scaleX = newModelWidth / modelWidth;
  982. } else {
  983. scaleY = newModelWidth / modelWidth;
  984. }
  985. positionX = referenceModelRightPositionX - newModelWidth / 2;
  986. }
  987. }
  988. // console.log("模型计算位置--", positionX, positionY)
  989. // console.log("模型计算位置", cubeInfo, centerX, centerY, spaceWidth, spaceHeight, modelWidth, modelHeight, spaceId, scaleX, scaleY, positionX, positionY, cubeInfo.modelName)
  990. let oldPosition = new THREE.Vector3();//当前几何体的位置参数
  991. oldPosition.copy(cube.position);
  992. let oldScale = new THREE.Vector3();//当前几何体的位置参数
  993. oldScale.copy(cube.scale);
  994. cube.position.x = positionX / 100;
  995. cube.position.z = positionY / 100;
  996. cube.rotation.y = rotationY;
  997. cube.scale.x = scaleX;
  998. cube.scale.z = scaleY;
  999. cube.scale.y = 1;
  1000. cube.userData.modelWidth = modelWidth;
  1001. cube.userData.modelHeight = modelHeight;
  1002. // if (!cube.parent) { //说明还没添加到场景中-旧版方法
  1003. // this.scene.add(cube); //处理完毕后在加入场景中
  1004. // }
  1005. // if(scaleX>1 || scaleY>1){
  1006. // console.warn("***scaleinfo***",cubeInfo.id,scaleX,scaleY,cubeInfo.modelName)
  1007. // }
  1008. if(this.type==2){//全局精简加载
  1009. let name = cubeInfo.modelName.substring(0, cubeInfo.modelName.length - 2);
  1010. if(globlShowModel.includes(name)){
  1011. if(cubeInfo.modelName=='BP_XSPACE_deng_01_C'){//灯光
  1012. this.lightHandle(cube)
  1013. }else{
  1014. this.updateInfo(cube,oldPosition,oldScale);//实例化方法
  1015. }
  1016. }
  1017. }else{
  1018. if(cubeInfo.modelName=='BP_XSPACE_deng_01_C'){//灯光
  1019. this.lightHandle(cube)
  1020. }else{
  1021. this.updateInfo(cube,oldPosition,oldScale);//实例化方法
  1022. }
  1023. }
  1024. },
  1025. //更新家具模型到页面中
  1026. updateInfo(cube,oldPosition,oldScale){
  1027. const ssss = cube.scale.x / oldScale.x
  1028. // console.log("XXXXXXXXXXXXXXXXX", cube, oldPosition,oldScale, ssss)
  1029. let lay = this.gltfLayouts.find(it=>it.uniId==cube.uniId);
  1030. if(cube.instancedMeshIndexList && cube.instancedMeshIndexList.length>0){
  1031. cube.instancedMeshIndexList.forEach(item=>{
  1032. let index = item.instancedMeshIndex;
  1033. let instancedMesh = this.instancedFurList[index];//网格实例对象
  1034. let curMeshIndex = item.instancedAtIndex;//当前家具模型在网格实例对象里面的序号
  1035. let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
  1036. instancedMesh.getMatrixAt(curMeshIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
  1037. let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵
  1038. let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵
  1039. if (!lay.loaded) { //说明还没添加到场景中
  1040. // scaleMatrix.makeScale(scaleX,1,scaleY); //获得缩放变化矩阵
  1041. // panMatrix.makeTranslation(cube.position.x,0,cube.position.z); //获得平移变化矩阵
  1042. // stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵
  1043. // instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
  1044. // instancedMesh.setMatrixAt(curMeshIndex,stratMatrix);//更新几何体的世界矩阵
  1045. // this.scene.add(instancedMesh);
  1046. }else{//更新形变矩阵
  1047. scaleMatrix.makeScale(cube.scale.x / oldScale.x, 1, cube.scale.z/oldScale.z); //获得缩放变化矩阵
  1048. panMatrix.makeTranslation(cube.position.x - oldPosition.x,0,cube.position.z - oldPosition.z); //获得平移变化矩阵
  1049. stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵
  1050. instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
  1051. instancedMesh.setMatrixAt(curMeshIndex,stratMatrix);//更新几何体的世界矩阵
  1052. }
  1053. })
  1054. lay.loaded = true;
  1055. lay.userData = cube.userData;
  1056. }
  1057. },
  1058. // 空间处理光源
  1059. lightHandle(cube){
  1060. let light = this.gltfLayouts.find(it=>it.uniId==cube.uniId);
  1061. if(!light.loaded){
  1062. // 从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。
  1063. let pointLight = new THREE.PointLight(0xffd7b3, 1, 5, 1);
  1064. pointLight.position.set(cube.position.x, 1.5, cube.position.z); //default; light shining from top
  1065. this.scene.add(pointLight);
  1066. // let sphereSize = 0.1;
  1067. // let pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
  1068. // this.scene.add( pointLightHelper);
  1069. // pointLight.castShadow = true; // default false
  1070. // // 默认情况下光投影相机区域是一个长宽高为10x10x500的长方体区域,光源投射方向为通过坐标原点
  1071. // pointLight.shadow.camera.left = -200; // default
  1072. // pointLight.shadow.camera.right = 200; // default
  1073. // pointLight.shadow.camera.top = 200; // default
  1074. // pointLight.shadow.camera.bottom = -200; // default
  1075. this.scene.add(pointLight);
  1076. light.loaded = true;
  1077. }else{
  1078. }
  1079. },
  1080. // 空间布局旋转镜像重置模型约束
  1081. resetModelParameters(curSpace, cubeInfo) {
  1082. // 旋转
  1083. const defaultLayout = curSpace.layouts.find(item => {
  1084. return item.isDefault
  1085. })
  1086. if (!defaultLayout) {
  1087. return cubeInfo
  1088. }
  1089. let count = 0;
  1090. switch (parseInt(defaultLayout.layoutRotate)) {
  1091. case 90:
  1092. count = 1;
  1093. break;
  1094. case 180:
  1095. count = 2;
  1096. break;
  1097. case -90:
  1098. count = 3;
  1099. break;
  1100. default:
  1101. break;
  1102. }
  1103. for (let index = 0; index < count; index++) {
  1104. let oldCubeInfo = JSON.parse(JSON.stringify(cubeInfo))
  1105. oldCubeInfo.isStepAsideLeft = "false"
  1106. oldCubeInfo.isStepAsideTop = "false"
  1107. oldCubeInfo.isStepAsideRight = "false"
  1108. oldCubeInfo.isStepAsideBottom = "false"
  1109. oldCubeInfo.referenceModelLeft = "0"
  1110. oldCubeInfo.referenceModelTop = "0"
  1111. oldCubeInfo.referenceModelRight = "0"
  1112. oldCubeInfo.referenceModelBottom = "0"
  1113. oldCubeInfo.rotation = "0"
  1114. oldCubeInfo.marginLeft = "0";
  1115. oldCubeInfo.marginTop = "0";
  1116. oldCubeInfo.marginRight = "0";
  1117. oldCubeInfo.marginBottom = "0";
  1118. // 是否靠墙
  1119. if (cubeInfo.isStepAsideLeft == 'true') {
  1120. oldCubeInfo.isStepAsideTop = 'true'
  1121. }
  1122. if (cubeInfo.isStepAsideTop == 'true') {
  1123. oldCubeInfo.isStepAsideRight = 'true'
  1124. }
  1125. if (cubeInfo.isStepAsideRight == 'true') {
  1126. oldCubeInfo.isStepAsideBottom = 'true'
  1127. }
  1128. if (cubeInfo.isStepAsideBottom == 'true') {
  1129. oldCubeInfo.isStepAsideLeft = 'true'
  1130. }
  1131. // 参照物体
  1132. if (parseInt(cubeInfo.referenceModelLeft) > 0) {
  1133. oldCubeInfo.referenceModelTop = cubeInfo.referenceModelLeft;
  1134. }
  1135. if (parseInt(cubeInfo.referenceModelTop) > 0) {
  1136. oldCubeInfo.referenceModelRight = cubeInfo.referenceModelTop;
  1137. }
  1138. if (parseInt(cubeInfo.referenceModelRight) > 0) {
  1139. oldCubeInfo.referenceModelBottom = cubeInfo.referenceModelRight;
  1140. }
  1141. if (parseInt(cubeInfo.referenceModelBottom) > 0) {
  1142. oldCubeInfo.referenceModelLeft = cubeInfo.referenceModelBottom;
  1143. }
  1144. // 边距
  1145. oldCubeInfo.marginLeft = cubeInfo.marginBottom;
  1146. oldCubeInfo.marginTop = cubeInfo.marginLeft;
  1147. oldCubeInfo.marginRight = cubeInfo.marginTop;
  1148. oldCubeInfo.marginBottom = cubeInfo.marginRight;
  1149. oldCubeInfo.modelWidth = cubeInfo.modelHeight;
  1150. oldCubeInfo.modelHeight = cubeInfo.modelWidth;
  1151. // 旋转
  1152. if (parseInt(cubeInfo.rotation) == 0 || parseInt(cubeInfo.rotation) == 90) {
  1153. oldCubeInfo.rotation = parseInt(cubeInfo.rotation) + 90;
  1154. }
  1155. if (parseInt(cubeInfo.rotation) == 180) {
  1156. oldCubeInfo.rotation = "-90";
  1157. }
  1158. if (parseInt(cubeInfo.rotation) == -90) {
  1159. oldCubeInfo.rotation = "0";
  1160. }
  1161. // console.log("旋转前的模型参数X", cubeInfo, oldCubeInfo, defaultLayout)
  1162. cubeInfo = oldCubeInfo;
  1163. // console.log("旋转后的模型参数X", cubeInfo, oldCubeInfo, defaultLayout)
  1164. }
  1165. return cubeInfo;
  1166. },
  1167. //切换单个空间的布局到指定的布局上
  1168. changeSingleLayout(space,layoutObj){
  1169. if(!layoutObj){
  1170. console.warn("***changeSingleLayout***数据错误")
  1171. return false
  1172. }
  1173. // 更新空间的布局id
  1174. const element = this.spaceList.find(it=>it.spaceId == space.spaceId);
  1175. this.deleteLayoutModel(element, layoutObj);//删除当前空间的布局
  1176. element.layoutId = layoutObj.id;//更新布局信息到空间对象里面
  1177. if(space.spaceType==15){
  1178. element.layoutSpaceType = layoutObj.type;//更新布局信息到空间对象里面
  1179. element.layoutSpaceName = layoutObj.spacexName || layoutObj.name;//更新布局信息到空间对象里面
  1180. }
  1181. this.changeLayouts = [];
  1182. this.changeLayouts.push(layoutObj)
  1183. let changeSpaces = [];
  1184. changeSpaces.push(element)
  1185. console.log("新布局替换完成",this.changeLayouts, changeSpaces,this.arrFrunList.map(it=>it.id));
  1186. this.furnHandle(this.changeLayouts, changeSpaces);//先加载变化的空间的布局
  1187. this.updataPageData();//更新数据
  1188. },
  1189. // 改变空间模型
  1190. changeLayoutModel(){
  1191. let changeSpaces = [];
  1192. // 去重
  1193. for (let index = 0; index < this.changeSpaces.length; index++) {
  1194. const element = this.changeSpaces[index];
  1195. const findIndex = changeSpaces.findIndex((item)=>{
  1196. return item.spaceId == element.spaceId;
  1197. })
  1198. if(findIndex==-1){
  1199. const findListIndex = this.spaceList.findIndex((item)=>{
  1200. return item.spaceId == element.spaceId;
  1201. })
  1202. if(findListIndex !=-1 && this.spaceList[findListIndex].spaceType!=14){
  1203. changeSpaces.push(this.spaceList[findListIndex])
  1204. }
  1205. }
  1206. }
  1207. console.log("所有变化的空间", changeSpaces)
  1208. this.changeLayouts = [];
  1209. let promise_list = [];
  1210. if(!changeSpaces || changeSpaces.length==0){
  1211. // this.changeLayoutModelState(true); // 显示家具模型
  1212. return false;
  1213. }
  1214. this.clearAllLayoutData();//清除所有空间的家具模型
  1215. for (let index = 0; index < changeSpaces.length; index++) {
  1216. let element = changeSpaces[index];
  1217. let layoutObj = this.arrFrunList.find((item)=>{
  1218. return item.id == element.layoutId;
  1219. })
  1220. console.log("请求布局的对象",element?element.layoutId:"",layoutObj?layoutObj.id:"", layoutObj, element);
  1221. if(layoutObj){
  1222. promise_list.push(
  1223. new Promise((resolve, reject) => {
  1224. this.loadlayoutByID(layoutObj.groupType, element, resolve);
  1225. })
  1226. )
  1227. }else{//空间不存在布局,需要请求布局信息
  1228. promise_list.push(
  1229. new Promise((resolve, reject) => {
  1230. this.loadlayoutByID(element.groupType, element, resolve);
  1231. })
  1232. )
  1233. }
  1234. }
  1235. Promise.all(promise_list).then(()=>{
  1236. this.$nextTick(()=>{
  1237. console.log("新布局替换完成",this.changeLayouts, changeSpaces,this.arrFrunList.map(it=>it.id));
  1238. this.furnHandle(this.changeLayouts, changeSpaces);//先加载变化的空间的布局
  1239. this.updataPageData();//更新数据
  1240. })
  1241. })
  1242. },
  1243. async loadlayoutByID(groupType,spaceObj, resolve){
  1244. if(!groupType){
  1245. console.log("无法通过groupType请求布局", spaceObj.spaceId);
  1246. return resolve();
  1247. }
  1248. let param = {
  1249. "brandId": $config.brandId,
  1250. "houseId": this.curHouseObj.houseId,
  1251. "groupType": groupType
  1252. }
  1253. // 默认的布局
  1254. let res = await requestConfig("findOverallArrangementList", param);
  1255. if (!res.success || !res.pageModel || res.pageModel.resultSet.length == 0) {
  1256. return resolve();
  1257. }
  1258. const groupLayouts = res.pageModel.resultSet;
  1259. console.log("查询指定分组的布局", groupType, groupLayouts, spaceObj.spaceWidth, spaceObj.spaceHeight)
  1260. // 根据空间的尺寸和布局的最小尺寸,筛选出合适的最大的布局
  1261. const layouts01 = groupLayouts.filter((item)=>{
  1262. return item.minWidth <= spaceObj.spaceWidth && item.minDepth <= spaceObj.spaceHeight
  1263. })
  1264. console.log("过滤适合的布局01", layouts01)
  1265. // 长度和宽度都满足空间尺寸
  1266. const layouts02 = layouts01.filter((item)=>{
  1267. return (item.minWidth * item.minDepth ) <= (spaceObj.spaceWidth * spaceObj.spaceHeight)
  1268. })
  1269. console.log("过滤适合的布局02", layouts02)
  1270. // 取布局面积最大的一个
  1271. let layoutObj = null;
  1272. for (let index = 0; index < layouts02.length; index++) {
  1273. const element = layouts02[index];
  1274. if(!layoutObj){
  1275. layoutObj = element;
  1276. }else{
  1277. if((layoutObj.minWidth * layoutObj.minDepth) < (element.minWidth * element.minDepth)){
  1278. layoutObj = element;
  1279. }
  1280. }
  1281. }
  1282. if(layoutObj==null){
  1283. console.warn("没有合适的布局", layoutObj,spaceObj.layoutId);
  1284. spaceObj.groupType = groupType;
  1285. this.deleteLayoutModel(spaceObj, layoutObj);//删除当前的布局
  1286. return resolve()
  1287. }
  1288. console.log("找出最合适的布局", layoutObj)
  1289. console.log("更新空间的布局ID=", spaceObj.layoutId,'=>',layoutObj.id)
  1290. // 合适的布局更现有布局相同-不在需要了,因为这此之前已经把所有的家具都删除了
  1291. // if(spaceObj.layoutId == layoutObj.id && !spaceObj.delateLayoutId){
  1292. // // this.calculateLayoutModelSizeBySpace(spaceObj) // 提前计算模型的位置
  1293. // // this.changeLayoutModelState(true); // 显示家具模型
  1294. // return resolve()
  1295. // }
  1296. // 更新空间的布局id
  1297. const element = this.spaceList.find(it=>it.spaceId == spaceObj.spaceId);
  1298. if(element){
  1299. this.deleteLayoutModel(element, layoutObj)
  1300. element.layoutId = layoutObj.id;
  1301. if(element.spaceType==15){
  1302. element.layoutSpaceType = layoutObj.type;//更新布局信息到空间对象里面
  1303. element.layoutSpaceName = layoutObj.spacexName || layoutObj.name;//更新布局信息到空间对象里面
  1304. if(this.updataLable && typeof(this.updataLable)=='function'){
  1305. this.updataLable(element.spaceId,layoutObj);
  1306. }
  1307. }
  1308. console.log("替换空间的布局ID", spaceObj.spaceId, layoutObj.id);
  1309. }
  1310. this.changeLayouts.push(layoutObj)
  1311. resolve()
  1312. }
  1313. }
  1314. }