gate.threejs.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  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. debugger;
  239. group.add(hotPoint);
  240. }
  241. };
  242. /* 漫游路线 */
  243. const createLine = () => {
  244. const position = model.camera.position.clone();
  245. //创建样条曲线,作为运动轨迹
  246. const curve = new THREE.CatmullRomCurve3([
  247. new THREE.Vector3(position.x, position.y, position.z),
  248. new THREE.Vector3(26.586, 17.86, 14.144),
  249. new THREE.Vector3(-0.075, 19.669, 15.051),
  250. new THREE.Vector3(-154.882, 17.462, 14.981),
  251. // new THREE.Vector3(76, 28, 27),
  252. ]);
  253. const geometry = new THREE.BufferGeometry().setFromPoints(curve.getPoints(5000));
  254. // 材质对象
  255. const material = new THREE.LineBasicMaterial({
  256. color: 'red',
  257. });
  258. // 线条模型对象
  259. const line = new THREE.Line(geometry, material);
  260. // model?.scene.add(line) // 线条对象添加到场景中
  261. return curve;
  262. };
  263. /* 开启漫游 */
  264. const enterMY = () => {
  265. model.startAnimation = () => {};
  266. model.camera.position.set(114.27, 15.293, 14.189);
  267. model.camera.rotation.set(-86.23, 69.89, 85.98);
  268. const curve = createLine();
  269. let progress = 0;
  270. model.startMY = () => {
  271. if (progress <= 1 - 0.004 * 20) {
  272. const point = curve.getPointAt(progress); //获取样条曲线指定点坐标,作为相机的位置
  273. const pointBox = curve.getPointAt(progress + 0.004 * 20); //获取样条曲线指定点坐标
  274. model.camera.position.set(point.x, point.y, point.z);
  275. model.camera.lookAt(pointBox.x + 5, pointBox.y, pointBox.z);
  276. // model.orbitControls.position0.set(point.x, point.y, point.z) //非必要,场景有控件时才加上
  277. // model.orbitControls.target.set(pointBox.x, pointBox.y , pointBox.z) //非必要,场景有控件时才加上
  278. progress += 0.004;
  279. } else {
  280. // progress = 0
  281. model.camera.position.set(30.328, 58.993, 148.315);
  282. model.camera.rotation.set(-27.88, 14.35, 7.47);
  283. model.camera.lookAt(0, 0, 0);
  284. model.startMY = () => {};
  285. model.startAnimation = fmAnimation.bind(null);
  286. }
  287. };
  288. };
  289. /* 风门动画 */
  290. const render = () => {
  291. if (!model) {
  292. return;
  293. }
  294. if (isLRAnimation && group) {
  295. // 左右摇摆动画
  296. if (Math.abs(group.rotation.y) >= 0.2) {
  297. direction = -direction;
  298. group.rotation.y += 0.00002 * 30 * direction;
  299. } else {
  300. group.rotation.y += 0.00002 * 30 * direction;
  301. }
  302. }
  303. // // //自发光
  304. // const screen = group.getObjectByName('对象156');
  305. // if (screen) {
  306. // model.renderer.clearDepth();
  307. // screen.layers.enable(31);
  308. // !!renderBloomPass && renderBloomPass(group);
  309. // }
  310. // 风门开关动画
  311. const delta = model.clock?.getElapsedTime();
  312. if (model.mixers[0]) model.mixers[0]?.update(delta);
  313. };
  314. // 鼠标点击、松开事件
  315. const mouseEvent = (event) => {
  316. const widthScale = appStore.getWidthScale;
  317. const heightScale = appStore.getHeightScale;
  318. // debugger;
  319. event.stopPropagation();
  320. // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  321. model.mouse.x =
  322. ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
  323. model.mouse.y =
  324. -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
  325. (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
  326. // 计算物体和射线的焦点
  327. const intersects = model.rayCaster?.intersectObjects(group.children) as THREE.Intersection[];
  328. if (intersects.length > 0) {
  329. isLRAnimation = false;
  330. if (animationtimer) {
  331. clearTimeout(animationtimer);
  332. animationtimer = null;
  333. }
  334. if (model.camera.layers.mask == -1) model.camera.layers.toggle(1);
  335. // 判断是否点击到视频
  336. intersects.find((intersect) => {
  337. const mesh = intersect.object;
  338. // deviceDetailCSS3D?.layers.set(1);
  339. if (mesh.name === 'player1') {
  340. if (new Date().getTime() - playerStartClickTime1 < 400) {
  341. // model.orbitControls?.dispatchEvent.call(model.orbitControls, { type: 'end' })
  342. // 双击,视频放大
  343. if (player1) {
  344. player1.requestFullscreen();
  345. }
  346. }
  347. playerStartClickTime1 = new Date().getTime();
  348. return true;
  349. } else if (mesh.name === 'player2') {
  350. if (new Date().getTime() - playerStartClickTime2 < 400) {
  351. // model.orbitControls?.dispatchEvent.call(model.orbitControls, { type: 'end' })
  352. // 双击,视频放大
  353. if (player2) {
  354. player2.requestFullscreen();
  355. }
  356. }
  357. playerStartClickTime2 = new Date().getTime();
  358. return true;
  359. } else if (mesh.name.startsWith('hotPoint')) {
  360. if (deviceDetailCSS3D) {
  361. // document.getElementById('deviceCard') as HTMLElement;
  362. deviceDetailCSS3D.position.set(intersect.point.x, intersect.point.y + 18, intersect.point.z);
  363. console.log('[ deviceDetailCSS3D.position ] >', deviceDetailCSS3D.position);
  364. // deviceDetailCSS3D?.layers.set(0);
  365. model.camera.layers.enableAll();
  366. return true;
  367. }
  368. // let position = new THREE.Vector3(mesh.position.x, mesh.position.y, 0.5);
  369. // position = position.applyMatrix4(group.matrixWorld);
  370. // model.scene.updateMatrixWorld(true);
  371. // // let worldPosition = new THREE.Vector3();
  372. // // let worldScale = new THREE.Vector3();
  373. // // worldPosition = mesh.getWorldPosition(worldPosition);
  374. // // worldScale = mesh.getWorldScale(worldScale);
  375. // const devicePosition = transScreenCoord(intersect.point, model.camera);
  376. // element.style.left = devicePosition.x + 'px';
  377. // element.style.top = devicePosition.y + 'px';
  378. // console.log('[ point 坐标位置 ] >', devicePosition, mesh.position);
  379. } else {
  380. // deviceDetailCSS3D?.layers.set(1);
  381. console.log('[ 点击事件 ] >');
  382. }
  383. return false;
  384. });
  385. }
  386. };
  387. // 初始化左右摇摆动画
  388. const startAnimation = () => {
  389. // 开启动画
  390. model.startAnimation = render.bind(null);
  391. // 定义鼠标点击事件x
  392. model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
  393. model.canvasContainer?.addEventListener('pointerup', (event) => {
  394. event.stopPropagation();
  395. // 10s后开始摆动
  396. if (!animationtimer && !isLRAnimation) {
  397. animationtimer = setTimeout(() => {
  398. isLRAnimation = true;
  399. }, 10000);
  400. }
  401. });
  402. };
  403. /* 提取风门序列帧,初始化前后门动画 */
  404. const initAnimation = () => {
  405. const tracks = model.animations[0].tracks;
  406. const fontTracks: any[] = [],
  407. backTracks: any[] = [];
  408. for (let i = 0; i < tracks.length; i++) {
  409. const track = tracks[i];
  410. if (track.name.startsWith('qianmen')) {
  411. fontTracks.push(track);
  412. } else if (track.name.startsWith('houmen')) {
  413. backTracks.push(track);
  414. }
  415. }
  416. const frontDoor = new THREE.AnimationClip('frontDoor', 4, fontTracks);
  417. const backDoor = new THREE.AnimationClip('backDoor', 4, backTracks);
  418. const arr = [frontDoor, backDoor];
  419. arr.forEach((animationClip) => {
  420. const clipAction = model.mixers[0].clipAction(animationClip, group);
  421. clipAction.clampWhenFinished = true;
  422. clipAction.loop = THREE.LoopOnce;
  423. if (animationClip.name == 'frontDoor') clipActionArr.frontDoor = clipAction;
  424. if (animationClip.name == 'backDoor') clipActionArr.backDoor = clipAction;
  425. });
  426. };
  427. export const deviceDetailCard = (position = { x: 0, y: 0, z: 0 }) => {
  428. const element = document.getElementById('deviceCard') as HTMLElement;
  429. deviceDetailCSS3D = new CSS2DObject(element);
  430. deviceDetailCSS3D.name = 'deviceCard';
  431. // deviceDetailCSS3D.scale.set(0.1, 0.1, 0.1);
  432. // deviceDetailCSS3D.scale.set(0.004, 0.004, 0.004);
  433. // deviceDetailCSS3D.rotation.y = -Math.PI / 2;
  434. deviceDetailCSS3D.position.set(position.x, position.y, position.z);
  435. deviceDetailCSS3D?.layers.set(1);
  436. // group.add(deviceDetailCSS3D);
  437. model.scene.add(deviceDetailCSS3D);
  438. };
  439. // 播放动画
  440. export const play = (handlerState) => {
  441. let handler = () => {};
  442. switch (handlerState) {
  443. case 1: // 打开前门
  444. handler = () => {
  445. clipActionArr.frontDoor.paused = true;
  446. clipActionArr.frontDoor.reset();
  447. clipActionArr.frontDoor.time = 0.5;
  448. clipActionArr.frontDoor.timeScale = 0.01;
  449. clipActionArr.frontDoor.clampWhenFinished = true;
  450. clipActionArr.frontDoor.play();
  451. };
  452. break;
  453. case 2: // 关闭前门
  454. handler = () => {
  455. clipActionArr.frontDoor.paused = true;
  456. clipActionArr.frontDoor.reset(); //
  457. clipActionArr.frontDoor.time = 4;
  458. clipActionArr.frontDoor.timeScale = -0.01;
  459. clipActionArr.frontDoor.clampWhenFinished = true;
  460. clipActionArr.frontDoor.play();
  461. };
  462. break;
  463. case 3: // 打开后门
  464. handler = () => {
  465. clipActionArr.backDoor.paused = true;
  466. clipActionArr.backDoor.reset();
  467. clipActionArr.backDoor.time = 0.5;
  468. clipActionArr.backDoor.timeScale = 0.01;
  469. clipActionArr.backDoor.clampWhenFinished = true;
  470. clipActionArr.backDoor.play();
  471. };
  472. break;
  473. case 4: // 关闭后门
  474. handler = () => {
  475. clipActionArr.backDoor.paused = true;
  476. clipActionArr.backDoor.reset();
  477. clipActionArr.backDoor.time = 4;
  478. clipActionArr.backDoor.timeScale = -0.01;
  479. clipActionArr.backDoor.clampWhenFinished = true;
  480. clipActionArr.backDoor.play();
  481. };
  482. break;
  483. case 5: // 打开前后门
  484. handler = () => {
  485. clipActionArr.backDoor.paused = true;
  486. clipActionArr.frontDoor.paused = true;
  487. clipActionArr.frontDoor.reset();
  488. clipActionArr.frontDoor.time = 0.5;
  489. clipActionArr.frontDoor.timeScale = 0.01;
  490. clipActionArr.frontDoor.clampWhenFinished = true;
  491. clipActionArr.frontDoor.play();
  492. clipActionArr.backDoor.reset();
  493. clipActionArr.backDoor.time = 0.5;
  494. clipActionArr.backDoor.timeScale = 0.01;
  495. clipActionArr.backDoor.clampWhenFinished = true;
  496. clipActionArr.backDoor.play();
  497. };
  498. break;
  499. case 6: // 关闭前后门
  500. handler = () => {
  501. clipActionArr.backDoor.paused = true;
  502. clipActionArr.frontDoor.paused = true;
  503. clipActionArr.frontDoor.reset();
  504. clipActionArr.frontDoor.time = 4;
  505. clipActionArr.frontDoor.timeScale = -0.01;
  506. clipActionArr.frontDoor.clampWhenFinished = true;
  507. clipActionArr.frontDoor.play();
  508. clipActionArr.backDoor.reset();
  509. clipActionArr.backDoor.time = 4;
  510. clipActionArr.backDoor.timeScale = -0.01;
  511. clipActionArr.backDoor.clampWhenFinished = true;
  512. clipActionArr.backDoor.play();
  513. };
  514. break;
  515. default:
  516. }
  517. handler();
  518. model.clock.start();
  519. // const honglvdeng = group.getObjectByName('honglvdeng');
  520. // const material = honglvdeng.material;
  521. // setTimeout(() => {
  522. // if (handlerState === 2 || handlerState === 4 || handlerState === 6) {
  523. // material.color = new THREE.Color(0x00ff00);
  524. // } else {
  525. // material.color = new THREE.Color(0xff0000);
  526. // }
  527. // }, 1000);
  528. };
  529. // 初始化门的开关状态
  530. export const initOpenState = (selectData) => {
  531. if (!group) return;
  532. model.camera.position.set(-1000, 100, 500);
  533. group.rotation.y = 0;
  534. return new Promise(async (resolve) => {
  535. setTimeout(async () => {
  536. const oldCameraPosition = { x: -1000, y: 100, z: 500 };
  537. await animateCamera(oldCameraPosition, oldCameraPosition, { x: 46.257, y: 57.539, z: 94.313 }, { x: -50, y: 0, z: 0 }, model, 0.8);
  538. resolve(null);
  539. if (!selectData) {
  540. return;
  541. }
  542. if (selectData.frontGateOpen == 1) {
  543. clipActionArr.frontDoor.reset();
  544. clipActionArr.frontDoor.time = 0.5;
  545. clipActionArr.frontDoor.clampWhenFinished = true;
  546. clipActionArr.frontDoor.timeScale = 1;
  547. clipActionArr.frontDoor.play();
  548. } else {
  549. clipActionArr.frontDoor.reset();
  550. clipActionArr.frontDoor.time = 4;
  551. clipActionArr.frontDoor.timeScale = -1;
  552. clipActionArr.frontDoor.clampWhenFinished = true;
  553. clipActionArr.frontDoor.play();
  554. }
  555. if (selectData.rearGateOpen == 1) {
  556. clipActionArr.backDoor.reset();
  557. clipActionArr.backDoor.time = 0.5;
  558. clipActionArr.backDoor.timeScale = 1;
  559. clipActionArr.backDoor.clampWhenFinished = true;
  560. clipActionArr.backDoor.play();
  561. } else {
  562. clipActionArr.backDoor.reset();
  563. clipActionArr.backDoor.time = 4;
  564. clipActionArr.backDoor.timeScale = -1;
  565. clipActionArr.backDoor.clampWhenFinished = true;
  566. clipActionArr.backDoor.play();
  567. }
  568. model.clock.start();
  569. }, 800);
  570. });
  571. };
  572. export const mountedThree = (playerVal1, playerVal2) => {
  573. return new Promise((resolve) => {
  574. model = new UseThree('#damper3D', '', '#deviceDetail');
  575. model.setEnvMap('test1');
  576. model.renderer.toneMappingExposure = 0.8;
  577. model.setModel(modelName).then((gltf) => {
  578. group = gltf.scene;
  579. group.layers.enableAll();
  580. if (gltf.animations && gltf.animations.length > 0) {
  581. model.mixers = [];
  582. model.animations = [];
  583. gltf.animations.forEach((animation) => {
  584. const mixer = new THREE.AnimationMixer(group);
  585. model.mixers.push(mixer);
  586. model.animations.push(animation);
  587. });
  588. }
  589. model.scene?.add(group);
  590. // model.camera.position.set(-1000, 100, 500);
  591. addLight(model.scene);
  592. // resetCamera();
  593. setModalPosition();
  594. startAnimation();
  595. // 初始化左右摇摆动画;
  596. // startAnimation();
  597. initAnimation();
  598. model.animate();
  599. drawHots();
  600. deviceDetailCard();
  601. if (model.camera.layers.mask == -1) model.camera.layers.toggle(1);
  602. // renderBloomPass = createComposer(model).renderBloomPass;
  603. // const flyLineMesh = flyLine(
  604. // [
  605. // new THREE.Vector3(-110, 0, 0),
  606. // // new THREE.Vector3(5, 4, 0),
  607. // new THREE.Vector3(120, 0, 0),
  608. // ],
  609. // '/model/hdr/y1.png'
  610. // );
  611. // group.add(flyLineMesh);
  612. setTimeout(async () => {
  613. player1 = playerVal1;
  614. player2 = playerVal2;
  615. const videoPlayer1 = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
  616. const videoPlayer2 = document.getElementById('fm-player2')?.getElementsByClassName('vjs-tech')[0];
  617. if (videoPlayer1) {
  618. const mesh = renderVideo(group, videoPlayer1, 'player1');
  619. mesh.scale.set(-0.028, 0.0285, 1);
  620. mesh.position.set(4.298, 0.02, -0.4);
  621. mesh.rotation.y = -Math.PI;
  622. group.add(mesh);
  623. }
  624. if (videoPlayer2) {
  625. const mesh = renderVideo(group, videoPlayer2, 'player2');
  626. mesh.scale.set(-0.028, 0.0285, 1);
  627. mesh.position.set(-4.262, 0.02, -0.4);
  628. mesh.rotation.y = -Math.PI;
  629. group.add(mesh);
  630. }
  631. resolve(model);
  632. }, 0);
  633. });
  634. });
  635. };
  636. export const destroy = () => {
  637. if (model) {
  638. if (model.mixers[0]) {
  639. model.mixers[0].uncacheClip(clipActionArr.frontDoor.getClip());
  640. model.mixers[0].uncacheClip(clipActionArr.backDoor.getClip());
  641. model.mixers[0].uncacheAction(clipActionArr.frontDoor, group);
  642. model.mixers[0].uncacheAction(clipActionArr.backDoor, group);
  643. model.mixers[0].uncacheRoot(group);
  644. model.animations[0].tracks = [];
  645. }
  646. clipActionArr.backDoor = undefined;
  647. clipActionArr.frontDoor = undefined;
  648. model.mixers = [];
  649. model.deleteModal();
  650. model = null;
  651. group = null;
  652. // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
  653. }
  654. };