gate.threejs.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. import * as THREE from 'three';
  2. import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
  3. import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
  4. import UseThree from '../../../../hooks/core/threejs/useThree';
  5. import { flyLine } from '/@/utils/threejs/FlyLine';
  6. import { createComposer } from '/@/utils/threejs/bloomPass';
  7. const modelName = 'fm';
  8. // 模型对象、 文字对象
  9. let model, //
  10. track,
  11. group,
  12. fmCSS3D, //文字
  13. isLRAnimation = true, // 是否开启左右摇摆动画
  14. direction = 1, // 摇摆方向
  15. animationtimer: NodeJS.Timeout | null, // 摇摆开启定时器
  16. renderBloomPass,
  17. player1,
  18. player2,
  19. playerStartClickTime1 = new Date().getTime(),
  20. playerStartClickTime2 = new Date().getTime();
  21. const clipActionArr = {
  22. frontDoor: null as unknown as THREE.AnimationAction,
  23. backDoor: null as unknown as THREE.AnimationAction,
  24. arrowTracks: null as unknown as THREE.AnimationAction,
  25. };
  26. // 打灯光
  27. const addLight = (scene) => {
  28. const pointLight2 = new THREE.PointLight(0xffeeee, 0.8, 300);
  29. pointLight2.position.set(-113, 29, 10);
  30. // light2.castShadow = true
  31. pointLight2.shadow.bias = -0.05;
  32. scene.add(pointLight2);
  33. // const pointLightHelper2 = new THREE.PointLightHelper( pointLight2, 1 );
  34. // scene.add( pointLightHelper2 );
  35. const pointLight3 = new THREE.PointLight(0xffffff, 0.8, 100);
  36. pointLight3.position.set(0, 30, 3);
  37. // light2.castShadow = true
  38. pointLight3.shadow.bias = -0.05;
  39. scene.add(pointLight3);
  40. // const pointLightHelper = new THREE.PointLightHelper( pointLight3, 1 );
  41. // scene.add( pointLightHelper );
  42. const pointLight4 = new THREE.PointLight(0xffeeee, 0.6, 100);
  43. pointLight4.position.set(-14, 29, 13);
  44. // light2.castShadow = true
  45. pointLight4.shadow.bias = -0.05;
  46. scene.add(pointLight4);
  47. // const pointLightHelper4 = new THREE.PointLightHelper( pointLight4, 1 );
  48. // scene.add( pointLightHelper4 );
  49. const pointLight5 = new THREE.PointLight(0xffffff, 0.8, 100);
  50. pointLight5.position.set(80, 43, -5.3);
  51. // light2.castShadow = true
  52. pointLight5.shadow.bias = -0.05;
  53. scene.add(pointLight5);
  54. // const pointLightHelper5 = new THREE.PointLightHelper( pointLight5, 1 );
  55. // scene.add( pointLightHelper5 );
  56. const pointLight6 = new THREE.PointLight(0xffffff, 1, 300);
  57. // pointLight6.position.set(-47, 49, 12.9)
  58. pointLight6.position.set(-7, 40, 9);
  59. // light2.castShadow = true
  60. pointLight6.shadow.bias = -0.05;
  61. scene.add(pointLight6);
  62. // const pointLightHelper6 = new THREE.PointLightHelper( pointLight6, 1 );
  63. // scene.add( pointLightHelper6 );
  64. const pointLight7 = new THREE.PointLight(0xffffff, 0.8, 300);
  65. pointLight7.position.set(45, 51, -4.1);
  66. // light2.castShadow = true
  67. pointLight7.shadow.bias = -0.05;
  68. scene.add(pointLight7);
  69. // const pointLightHelper7 = new THREE.PointLightHelper( pointLight7, 1 );
  70. // scene.add( pointLightHelper7 );
  71. const spotLight = new THREE.SpotLight();
  72. spotLight.angle = Math.PI / 16;
  73. spotLight.penumbra = 0;
  74. // spotLight.castShadow = true;
  75. spotLight.position.set(-231, 463, 687);
  76. scene.add(spotLight);
  77. // spotLight.shadow.mapSize.width = 1500; // default
  78. // spotLight.shadow.mapSize.height = 800; // default
  79. spotLight.shadow.camera.near = 0.5; // default
  80. spotLight.shadow.camera.far = 1000; // default
  81. spotLight.shadow.focus = 1.2;
  82. spotLight.shadow.bias = -0.000002;
  83. // gui.add(pointLight6.position, 'x', -200, 200)
  84. // gui.add(pointLight6.position, 'y', -200, 200)
  85. // gui.add(pointLight6.position, 'z', -200, 200)
  86. };
  87. // 重置摄像头
  88. const resetCamera = () => {
  89. // model.camera?.position.set(0, 0.2, 0.3);
  90. model.camera.position.set(30.328, 58.993, 148.315);
  91. model.camera.rotation.set(-27.88, 14.35, 7.47);
  92. model.orbitControls?.update();
  93. model.camera.updateProjectionMatrix();
  94. };
  95. // 设置模型位置
  96. const setModalPosition = () => {
  97. group?.scale.set(22, 22, 22);
  98. group.position.set(-10, 30, 9);
  99. };
  100. // // css3D文字
  101. // const addFm1Text = () => {
  102. // fmCSS3D = new CSS3DObject(elementContent.value);
  103. // fmCSS3D.scale.set(0.13, 0.13, 0.13);
  104. // fmCSS3D.position.set(0, 52, 0);
  105. // fmCSS3D.lookAt(model.camera.position.clone());
  106. // model?.scene.add(fmCSS3D);
  107. // };
  108. /* 添加监控数据 */
  109. export const addFmText = (selectData) => {
  110. if (!group) {
  111. return;
  112. }
  113. const textArr = [
  114. {
  115. text: `煤矿巷道远程风门系统`,
  116. font: 'normal 2.2rem Arial',
  117. color: '#009900',
  118. strokeStyle: '#002200',
  119. x: 80,
  120. y: 95,
  121. },
  122. {
  123. text: `压力(Pa):`,
  124. font: 'normal 30px Arial',
  125. color: '#009900',
  126. strokeStyle: '#002200',
  127. x: 0,
  128. y: 155,
  129. },
  130. {
  131. text: `${selectData.frontRearDP}`,
  132. font: 'normal 30px Arial',
  133. color: '#009900',
  134. strokeStyle: '#002200',
  135. x: 290,
  136. y: 155,
  137. },
  138. {
  139. text: `动力源压力(MPa): `,
  140. font: 'normal 30px Arial',
  141. color: '#009900',
  142. strokeStyle: '#002200',
  143. x: 0,
  144. y: 215,
  145. },
  146. {
  147. text: ` ${selectData.sourcePressure}`,
  148. font: 'normal 30px Arial',
  149. color: '#009900',
  150. strokeStyle: '#002200',
  151. x: 280,
  152. y: 215,
  153. },
  154. {
  155. text: `故障诊断:`,
  156. font: 'normal 30px Arial',
  157. color: '#009900',
  158. strokeStyle: '#002200',
  159. x: 0,
  160. y: 275,
  161. },
  162. {
  163. text: `${selectData.fault}`,
  164. font: 'normal 30px Arial',
  165. color: '#009900',
  166. strokeStyle: '#002200',
  167. x: 280,
  168. y: 275,
  169. },
  170. {
  171. text: `煤炭科学技术研究院有限公司研制`,
  172. font: 'normal 28px Arial',
  173. color: '#009900',
  174. strokeStyle: '#002200',
  175. x: 20,
  176. y: 325,
  177. },
  178. ];
  179. //
  180. getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
  181. const textMap = track(new THREE.CanvasTexture(canvas)); // 关键一步
  182. const textMaterial = track(
  183. new THREE.MeshBasicMaterial({
  184. // 关于材质并未讲解 实操即可熟悉 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
  185. map: textMap, // 设置纹理贴图
  186. transparent: true,
  187. side: THREE.FrontSide, // 这里是双面渲染的意思
  188. })
  189. );
  190. textMaterial.blending = THREE.CustomBlending;
  191. const monitorPlane = group.getObjectByName('monitorText');
  192. if (monitorPlane) {
  193. monitorPlane.material = textMaterial;
  194. } else {
  195. const planeGeometry = track(new THREE.PlaneGeometry(526, 346)); // 平面3维几何体PlaneGeometry
  196. const planeMesh = track(new THREE.Mesh(planeGeometry, textMaterial));
  197. planeMesh.name = 'monitorText';
  198. planeMesh.scale.set(0.002, 0.002, 0.002);
  199. planeMesh.position.set(-1.255, 0.09, -0.41);
  200. group.add(planeMesh);
  201. }
  202. });
  203. };
  204. /* 漫游路线 */
  205. const createLine = () => {
  206. const position = model.camera.position.clone();
  207. //创建样条曲线,作为运动轨迹
  208. const curve = new THREE.CatmullRomCurve3([
  209. new THREE.Vector3(position.x, position.y, position.z),
  210. new THREE.Vector3(26.586, 17.86, 14.144),
  211. new THREE.Vector3(-0.075, 19.669, 15.051),
  212. new THREE.Vector3(-154.882, 17.462, 14.981),
  213. // new THREE.Vector3(76, 28, 27),
  214. ]);
  215. const geometry = new THREE.BufferGeometry().setFromPoints(curve.getPoints(5000));
  216. // 材质对象
  217. const material = new THREE.LineBasicMaterial({
  218. color: 'red',
  219. });
  220. // 线条模型对象
  221. const line = new THREE.Line(geometry, material);
  222. // model?.scene.add(line) // 线条对象添加到场景中
  223. return curve;
  224. };
  225. /* 开启漫游 */
  226. const enterMY = () => {
  227. model.startAnimation = () => {};
  228. model.camera.position.set(114.27, 15.293, 14.189);
  229. model.camera.rotation.set(-86.23, 69.89, 85.98);
  230. const curve = createLine();
  231. let progress = 0;
  232. model.startMY = () => {
  233. if (progress <= 1 - 0.004 * 20) {
  234. const point = curve.getPointAt(progress); //获取样条曲线指定点坐标,作为相机的位置
  235. const pointBox = curve.getPointAt(progress + 0.004 * 20); //获取样条曲线指定点坐标
  236. model.camera.position.set(point.x, point.y, point.z);
  237. model.camera.lookAt(pointBox.x + 5, pointBox.y, pointBox.z);
  238. // model.orbitControls.position0.set(point.x, point.y, point.z) //非必要,场景有控件时才加上
  239. // model.orbitControls.target.set(pointBox.x, pointBox.y , pointBox.z) //非必要,场景有控件时才加上
  240. progress += 0.004;
  241. } else {
  242. // progress = 0
  243. model.camera.position.set(30.328, 58.993, 148.315);
  244. model.camera.rotation.set(-27.88, 14.35, 7.47);
  245. model.camera.lookAt(0, 0, 0);
  246. model.startMY = () => {};
  247. model.startAnimation = fmAnimation.bind(null);
  248. }
  249. };
  250. };
  251. /* 风门动画 */
  252. const render = () => {
  253. if (!model) {
  254. return;
  255. }
  256. if (isLRAnimation && group) {
  257. // 左右摇摆动画
  258. if (Math.abs(group.rotation.y) >= 0.2) {
  259. direction = -direction;
  260. group.rotation.y += 0.00005 * 30 * direction;
  261. } else {
  262. group.rotation.y += 0.00005 * 30 * direction;
  263. }
  264. }
  265. // // //自发光
  266. // const screen = group.getObjectByName('对象156');
  267. // if (screen) {
  268. // model.renderer.clearDepth();
  269. // screen.layers.enable(31);
  270. // !!renderBloomPass && renderBloomPass(group);
  271. // }
  272. // 风门开关动画
  273. const delta = model.clock?.getElapsedTime();
  274. if (model.mixers[0]) model.mixers[0]?.update(delta);
  275. };
  276. // 鼠标点击、松开事件
  277. const mouseEvent = (event) => {
  278. event.stopPropagation();
  279. // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  280. model.mouse.x = ((event.clientX - model.canvasContainer.getBoundingClientRect().left) / model.canvasContainer.clientWidth) * 2 - 1;
  281. model.mouse.y = -((event.clientY - model.canvasContainer.getBoundingClientRect().top) / model.canvasContainer.clientHeight) * 2 + 1;
  282. (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
  283. // 计算物体和射线的焦点
  284. const intersects = model.rayCaster?.intersectObjects(group.children) as THREE.Intersection[];
  285. if (intersects.length > 0) {
  286. isLRAnimation = false;
  287. if (animationtimer) {
  288. clearTimeout(animationtimer);
  289. animationtimer = null;
  290. }
  291. // 判断是否点击到视频
  292. intersects.find((intersect) => {
  293. const mesh = intersect.object;
  294. if (mesh.name === 'player1') {
  295. if (new Date().getTime() - playerStartClickTime1 < 400) {
  296. // model.orbitControls?.dispatchEvent.call(model.orbitControls, { type: 'end' })
  297. // 双击,视频放大
  298. if (player1) {
  299. player1.requestFullscreen();
  300. }
  301. }
  302. playerStartClickTime1 = new Date().getTime();
  303. return true;
  304. } else if (mesh.name === 'player2') {
  305. if (new Date().getTime() - playerStartClickTime2 < 400) {
  306. // model.orbitControls?.dispatchEvent.call(model.orbitControls, { type: 'end' })
  307. // 双击,视频放大
  308. if (player2) {
  309. player2.requestFullscreen();
  310. }
  311. }
  312. playerStartClickTime2 = new Date().getTime();
  313. return true;
  314. }
  315. return false;
  316. });
  317. }
  318. };
  319. // 初始化左右摇摆动画
  320. const startAnimation = () => {
  321. // 开启动画
  322. model.startAnimation = render.bind(null);
  323. // 定义鼠标点击事件x
  324. model.canvasContainer?.addEventListener('pointerdown', mouseEvent.bind(null));
  325. model.canvasContainer?.addEventListener('pointerup', (event) => {
  326. event.stopPropagation();
  327. // 10s后开始摆动
  328. if (!animationtimer && !isLRAnimation) {
  329. animationtimer = setTimeout(() => {
  330. isLRAnimation = true;
  331. }, 10000);
  332. }
  333. });
  334. };
  335. /* 提取风门序列帧,初始化前后门动画 */
  336. const initAnimation = () => {
  337. const tracks = model.animations[0].tracks;
  338. const fontTracks: any[] = [],
  339. backTracks: any[] = [],
  340. arrowTracks: any[] = [];
  341. for (let i = 0; i < tracks.length; i++) {
  342. const track = tracks[i];
  343. if (track.name.startsWith('qianmen')) {
  344. fontTracks.push(track);
  345. } else if (track.name.startsWith('houmen')) {
  346. backTracks.push(track);
  347. } else if (track.name.startsWith('Plane')) {
  348. arrowTracks.push(track);
  349. }
  350. }
  351. const frontDoor = new THREE.AnimationClip('frontDoor', 4, fontTracks);
  352. const backDoor = new THREE.AnimationClip('backDoor', 4, backTracks);
  353. const arr = [frontDoor, backDoor];
  354. arr.forEach((animationClip) => {
  355. const clipAction = model.mixers[0].clipAction(animationClip, group);
  356. clipAction.clampWhenFinished = true;
  357. clipAction.loop = THREE.LoopOnce;
  358. if (animationClip.name == 'frontDoor') clipActionArr.frontDoor = clipAction;
  359. if (animationClip.name == 'backDoor') clipActionArr.backDoor = clipAction;
  360. });
  361. };
  362. // 播放动画
  363. export const play = (handlerState) => {
  364. let handler = () => {};
  365. switch (handlerState) {
  366. case 1: // 打开前门
  367. handler = () => {
  368. clipActionArr.frontDoor.paused = true;
  369. clipActionArr.frontDoor.reset();
  370. clipActionArr.frontDoor.time = 0.5;
  371. clipActionArr.frontDoor.timeScale = 0.01;
  372. clipActionArr.frontDoor.clampWhenFinished = true;
  373. clipActionArr.frontDoor.play();
  374. };
  375. break;
  376. case 2: // 关闭前门
  377. handler = () => {
  378. clipActionArr.frontDoor.paused = true;
  379. clipActionArr.frontDoor.reset(); //
  380. clipActionArr.frontDoor.time = 4;
  381. clipActionArr.frontDoor.timeScale = -0.01;
  382. clipActionArr.frontDoor.clampWhenFinished = true;
  383. clipActionArr.frontDoor.play();
  384. };
  385. break;
  386. case 3: // 打开后门
  387. handler = () => {
  388. clipActionArr.backDoor.paused = true;
  389. clipActionArr.backDoor.reset();
  390. clipActionArr.backDoor.time = 0.5;
  391. clipActionArr.backDoor.timeScale = 0.01;
  392. clipActionArr.backDoor.clampWhenFinished = true;
  393. clipActionArr.backDoor.play();
  394. };
  395. break;
  396. case 4: // 关闭后门
  397. handler = () => {
  398. clipActionArr.backDoor.paused = true;
  399. clipActionArr.backDoor.reset();
  400. clipActionArr.backDoor.time = 4;
  401. clipActionArr.backDoor.timeScale = -0.01;
  402. clipActionArr.backDoor.clampWhenFinished = true;
  403. clipActionArr.backDoor.play();
  404. };
  405. break;
  406. case 5: // 打开前后门
  407. handler = () => {
  408. clipActionArr.backDoor.paused = true;
  409. clipActionArr.frontDoor.paused = true;
  410. clipActionArr.frontDoor.reset();
  411. clipActionArr.frontDoor.time = 0.5;
  412. clipActionArr.frontDoor.timeScale = 0.01;
  413. clipActionArr.frontDoor.clampWhenFinished = true;
  414. clipActionArr.frontDoor.play();
  415. clipActionArr.backDoor.reset();
  416. clipActionArr.backDoor.time = 0.5;
  417. clipActionArr.backDoor.timeScale = 0.01;
  418. clipActionArr.backDoor.clampWhenFinished = true;
  419. clipActionArr.backDoor.play();
  420. };
  421. break;
  422. case 6: // 关闭前后门
  423. handler = () => {
  424. clipActionArr.backDoor.paused = true;
  425. clipActionArr.frontDoor.paused = true;
  426. clipActionArr.frontDoor.reset();
  427. clipActionArr.frontDoor.time = 4;
  428. clipActionArr.frontDoor.timeScale = -0.01;
  429. clipActionArr.frontDoor.clampWhenFinished = true;
  430. clipActionArr.frontDoor.play();
  431. clipActionArr.backDoor.reset();
  432. clipActionArr.backDoor.time = 4;
  433. clipActionArr.backDoor.timeScale = -0.01;
  434. clipActionArr.backDoor.clampWhenFinished = true;
  435. clipActionArr.backDoor.play();
  436. };
  437. break;
  438. default:
  439. }
  440. handler();
  441. model.clock.start();
  442. // const honglvdeng = group.getObjectByName('honglvdeng');
  443. // const material = honglvdeng.material;
  444. // setTimeout(() => {
  445. // if (handlerState === 2 || handlerState === 4 || handlerState === 6) {
  446. // material.color = new THREE.Color(0x00ff00);
  447. // } else {
  448. // material.color = new THREE.Color(0xff0000);
  449. // }
  450. // }, 1000);
  451. };
  452. // 初始化门的开关状态
  453. export const initOpenState = (selectData) => {
  454. if (selectData.frontGateOpen == 1) {
  455. clipActionArr.frontDoor.reset();
  456. clipActionArr.frontDoor.time = 0.5;
  457. clipActionArr.frontDoor.clampWhenFinished = true;
  458. clipActionArr.frontDoor.timeScale = 1;
  459. clipActionArr.frontDoor.play();
  460. } else {
  461. clipActionArr.frontDoor.reset();
  462. clipActionArr.frontDoor.time = 4;
  463. clipActionArr.frontDoor.timeScale = -1;
  464. clipActionArr.frontDoor.clampWhenFinished = true;
  465. clipActionArr.frontDoor.play();
  466. }
  467. if (selectData.rearGateOpen == 1) {
  468. clipActionArr.backDoor.reset();
  469. clipActionArr.backDoor.time = 0.5;
  470. clipActionArr.backDoor.timeScale = 1;
  471. clipActionArr.backDoor.clampWhenFinished = true;
  472. clipActionArr.backDoor.play();
  473. } else {
  474. clipActionArr.backDoor.reset();
  475. clipActionArr.backDoor.time = 4;
  476. clipActionArr.backDoor.timeScale = -1;
  477. clipActionArr.backDoor.clampWhenFinished = true;
  478. clipActionArr.backDoor.play();
  479. }
  480. model.clock.start();
  481. };
  482. export const mountedThree = (playerVal1, playerVal2) => {
  483. return new Promise((resolve) => {
  484. model = new UseThree('#damper3D');
  485. track = model.track;
  486. model.setEnvMap('test1');
  487. model.renderer.toneMappingExposure = 0.8;
  488. model.setModel('fm').then((gltf) => {
  489. group = gltf.scene;
  490. model.scene?.add(group);
  491. if (gltf.animations && gltf.animations.length > 0) {
  492. model.mixers = [];
  493. model.animations = [];
  494. gltf.animations.forEach((animation) => {
  495. const mixer = new THREE.AnimationMixer(group);
  496. model.mixers.push(mixer);
  497. model.animations.push(animation);
  498. });
  499. }
  500. model.animate();
  501. addLight(model.scene);
  502. resetCamera();
  503. setModalPosition();
  504. startAnimation();
  505. // 初始化左右摇摆动画;
  506. // startAnimation();
  507. initAnimation();
  508. // renderBloomPass = createComposer(model).renderBloomPass;
  509. // const flyLineMesh = flyLine(
  510. // [
  511. // new THREE.Vector3(-110, 0, 0),
  512. // // new THREE.Vector3(5, 4, 0),
  513. // new THREE.Vector3(120, 0, 0),
  514. // ],
  515. // '/model/hdr/y1.png'
  516. // );
  517. // group.add(flyLineMesh);
  518. setTimeout(async () => {
  519. player1 = playerVal1;
  520. player2 = playerVal2;
  521. const videoPlayer1 = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
  522. const videoPlayer2 = document.getElementById('fm-player2')?.getElementsByClassName('vjs-tech')[0];
  523. if (videoPlayer1) {
  524. const mesh = renderVideo(group, videoPlayer1, 'player1');
  525. mesh.scale.set(-0.028, 0.0285, 1);
  526. mesh.position.set(4.298, 0.02, -0.4);
  527. mesh.rotation.y = -Math.PI;
  528. }
  529. if (videoPlayer2) {
  530. const mesh = renderVideo(group, videoPlayer2, 'player2');
  531. mesh.scale.set(-0.028, 0.0285, 1);
  532. mesh.position.set(-4.262, 0.02, -0.4);
  533. mesh.rotation.y = -Math.PI;
  534. }
  535. resolve(model);
  536. }, 0);
  537. // resolve(model);
  538. });
  539. });
  540. };
  541. export const destroy = () => {
  542. if (model) {
  543. model.mixers[0].uncacheClip(clipActionArr.frontDoor.getClip());
  544. model.mixers[0].uncacheClip(clipActionArr.backDoor.getClip());
  545. model.mixers[0].uncacheAction(clipActionArr.frontDoor, group);
  546. model.mixers[0].uncacheAction(clipActionArr.backDoor, group);
  547. model.mixers[0].uncacheRoot(group);
  548. clipActionArr.backDoor = undefined;
  549. clipActionArr.frontDoor = undefined;
  550. model.animations[0].tracks = [];
  551. model.mixers = [];
  552. model.deleteModal();
  553. model = null;
  554. group = null;
  555. }
  556. };