fireDoor.threejs.ymh.ts 8.0 KB

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