mainWind.li3.threejs.ts 26 KB

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