gate.threejs.ts 24 KB

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