fireDoor.threejs.ssl.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import * as THREE from 'three';
  2. import { useAppStore } from '/@/store/modules/app';
  3. // import * as dat from 'dat.gui';
  4. // const gui = new dat.GUI();
  5. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  6. class FireDoorSsl {
  7. modelName = 'fireDoorSsl';
  8. model; //
  9. group;
  10. isLRAnimation = true; // 是否开启左右摇摆动画
  11. direction = 1; // 摇摆方向
  12. animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
  13. player1;
  14. player2;
  15. deviceDetailCSS3D;
  16. playerStartClickTime1 = new Date().getTime();
  17. playerStartClickTime2 = new Date().getTime();
  18. fmClock = new THREE.Clock();
  19. mixers: THREE.AnimationMixer | undefined;
  20. appStore = useAppStore();
  21. damperOpenMesh;
  22. damperClosedMesh;
  23. clipActionArr: Record<string, THREE.AnimationAction | undefined> = {
  24. /** 卷帘门动画 */
  25. juanlianmen: undefined,
  26. /** 盖板动画 */
  27. gaiban: undefined,
  28. };
  29. constructor(model) {
  30. this.model = model;
  31. }
  32. addLight() {
  33. const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
  34. directionalLight.position.set(344, 690, 344);
  35. this.group?.add(directionalLight);
  36. directionalLight.target = this.group as THREE.Object3D;
  37. const pointLight2 = new THREE.PointLight(0xffeeee, 1, 300);
  38. pointLight2.position.set(-4, 10, 1.8);
  39. pointLight2.shadow.bias = 0.05;
  40. this.group?.add(pointLight2);
  41. const pointLight3 = new THREE.PointLight(0xffeeee, 1, 200);
  42. pointLight3.position.set(-0.5, -0.5, 0.75);
  43. pointLight3.shadow.bias = 0.05;
  44. this.group?.add(pointLight3);
  45. }
  46. resetCamera() {
  47. this.model.camera.far = 274;
  48. this.model.orbitControls?.update();
  49. this.model.camera.updateProjectionMatrix();
  50. }
  51. // 设置模型位置
  52. setModalPosition() {
  53. this.group?.scale.set(22, 22, 22);
  54. this.group?.position.set(-20, 20, 9);
  55. }
  56. /* 风门动画 */
  57. render() {
  58. if (!this.model) {
  59. return;
  60. }
  61. if (this.mixers && this.fmClock.running) {
  62. this.mixers.update(1);
  63. }
  64. }
  65. /* 点击风门 */
  66. mousedownModel(intersects: THREE.Intersection[]) {
  67. console.log('摄像头控制信息', intersects);
  68. }
  69. mouseUpModel() {}
  70. /* 提取风门序列帧,初始化前后门动画 */
  71. initAnimation() {
  72. const group = this.group.children[0];
  73. /** 卷帘门的元素名称,pCude34-pCude73 */
  74. const eleNames = new Array(40).fill(0).map((_, i) => `pCube${i + 34}`);
  75. if (group) {
  76. const tracksA: THREE.KeyframeTrack[] = [];
  77. const tracksB: THREE.KeyframeTrack[] = [];
  78. group.animations[0].tracks.forEach((track) => {
  79. if (eleNames.some((e) => track.name.includes(e))) {
  80. tracksA.push(track);
  81. } else {
  82. tracksB.push(track);
  83. }
  84. });
  85. this.mixers = new THREE.AnimationMixer(group);
  86. const juanlianmen = new THREE.AnimationClip('juanlianmen', 10, tracksA);
  87. const clipA = this.mixers.clipAction(juanlianmen, group);
  88. clipA.clampWhenFinished = true;
  89. clipA.loop = THREE.LoopOnce;
  90. this.clipActionArr.juanlianmen = clipA;
  91. const gaiban = new THREE.AnimationClip('gaiban', 10, tracksB);
  92. const clipB = this.mixers.clipAction(gaiban, group);
  93. clipB.clampWhenFinished = true;
  94. clipB.loop = THREE.LoopOnce;
  95. this.clipActionArr.gaiban = clipB;
  96. }
  97. }
  98. resetAnimate() {
  99. if (this.clipActionArr.juanlianmen) {
  100. this.clipActionArr.juanlianmen.reset();
  101. this.clipActionArr.juanlianmen.time = 0.1;
  102. this.clipActionArr.juanlianmen.stop();
  103. this.fmClock.stop();
  104. }
  105. if (this.clipActionArr.gaiban) {
  106. this.clipActionArr.gaiban.reset();
  107. this.clipActionArr.gaiban.time = 0.1;
  108. this.clipActionArr.gaiban.stop();
  109. this.fmClock.stop();
  110. }
  111. }
  112. // 播放动画
  113. /**
  114. * 播放门开关动画的处理函数
  115. * @param {number} handlerState - 处理状态,1表示开门,2表示关门
  116. * @param {number} [timeScale=0.01] - 动画时间缩放因子,控制动画播放速度
  117. */
  118. play(handlerState, timeScale = 0.01) {
  119. let handler = () => {};
  120. switch (handlerState) {
  121. case 1: // 打开门
  122. handler = () => {
  123. if (!this.clipActionArr.juanlianmen) return;
  124. this.clipActionArr.juanlianmen.paused = true;
  125. this.clipActionArr.juanlianmen.reset();
  126. this.clipActionArr.juanlianmen.time = 0.1;
  127. this.clipActionArr.juanlianmen.timeScale = timeScale;
  128. // this.clipActionArr.juanlianmen.clampWhenFinished = true;
  129. this.clipActionArr.juanlianmen.play();
  130. this.fmClock.start();
  131. // 显示打开前门文字
  132. if (this.damperOpenMesh) this.damperOpenMesh.visible = true;
  133. };
  134. break;
  135. case 2: // 关闭门
  136. handler = () => {
  137. if (!this.clipActionArr.juanlianmen) return;
  138. this.clipActionArr.juanlianmen.paused = true;
  139. this.clipActionArr.juanlianmen.reset(); //
  140. this.clipActionArr.juanlianmen.time = 9;
  141. this.clipActionArr.juanlianmen.timeScale = -timeScale;
  142. // this.clipActionArr.juanlianmen.clampWhenFinished = true;
  143. this.clipActionArr.juanlianmen.play();
  144. this.fmClock.start();
  145. if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
  146. };
  147. break;
  148. case 3: // 打开盖板
  149. handler = () => {
  150. if (!this.clipActionArr.gaiban) return;
  151. this.clipActionArr.gaiban.paused = true;
  152. this.clipActionArr.gaiban.reset();
  153. this.clipActionArr.gaiban.time = 0.1;
  154. this.clipActionArr.gaiban.timeScale = timeScale;
  155. // this.clipActionArr.gaiban.clampWhenFinished = true;
  156. this.clipActionArr.gaiban.play();
  157. this.fmClock.start();
  158. if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
  159. };
  160. break;
  161. case 4: // 关闭盖板
  162. handler = () => {
  163. if (!this.clipActionArr.gaiban) return;
  164. this.clipActionArr.gaiban.paused = true;
  165. this.clipActionArr.gaiban.reset(); //
  166. this.clipActionArr.gaiban.time = 9;
  167. this.clipActionArr.gaiban.timeScale = -timeScale;
  168. // this.clipActionArr.gaiban.clampWhenFinished = true;
  169. this.clipActionArr.gaiban.play();
  170. this.fmClock.start();
  171. if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
  172. };
  173. break;
  174. default:
  175. }
  176. handler();
  177. }
  178. mountedThree() {
  179. this.group = new THREE.Object3D();
  180. this.group.name = this.modelName;
  181. return new Promise((resolve) => {
  182. if (!this.model) {
  183. resolve(null);
  184. }
  185. this.model.setGLTFModel(['Fire-door-ssl'], this.group).then(() => {
  186. this.setModalPosition();
  187. // 初始化左右摇摆动画;
  188. this.initAnimation();
  189. // this.addLight();
  190. // this.model.animate();
  191. // resolve(this.model);
  192. // this.damperOpenMesh = this.group.getObjectByName('Damper_Open_2');
  193. // if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
  194. // this.damperClosedMesh = this.group.getObjectByName('Damper_Closed_2');
  195. // if (this.damperClosedMesh) this.damperClosedMesh.visible = true;
  196. });
  197. });
  198. }
  199. destroy() {
  200. if (!this.model) return;
  201. if (this.mixers && this.clipActionArr.juanlianmen && this.clipActionArr.gaiban) {
  202. this.mixers.uncacheClip(this.clipActionArr.juanlianmen.getClip());
  203. this.mixers.uncacheAction(this.clipActionArr.juanlianmen.getClip(), this.group);
  204. this.mixers.uncacheClip(this.clipActionArr.gaiban.getClip());
  205. this.mixers.uncacheAction(this.clipActionArr.gaiban.getClip(), this.group);
  206. this.mixers.uncacheRoot(this.group);
  207. if (this.model.animations[0]) this.model.animations[0].tracks = [];
  208. }
  209. this.model.clearGroup(this.group);
  210. this.clipActionArr.juanlianmen = undefined;
  211. this.clipActionArr.gaiban = undefined;
  212. this.mixers = undefined;
  213. // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
  214. }
  215. }
  216. export default FireDoorSsl;