mainWind.threejs.ts 26 KB

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