mainWind.threejs.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. import * as THREE from 'three';
  2. import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
  3. import Smoke from '/@/views/vent/comment/threejs/Smoke';
  4. import { renderVideo } from '/@/utils/threejs/util';
  5. import gsap from 'gsap';
  6. class mainWindRect {
  7. model;
  8. modelName = 'main';
  9. group: THREE.Group | null = null; // 主通风机场景
  10. motorGroup1: THREE.Group | null = null; //电机
  11. motorGroup2: THREE.Group | null = null; //电机
  12. airJin1: THREE.Mesh | null = null; //风向箭头
  13. airJin2: THREE.Mesh | null = null; //风向箭头
  14. airChu1: THREE.Mesh | null = null; //风向箭头
  15. airChu2: THREE.Mesh | null = null; //风向箭头
  16. gearFront = {
  17. gear1: null, //扇叶
  18. gear2: null, //扇叶
  19. gear1Direction: -1,
  20. gear2Direction: 1,
  21. gearFrameId: undefined,
  22. gearRotateFactor: 0.5,
  23. endGearRotateFactor: 3,
  24. };
  25. gearBack = {
  26. gear1: null, //扇叶
  27. gear2: null, //扇叶
  28. gear1Direction: -1, // 扇叶转动方向
  29. gear2Direction: 1, // 扇叶转动方向
  30. gearFrameId: undefined,
  31. gearRotateFactor: 0.5, // 扇叶转动因素
  32. endGearRotateFactor: 3, // 扇叶最终转动速度因素
  33. };
  34. oldMaterial: THREE.Material = new THREE.MeshStandardMaterial();
  35. // smoke;
  36. frontSmoke: Smoke | null = null; // 前面风流对象
  37. backSmoke: Smoke | null = null; // 后面风流对象
  38. player1; // 视频播放器
  39. playerStartClickTime1 = new Date().getTime();
  40. frontWindowGroup;
  41. backWindowGroup;
  42. windowAngle = 0;
  43. fbmAnimationClip: THREE.AnimationClip | null = null;
  44. fbmMixers: THREE.AnimationMixer | null = null;
  45. fbmOpenAction: THREE.AnimationAction | null = null;
  46. constructor(model, playerVal1) {
  47. this.model = model;
  48. this.player1 = playerVal1;
  49. }
  50. // 添加 cssObject
  51. addCssText() {
  52. if (!this.group) {
  53. return;
  54. }
  55. const ztfjGroup = this.group.getObjectByName('ztfj');
  56. if (!this.group.getObjectByName('monitorText1')) {
  57. const worldPosition = new THREE.Vector3();
  58. ztfjGroup?.getObjectByName('Cylinder1042')?.getWorldPosition(worldPosition);
  59. const element = document.getElementById('inputBox') as HTMLElement;
  60. if (element) {
  61. const mainCSS3D = new CSS3DObject(element);
  62. mainCSS3D.name = 'monitorText1';
  63. mainCSS3D.scale.set(0.09, 0.09, 0.09);
  64. // mainCSS3D.position.set(23.78, 18.18, -6.85);
  65. mainCSS3D.position.set(worldPosition.x + 12, worldPosition.y - 10, worldPosition.z - 20);
  66. mainCSS3D.lookAt(worldPosition.x + 12, worldPosition.y - 0, worldPosition.z + 2);
  67. this.group.add(mainCSS3D);
  68. }
  69. }
  70. if (!this.group.getObjectByName('monitorText2')) {
  71. const worldPosition = new THREE.Vector3();
  72. ztfjGroup?.getObjectByName('Cylinder396')?.getWorldPosition(worldPosition);
  73. const element = document.getElementById('inputBox1') as HTMLElement;
  74. if (element) {
  75. const mainCSS3D = new CSS3DObject(element);
  76. mainCSS3D.name = 'monitorText2';
  77. mainCSS3D.scale.set(0.09, 0.09, 0.09);
  78. // mainCSS3D.position.set(23.78, 18.18, 16.82);
  79. mainCSS3D.position.set(worldPosition.x + 12, worldPosition.y - 10, worldPosition.z - 20);
  80. mainCSS3D.lookAt(worldPosition.x + 12, worldPosition.y - 0, worldPosition.z + 2);
  81. // mainCSS3D.lookAt(23.78, 20, 20.82);
  82. this.group.add(mainCSS3D);
  83. }
  84. }
  85. if (!this.group.getObjectByName('monitorText4')) {
  86. const worldPosition = new THREE.Vector3();
  87. const fbmGroup = this.group?.getObjectByName('fbm') as THREE.Group;
  88. if (fbmGroup) {
  89. fbmGroup?.getObjectByName('Box022')?.getWorldPosition(worldPosition);
  90. const element = document.getElementById('fbm') as HTMLElement;
  91. if (element) {
  92. const mainCSS3D = new CSS3DObject(element);
  93. mainCSS3D.name = 'monitorText4';
  94. mainCSS3D.scale.set(0.07, 0.07, 0.07);
  95. mainCSS3D.position.set(worldPosition.x + 20, worldPosition.y - 8, worldPosition.z - 20);
  96. mainCSS3D.lookAt(worldPosition.x + 20, worldPosition.y - 0, worldPosition.z + 2);
  97. this.group.add(mainCSS3D);
  98. }
  99. }
  100. }
  101. }
  102. clearCssText() {
  103. if (this.group) {
  104. const mainCSS3D1 = this.group.getObjectByName('monitorText1');
  105. const mainCSS3D2 = this.group.getObjectByName('monitorText2');
  106. if (mainCSS3D1) this.group.remove(mainCSS3D1);
  107. if (mainCSS3D2) this.group.remove(mainCSS3D2);
  108. }
  109. }
  110. addEcharts() {
  111. const echartsBox = document.getElementById('fan-echarts');
  112. if (echartsBox) {
  113. const canvasObj = echartsBox.getElementsByTagName('canvas')[0];
  114. // 将canvas 纹理转换为材质
  115. const echartsMap = new THREE.CanvasTexture(canvasObj); // 关键一步
  116. const echartsMaterial = new THREE.MeshBasicMaterial({
  117. map: echartsMap, // 设置纹理贴图
  118. transparent: true,
  119. side: THREE.FrontSide, // 这里是双面渲染的意思
  120. });
  121. echartsMaterial.blending = THREE.CustomBlending;
  122. const monitorPlane = this.group?.getObjectByName('monitorEcharts');
  123. if (monitorPlane) {
  124. monitorPlane.material = echartsMaterial;
  125. } else {
  126. const planeGeometry = new THREE.PlaneGeometry(17.6, 9.9); // 平面3维几何体PlaneGeometry
  127. const planeMesh = new THREE.Mesh(planeGeometry, echartsMaterial);
  128. planeMesh.name = 'monitorEcharts';
  129. planeMesh.scale.set(1, 1, 1);
  130. planeMesh.position.set(-47.38, 13.227, -21.79);
  131. this.group?.add(planeMesh);
  132. }
  133. }
  134. }
  135. initAnimation() {}
  136. startAnimation() {}
  137. /* 更新动画 */
  138. render() {
  139. if (!this.model) {
  140. return;
  141. }
  142. if (this.fbmMixers) this.fbmMixers?.update(1 / 25);
  143. }
  144. /* 点击风窗,风窗全屏 */
  145. mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
  146. // 判断是否点击到视频
  147. intersects.find((intersect) => {
  148. const mesh = intersect.object;
  149. if (mesh.name === 'player1') {
  150. if (new Date().getTime() - this.playerStartClickTime1 < 400) {
  151. // 双击,视频放大
  152. if (this.player1) {
  153. this.player1.requestFullscreen();
  154. }
  155. }
  156. this.playerStartClickTime1 = new Date().getTime();
  157. return true;
  158. }
  159. return false;
  160. });
  161. }
  162. mouseUpModel() {}
  163. async setDeviceFrequency(deviceType, state, frequencyVal?) {
  164. debugger;
  165. // 调节频率
  166. if (frequencyVal) {
  167. this.resetSmokeParam(deviceType, frequencyVal, 0);
  168. }
  169. this.openOrCloseValve(deviceType, state, 0);
  170. this.startGearAnimation(deviceType, state, '', 0);
  171. if (deviceType === 'front') {
  172. this.frontSmoke?.startSmoke();
  173. } else {
  174. this.backSmoke?.startSmoke();
  175. }
  176. setTimeout(() => {
  177. this.lookMotor(deviceType, state, 10);
  178. }, 2000);
  179. }
  180. async openDevice(deviceType, smokeDirection, frequencyVal, duration?) {
  181. if (smokeDirection) {
  182. this.setSmokeDirection(deviceType, smokeDirection);
  183. }
  184. let smoke;
  185. if (deviceType === 'front') {
  186. smoke = this.frontSmoke;
  187. } else {
  188. smoke = this.backSmoke;
  189. }
  190. if (!smoke.frameId) {
  191. await this.lookMotor(deviceType, 'open', duration);
  192. await this.openOrCloseValve(deviceType, 'open', duration);
  193. this.startGearAnimation(deviceType, 'open', smokeDirection, frequencyVal, duration);
  194. debugger;
  195. smoke.startSmoke(duration);
  196. }
  197. }
  198. async closeDevice(deviceType, flag = true) {
  199. let smoke;
  200. if (deviceType === 'front') {
  201. smoke = this.frontSmoke;
  202. } else if (deviceType === 'back') {
  203. smoke = this.backSmoke;
  204. }
  205. if (smoke && smoke.frameId) {
  206. if (flag) {
  207. smoke.stopSmoke();
  208. await this.openOrCloseValve(deviceType, 'close');
  209. this.startGearAnimation(deviceType, 'close', '', null);
  210. await this.lookMotor(deviceType, 'close');
  211. } else {
  212. smoke.stopSmoke(0);
  213. await this.openOrCloseValve(deviceType, 'close', 0);
  214. this.startGearAnimation(deviceType, 'close', '', null, 0);
  215. await this.lookMotor(deviceType, 'close', 0);
  216. }
  217. }
  218. }
  219. async setSmokeDirection(deviceType, smokeDirection) {
  220. const windowPositivePath = [
  221. {
  222. path0: new THREE.Vector3(4.441, 20.267, 3.614),
  223. path1: new THREE.Vector3(5.041, 6.806, 3.614),
  224. isSpread: true,
  225. spreadDirection: -1, //
  226. },
  227. {
  228. path0: new THREE.Vector3(7.441, 0.806, 3.614),
  229. path1: new THREE.Vector3(41.583, 1.485, 3.614),
  230. isSpread: false,
  231. spreadDirection: 0, //
  232. },
  233. {
  234. path0: new THREE.Vector3(41.583, 1.485, 3.614),
  235. path1: new THREE.Vector3(42.741, 5.364, 3.614),
  236. isSpread: false,
  237. spreadDirection: 0,
  238. },
  239. {
  240. path0: new THREE.Vector3(42.741, 5.364, 3.614),
  241. path1: new THREE.Vector3(44.741, 17.267, 3.614),
  242. isSpread: true,
  243. spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
  244. },
  245. ];
  246. const windowInversePath = [
  247. {
  248. path0: new THREE.Vector3(44.741, 17.267, 3.614),
  249. path1: new THREE.Vector3(42.741, 5.364, 3.614),
  250. isSpread: true,
  251. spreadDirection: -1, //
  252. },
  253. {
  254. path0: new THREE.Vector3(42.741, 5.364, 3.614),
  255. path1: new THREE.Vector3(41.583, 1.485, 3.614),
  256. isSpread: false,
  257. spreadDirection: 0, //
  258. },
  259. {
  260. path0: new THREE.Vector3(41.583, 1.485, 3.614),
  261. path1: new THREE.Vector3(7.441, 0.806, 3.614),
  262. isSpread: false,
  263. spreadDirection: 0, // 1是由小变大,-1是由大变小
  264. },
  265. {
  266. path0: new THREE.Vector3(4.441, 17.267, 3.614),
  267. path1: new THREE.Vector3(5.041, 6.806, 3.614),
  268. isSpread: true,
  269. spreadDirection: 1, //
  270. },
  271. ];
  272. const tubPositivePath = [
  273. {
  274. path0: new THREE.Vector3(7.441, 0.806, 3.614),
  275. path1: new THREE.Vector3(44.583, 1.485, 3.614),
  276. isSpread: false,
  277. spreadDirection: 0, //
  278. },
  279. {
  280. path0: new THREE.Vector3(44.583, 1.485, 3.614),
  281. path1: new THREE.Vector3(45.741, 5.364, 3.614),
  282. isSpread: false,
  283. spreadDirection: 0,
  284. },
  285. {
  286. path0: new THREE.Vector3(45.741, 5.364, 3.614),
  287. path1: new THREE.Vector3(47.741, 17.267, 3.614),
  288. isSpread: true,
  289. spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
  290. },
  291. ];
  292. const tubInversePath = [
  293. {
  294. path0: new THREE.Vector3(47.741, 17.267, 3.614),
  295. path1: new THREE.Vector3(45.741, 5.364, 3.614),
  296. isSpread: true,
  297. spreadDirection: -1, //
  298. },
  299. {
  300. path0: new THREE.Vector3(45.741, 5.364, 3.614),
  301. path1: new THREE.Vector3(44.583, 1.485, 3.614),
  302. isSpread: false,
  303. spreadDirection: 0, //
  304. },
  305. {
  306. path0: new THREE.Vector3(44.583, 1.485, 3.614),
  307. path1: new THREE.Vector3(7.441, 0.806, 3.614),
  308. isSpread: false,
  309. spreadDirection: 0, // 1是由小变大,-1是由大变小
  310. },
  311. ];
  312. let smoke;
  313. if (deviceType === 'front') {
  314. smoke = this.frontSmoke;
  315. } else if (deviceType === 'back') {
  316. smoke = this.backSmoke;
  317. }
  318. switch (smokeDirection) {
  319. case 'tubPositivePath': // 风筒正
  320. smoke.setPath(tubPositivePath);
  321. break;
  322. case 'tubInversePath': // 风筒反
  323. smoke.setPath(tubInversePath);
  324. break;
  325. case 'windowPositivePath': // 风窗正
  326. smoke.setPath(windowPositivePath);
  327. break;
  328. case 'windowInversePath': // 风窗反
  329. smoke.setPath(windowInversePath);
  330. break;
  331. }
  332. }
  333. /* 播放气流动画 */
  334. /**
  335. *
  336. * @param controlType // 设备控制类型
  337. * @param deviceType //前后风机
  338. * @param frequencyVal // 风机运行频率
  339. * @param state // 打开、关闭状态
  340. */
  341. async playSmoke(controlType, deviceType, frequencyVal, state, smokeDirection) {
  342. debugger;
  343. if (frequencyVal) {
  344. this.resetSmokeParam(deviceType, frequencyVal);
  345. }
  346. if (controlType === 'startSmoke') {
  347. if (state === 'stop') {
  348. await this.closeDevice(deviceType);
  349. } else {
  350. // 开启时需要设置方向
  351. await this.openDevice(deviceType, smokeDirection, frequencyVal);
  352. }
  353. } else if (controlType === 'changeDirection') {
  354. // 改变扇叶转动方向、反风
  355. this.startGearAnimation(deviceType, 'changeDirection', smokeDirection, frequencyVal);
  356. let smoke;
  357. if (deviceType === 'front') {
  358. smoke = this.frontSmoke;
  359. } else {
  360. smoke = this.backSmoke;
  361. }
  362. if (smoke && smoke.frameId) {
  363. await smoke.stopSmoke();
  364. await this.setSmokeDirection(deviceType, smokeDirection);
  365. debugger;
  366. smoke.startSmoke();
  367. }
  368. } else if (controlType === 'frequency') {
  369. this.startGearAnimation(deviceType, 'frequency', smokeDirection, frequencyVal);
  370. } else if (controlType === 'initiatePlay') {
  371. this.openDevice(deviceType, smokeDirection, frequencyVal, 0);
  372. } else if (controlType === 'changeSmoke') {
  373. //
  374. }
  375. }
  376. stopSmoke() {
  377. this.closeDevice('front', false);
  378. this.closeDevice('back', false);
  379. }
  380. /* 打开或关闭蝶阀 */
  381. openOrCloseValve(deviceType, flag, duration = 3) {
  382. const ztfjGroup = this.group?.getObjectByName('ztfj');
  383. return new Promise((resolve) => {
  384. let diefa;
  385. if (deviceType == 'front') {
  386. diefa = ztfjGroup?.getObjectByName('butterfly_valve001') as THREE.Mesh;
  387. } else {
  388. diefa = ztfjGroup?.getObjectByName('butterfly_valve002') as THREE.Mesh;
  389. }
  390. let rotationY;
  391. if (flag == 'open') {
  392. rotationY = 0;
  393. } else {
  394. rotationY = Math.PI / 2;
  395. }
  396. if (diefa) {
  397. gsap.to(diefa.rotation, {
  398. y: rotationY,
  399. duration: duration,
  400. ease: 'none',
  401. onComplete: function () {
  402. resolve(null);
  403. },
  404. });
  405. }
  406. });
  407. }
  408. /* 风流调频, 范围1-50 */
  409. // opacityFactor (0.4 300)
  410. // life 最小 300, 最大 50
  411. // speedFactor 最大0, 最小100
  412. resetSmokeParam(deviceType, frequency, duration = 5) {
  413. if (frequency < 1) frequency = 1;
  414. if (frequency > 50) frequency = 50;
  415. let smoke;
  416. if (deviceType === 'front') {
  417. smoke = this.frontSmoke;
  418. } else {
  419. smoke = this.backSmoke;
  420. }
  421. const opacityFactor = (frequency / 50) * 0.8;
  422. duration = (Number(Math.abs(smoke.opacityFactor - opacityFactor).toFixed(1)) / 0.8) * 5;
  423. const life = (-250 / 50) * frequency + 300;
  424. gsap.to(smoke, {
  425. opacityFactor: opacityFactor,
  426. life: life,
  427. duration: duration,
  428. ease: 'easeInCirc',
  429. overwrite: true,
  430. });
  431. }
  432. /* 显示电机 */
  433. lookMotor(deviceType, flag, duration = 5) {
  434. return new Promise((resolve) => {
  435. const ztfjGroup = this.group?.getObjectByName('ztfj');
  436. let mesh, mesh1, mesh2, motorGroup;
  437. mesh1 = ztfjGroup?.getObjectByName('TWO00'); //前
  438. mesh2 = ztfjGroup?.getObjectByName('ONE00'); //后
  439. if (deviceType == 'front') {
  440. mesh = mesh1;
  441. motorGroup = this.motorGroup2;
  442. } else {
  443. mesh = mesh2;
  444. motorGroup = this.motorGroup1;
  445. }
  446. if (mesh && motorGroup) {
  447. if (flag == 'open') {
  448. mesh.material.depthWrite = false;
  449. mesh.material.depthTest = false;
  450. motorGroup.visible = true;
  451. gsap.to(mesh.material, {
  452. opacity: 0.1,
  453. duration: duration,
  454. overwrite: true,
  455. onComplete: function () {
  456. // mesh.material.color = '#000';
  457. resolve(null);
  458. },
  459. });
  460. } else {
  461. const opacity = mesh.material.opacity;
  462. Object.assign(mesh.material, this.oldMaterial, { opacity: opacity });
  463. mesh.material.depthWrite = true;
  464. mesh.material.depthTest = true;
  465. gsap.to(mesh.material, {
  466. opacity: 1,
  467. duration: 1,
  468. overwrite: true,
  469. onComplete: function () {
  470. resolve(null);
  471. },
  472. });
  473. }
  474. }
  475. });
  476. }
  477. /* 齿轮转动动画 1 - 50 最大3 */
  478. startGearAnimation(deviceType, flag, smokeDirection, frequencyVal, duration = 8) {
  479. let gearObj, gearDirection;
  480. if (deviceType === 'front') {
  481. gearObj = this.gearFront;
  482. } else {
  483. gearObj = this.gearBack;
  484. }
  485. if (smokeDirection === 'tubPositivePath') {
  486. gearDirection = 1;
  487. } else if (smokeDirection === 'tubInversePath') {
  488. gearDirection = -1;
  489. }
  490. if (frequencyVal) {
  491. const endGearRotateFactor = (3 / 50) * frequencyVal;
  492. duration = (8 / 3) * Math.abs(gearObj.endGearRotateFactor - endGearRotateFactor);
  493. gearObj.endGearRotateFactor = endGearRotateFactor;
  494. }
  495. const gearAnimation = () => {
  496. gsap.to(gearObj, {
  497. gearRotateFactor: gearObj.endGearRotateFactor,
  498. duration: duration,
  499. ease: 'easeInCubic',
  500. repeat: 0,
  501. overwrite: true,
  502. });
  503. const clock = new THREE.Clock(); // 时钟
  504. const h = () => {
  505. if (gearObj.gear1 && gearObj.gear2) {
  506. gearObj.gearFrameId = requestAnimationFrame(h);
  507. const dt = clock.getDelta();
  508. gearObj.gear1.rotation.x += dt * gearObj.gearRotateFactor * gearObj.gear1Direction;
  509. gearObj.gear2.rotation.x += dt * gearObj.gearRotateFactor * gearObj.gear2Direction;
  510. }
  511. };
  512. h();
  513. };
  514. if (flag === 'changeDirection') {
  515. if (gearDirection == -1 * gearObj.gear1Direction) {
  516. // 齿轮正在转,需要停止后再反方向转
  517. gsap.to(gearObj, {
  518. gearRotateFactor: 0,
  519. duration: duration,
  520. ease: 'easeInCubic',
  521. repeat: 0,
  522. onComplete: function () {
  523. window.cancelAnimationFrame(gearObj.gearFrameId);
  524. gearObj.gearFrameId = undefined;
  525. gearObj.gear1Direction = -1 * gearObj.gear1Direction;
  526. gearObj.gear2Direction = -1 * gearObj.gear2Direction;
  527. gearAnimation();
  528. },
  529. });
  530. }
  531. } else if (flag === 'open') {
  532. gearObj.gear1Direction = gearDirection;
  533. gearObj.gear2Direction = -1 * gearDirection;
  534. gearAnimation();
  535. } else if (flag === 'close') {
  536. gsap.to(gearObj, {
  537. gearRotateFactor: 0,
  538. duration: duration,
  539. ease: 'easeInCubic',
  540. repeat: 0,
  541. overwrite: true,
  542. onComplete: function () {
  543. window.cancelAnimationFrame(gearObj.gearFrameId);
  544. gearObj.gearFrameId = undefined;
  545. },
  546. });
  547. } else if (flag === 'frequency') {
  548. gsap.to(gearObj, {
  549. gearRotateFactor: gearObj.endGearRotateFactor,
  550. duration: duration,
  551. ease: 'easeInCubic',
  552. repeat: 0,
  553. overwrite: true,
  554. });
  555. }
  556. }
  557. /* 初始化口上面的气体 */
  558. initSmokeMass() {
  559. if (!this.frontSmoke) {
  560. this.frontSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 1.8, 100);
  561. }
  562. if (!this.backSmoke) {
  563. this.backSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 1.8, 100);
  564. }
  565. }
  566. /* 设置气流位置 */
  567. async setSmokePosition() {
  568. if (this.frontSmoke) {
  569. await this.frontSmoke.setPoints();
  570. this.frontSmoke.points.name = 'frontSmoke';
  571. this.group?.add(this.frontSmoke.points);
  572. // this.frontSmoke.points.position.set(-2.51, 2.51, 8.25);
  573. this.frontSmoke.points.position.set(-2.51, 2.51, 13.25);
  574. }
  575. if (this.backSmoke) {
  576. await this.backSmoke.setPoints();
  577. this.backSmoke.points.name = 'backSmoke';
  578. this.group?.add(this.backSmoke.points);
  579. // this.backSmoke.points.position.set(-2.2, 3.13, -7.8);
  580. this.backSmoke.points.position.set(-2.2, 3.13, -2.8);
  581. }
  582. }
  583. /** 初始化电机 */
  584. async initMotor() {
  585. // 前电机
  586. const motorGltf1 = await this.model.setGLTFModel('dj1');
  587. this.motorGroup1 = motorGltf1[0] as THREE.Group;
  588. this.motorGroup1?.position.set(0, 0, 5);
  589. this.motorGroup1.visible = false;
  590. this.motorGroup1.traverse((item) => {
  591. if (item instanceof THREE.Object3D) {
  592. item.renderOrder = -1;
  593. if (item.name === 'fan_blade003') {
  594. // @ts-ignore
  595. this.gearBack.gear1 = item as THREE.Group;
  596. } else if (item.name === 'fan_blade005') {
  597. // @ts-ignore
  598. this.gearBack.gear2 = item as THREE.Group;
  599. }
  600. }
  601. });
  602. this.motorGroup1.renderOrder = -1;
  603. this.group?.add(this.motorGroup1);
  604. // 后电机
  605. const motorGltf2 = await this.model.setGLTFModel('dj2');
  606. this.motorGroup2 = motorGltf2[0] as THREE.Group;
  607. this.motorGroup2?.position.set(0, 0, 5);
  608. this.motorGroup2.visible = false;
  609. this.motorGroup2.traverse((item) => {
  610. if (item instanceof THREE.Object3D) {
  611. item.renderOrder = -1;
  612. if (item.name === 'fan_blade007') {
  613. // @ts-ignore
  614. this.gearFront.gear1 = item as THREE.Group;
  615. } else if (item.name === 'fan_blade006') {
  616. // @ts-ignore
  617. this.gearFront.gear2 = item as THREE.Group;
  618. }
  619. }
  620. });
  621. this.motorGroup2.renderOrder = -1;
  622. this.group?.add(this.motorGroup2);
  623. }
  624. openOrCloseWindow(deviceType, flag) {
  625. const _this = this;
  626. let endAngle = 0,
  627. windowGroup;
  628. if (deviceType === 'front') {
  629. windowGroup = this.frontWindowGroup;
  630. }
  631. if (deviceType === 'back') {
  632. windowGroup = this.backWindowGroup;
  633. }
  634. if (flag == 'openWindow') {
  635. // 打开风窗
  636. endAngle = 1;
  637. } else {
  638. // 关闭风窗
  639. endAngle = 0;
  640. }
  641. if (windowGroup)
  642. gsap.to(this, {
  643. windowAngle: endAngle,
  644. duration: Math.abs(endAngle - this.windowAngle) * 10,
  645. ease: 'none',
  646. onUpdate: function () {
  647. windowGroup.children.forEach((mesh) => {
  648. mesh.rotation.z = _this.windowAngle;
  649. });
  650. },
  651. });
  652. }
  653. /** 初始化风窗 */
  654. initWindow() {
  655. if (!this.group) return;
  656. this.frontWindowGroup = new THREE.Group();
  657. this.frontWindowGroup.name = 'frontWindowGroup';
  658. this.backWindowGroup = new THREE.Group();
  659. this.backWindowGroup.name = 'backWindowGroup';
  660. if (this.group && this.group?.children.length > 0) {
  661. for (let i = this.group?.children.length - 1; i >= 0; i--) {
  662. const obj = this.group?.children[i];
  663. if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('TC')) {
  664. const mesh = obj.clone();
  665. if (obj.name.startsWith('TC1')) {
  666. this.backWindowGroup.add(mesh);
  667. } else if (obj.name.startsWith('TC2')) {
  668. this.frontWindowGroup.add(mesh);
  669. }
  670. obj.removeFromParent();
  671. this.group?.remove(obj);
  672. }
  673. }
  674. }
  675. this.group?.add(this.backWindowGroup);
  676. this.group?.add(this.frontWindowGroup);
  677. }
  678. initFbmAnimation() {
  679. const fbmGroup = this.group?.getObjectByName('fbm') as THREE.Group;
  680. if (fbmGroup) {
  681. this.fbmAnimationClip = fbmGroup.animations[0];
  682. this.fbmMixers = new THREE.AnimationMixer(fbmGroup);
  683. this.fbmOpenAction = this.fbmMixers.clipAction(this.fbmAnimationClip);
  684. this.fbmOpenAction.loop = THREE.LoopOnce;
  685. this.fbmOpenAction.clampWhenFinished = true;
  686. this.fbmMixers.timeScale = 0.15;
  687. }
  688. }
  689. playAnimation(flag, duration?) {
  690. if (this.fbmOpenAction && this.fbmMixers && this.fbmAnimationClip) {
  691. if (duration == 0) {
  692. if (flag == 'open') {
  693. this.fbmOpenAction.reset();
  694. this.fbmOpenAction.time = this.fbmAnimationClip.duration;
  695. this.fbmOpenAction.timeScale = 1;
  696. } else {
  697. this.fbmOpenAction.reset();
  698. this.fbmOpenAction.time = 0;
  699. this.fbmOpenAction.timeScale = -1;
  700. }
  701. this.fbmOpenAction.play();
  702. } else {
  703. if (flag == 'open') {
  704. this.fbmOpenAction.reset();
  705. this.fbmOpenAction.time = 0;
  706. this.fbmOpenAction.timeScale = 1;
  707. this.fbmOpenAction.play();
  708. } else {
  709. this.fbmOpenAction.reset();
  710. this.fbmOpenAction.time = this.fbmAnimationClip.duration;
  711. this.fbmOpenAction.timeScale = -1;
  712. this.fbmOpenAction.play();
  713. }
  714. }
  715. }
  716. }
  717. mountedThree() {
  718. this.group = new THREE.Group();
  719. return new Promise(async (resolve) => {
  720. this.model.setGLTFModel(['bg1', 'fbm', 'ztfj', 'ztfj-fc'], this.group).then(async () => {
  721. // this.group = gltf[0];
  722. this.group?.position.set(-0.44, 19.88, 22.37);
  723. this.initSmokeMass();
  724. await this.setSmokePosition();
  725. debugger;
  726. const ztfjGroup = this.group?.getObjectByName('ztfj') as THREE.Group;
  727. const fbmGroup = this.group?.getObjectByName('fbm') as THREE.Group;
  728. const fcGroup = this.group?.getObjectByName('ztfj-fc') as THREE.Group;
  729. if (ztfjGroup) {
  730. ztfjGroup.position.z = ztfjGroup.position.z + 5;
  731. const airJinGroup = ztfjGroup.getObjectByName('JianTou1_Jin') as THREE.Object3D;
  732. const airChuGroup = ztfjGroup.getObjectByName('JianTou2_Chu') as THREE.Object3D;
  733. this.airJin1 = airJinGroup.getObjectByName('Jin_1') as THREE.Mesh;
  734. this.airJin2 = airJinGroup.getObjectByName('Jin_2') as THREE.Mesh;
  735. this.airChu1 = airChuGroup.getObjectByName('Chu_1') as THREE.Mesh;
  736. this.airChu2 = airChuGroup.getObjectByName('Chu_2') as THREE.Mesh;
  737. }
  738. if (fbmGroup) fbmGroup.position.z = fbmGroup.position.z + 5;
  739. if (fcGroup) fcGroup.position.z = fcGroup.position.z + 5;
  740. const mesh = ztfjGroup?.getObjectByName('jizu06') as THREE.Mesh; //前
  741. if (mesh && mesh.material) this.oldMaterial = mesh.material as THREE.MeshStandardMaterial;
  742. await this.initMotor();
  743. resolve(null);
  744. this.initWindow();
  745. this.initFbmAnimation();
  746. });
  747. });
  748. }
  749. destroy() {
  750. this.frontSmoke.clearSmoke();
  751. this.backSmoke.clearSmoke();
  752. const fbmGroup = this.group?.getObjectByName('fbm') as THREE.Group;
  753. if (this.fbmMixers && this.fbmAnimationClip && this.fbmOpenAction && fbmGroup) {
  754. this.fbmMixers.uncacheClip(this.fbmAnimationClip);
  755. this.fbmMixers.uncacheAction(this.fbmOpenAction.getClip(), fbmGroup);
  756. this.fbmMixers.uncacheRoot(fbmGroup);
  757. this.fbmAnimationClip.tracks = [];
  758. this.fbmAnimationClip = undefined;
  759. this.fbmOpenAction = undefined;
  760. }
  761. this.model.clearGroup(this.motorGroup1);
  762. this.model.clearGroup(this.motorGroup2);
  763. this.model.clearGroup(this.group);
  764. this.motorGroup1 = undefined;
  765. this.motorGroup2 = undefined;
  766. this.gearFront.gear1 = undefined;
  767. this.gearFront.gear2 = undefined;
  768. this.gearBack.gear1 = undefined;
  769. this.gearBack.gear2 = undefined;
  770. this.frontSmoke = undefined;
  771. this.backSmoke = undefined;
  772. this.model = undefined;
  773. this.group = undefined;
  774. }
  775. }
  776. export default mainWindRect;