fanLocalDual.threejs.base.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. import * as THREE from 'three';
  2. // import { setModalCenter } from '/@/utils/threejs/util';
  3. import Smoke from '../../comment/threejs/Smoke';
  4. import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer';
  5. import { get } from 'lodash-es';
  6. import { getTextCanvas } from '/@/utils/threejs/util';
  7. // import * as dat from 'dat.gui';
  8. // const gui = new dat.GUI();
  9. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  10. class ModelContext {
  11. model;
  12. // modelName = 'jbfj-hd';
  13. modelName = 'jbfj-dual';
  14. /** 本模型的根3D对象 */
  15. group?: THREE.Object3D;
  16. /** 本模型所包含的所有元素合集 */
  17. private elements: unknown[] = [];
  18. /** 本模型支持的 Object3DGroup 模块 */
  19. private modules: {
  20. /** 模块名称 */
  21. name: string;
  22. /** 控制该模块所用的上下文 */
  23. context: THREE.Object3D;
  24. /** 控制时行为声明 */
  25. behavior: (context: THREE.Object3D) => void;
  26. }[] = [];
  27. constructor(model) {
  28. this.model = model;
  29. }
  30. addLight() {
  31. // optional implementation
  32. }
  33. /**
  34. * 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换
  35. *
  36. * 本模型分为外侧(右侧)风机、内侧(左侧)风机,用户选择一个风机后,详情参数的框需要高亮,风机之间需要联动形成风流
  37. *
  38. * @param data 风机数据,第一项应为外侧(右侧)风机,第二项为内侧(左侧)
  39. */
  40. setModelType(modelType: 'inner' | 'outer' | string, data: any[]) {
  41. const fanOuter1Run = get<string>(data[0], 'Fan1StartStatus', '0') == '1';
  42. const fanInner1Run = get<string>(data[1], 'Fan1StartStatus', '0') == '1';
  43. if (modelType === 'inner') {
  44. this.execute('fanLeftStrong');
  45. }
  46. if (modelType === 'outer') {
  47. this.execute('fanRightStrong');
  48. }
  49. if (fanOuter1Run && fanInner1Run) {
  50. this.execute('fan1RightOpen&fan1LeftOpen');
  51. }
  52. if (fanOuter1Run && !fanInner1Run) {
  53. this.execute('fan1RightOpen&fan2LeftOpen');
  54. }
  55. if (!fanOuter1Run && fanInner1Run) {
  56. this.execute('fan2RightOpen&fan1LeftOpen');
  57. }
  58. if (!fanOuter1Run && !fanInner1Run) {
  59. this.execute('fan2RightOpen&fan2LeftOpen');
  60. }
  61. }
  62. private execute(cmdname: string) {
  63. this.modules.forEach(({ name, context, behavior }) => {
  64. if (name === cmdname) {
  65. behavior(context);
  66. }
  67. });
  68. }
  69. mountedThree() {
  70. return new Promise((resolve) => {
  71. this.model.setGLTFModel([this.modelName]).then(async (gltf) => {
  72. this.group = gltf[0];
  73. if (this.group) {
  74. // 将管道由黑色不透光的材质修改为半透明材质
  75. const material = new THREE.MeshBasicMaterial({
  76. color: '#000',
  77. transparent: true,
  78. opacity: 0.3,
  79. side: THREE.DoubleSide, // 这里是双面渲染的意思
  80. });
  81. [
  82. this.group.getObjectByName('Cylinder1054'),
  83. this.group.getObjectByName('BuErTaiJuBuFengJi_shupailie_baisezitiCylinder1054'),
  84. this.group.getObjectByName('pCylinder1'),
  85. ].forEach((e: THREE.Mesh) => {
  86. e.material = material;
  87. // e.renderOrder = 300;
  88. });
  89. // this.group.scale.set(2, 2, 2);
  90. // setModalCenter(this.group);
  91. this.addLight();
  92. this.setModelPosition();
  93. this.initModules().then(resolve);
  94. }
  95. });
  96. });
  97. }
  98. destroy() {
  99. if (!this.model) return;
  100. this.elements.forEach((element) => {
  101. this.model.clearGroup(element);
  102. });
  103. }
  104. // 设置模型位置
  105. setModelPosition() {
  106. if (!this.group) return;
  107. this.group.scale.set(0.6, 0.6, 0.6);
  108. // const ff = gui.addFolder(`位置调整`);
  109. // ff.add(this.group.position, 'x', -100, 100);
  110. // ff.add(this.group.position, 'y', -100, 100);
  111. // ff.add(this.group.position, 'z', -100, 100);
  112. this.group.position.set(0, 0, -60);
  113. this.group.rotation.y = Math.PI / 2;
  114. }
  115. // hideElements(eles: THREE.Object3D[]) {
  116. // eles.forEach((g) => {
  117. // g.visible = false;
  118. // });
  119. // }
  120. // showElements(eles: THREE.Object3D[]) {
  121. // eles.forEach((g) => {
  122. // g.visible = true;
  123. // });
  124. // }
  125. weakElements(eles: unknown[]) {
  126. eles.forEach((g) => {
  127. if (g instanceof Smoke) {
  128. g.oldOpacityFactor = 0.4;
  129. }
  130. if (g instanceof CSS3DObject) {
  131. g.element.style.setProperty('opacity', '0.3');
  132. }
  133. });
  134. }
  135. strongElements(eles: unknown[]) {
  136. eles.forEach((g) => {
  137. if (g instanceof Smoke) {
  138. g.oldOpacityFactor = 0.75;
  139. }
  140. if (g instanceof CSS3DObject) {
  141. g.element.style.setProperty('opacity', '1');
  142. }
  143. });
  144. }
  145. startAnimation(eles: unknown[]) {
  146. eles.forEach((g) => {
  147. if (g instanceof Smoke) {
  148. g.startSmoke();
  149. }
  150. });
  151. }
  152. stopAnimation(eles: unknown[]) {
  153. const smokes = eles.filter((g) => {
  154. return g instanceof Smoke;
  155. });
  156. return Promise.all(smokes.map((e) => e.stopSmoke()));
  157. }
  158. /** 核心方法,初始化本模型的各个模块,这些模块可以实现特定场景的展示、控制等功能 */
  159. async initModules() {
  160. if (this.elements.length > 0) return;
  161. // 右侧风机-主风机进风
  162. const curveFan1Right = this.generateSmokePath(
  163. [
  164. new THREE.Vector3(-85.69, 2.18, 51.89),
  165. new THREE.Vector3(-85.69, 2.18, 41.89),
  166. new THREE.Vector3(-85.69, 2.18, 35.32),
  167. new THREE.Vector3(-85.69, 0.78, 33.08),
  168. new THREE.Vector3(-85.69, 0.78, 27.84),
  169. new THREE.Vector3(-85.69, 4.72, 21.56),
  170. new THREE.Vector3(-85.69, 4.72, -13),
  171. new THREE.Vector3(-26.2, 4.72, -13.24),
  172. new THREE.Vector3(-25.61, 4.72, -47.03),
  173. new THREE.Vector3(80.03, 4.72, -47.03),
  174. ],
  175. true
  176. );
  177. // 右侧风机-备风机进风
  178. const curveFan2Right = this.generateSmokePath(
  179. [
  180. new THREE.Vector3(-85.69, -0.53, 51.89),
  181. new THREE.Vector3(-85.69, -0.53, 41.89),
  182. new THREE.Vector3(-85.69, -0.51, 35.32),
  183. new THREE.Vector3(-85.69, 0.78, 33.08),
  184. new THREE.Vector3(-85.69, 0.78, 27.84),
  185. new THREE.Vector3(-85.69, 4.72, 21.56),
  186. new THREE.Vector3(-85.69, 4.72, -13),
  187. new THREE.Vector3(-26.2, 4.72, -13.24),
  188. new THREE.Vector3(-25.61, 4.72, -47.03),
  189. new THREE.Vector3(80.03, 4.72, -47.03),
  190. ],
  191. true
  192. );
  193. // 左侧风机-主风机进风
  194. const curveFan1Left = this.generateSmokePath(
  195. [
  196. new THREE.Vector3(-85.69, 2.18, 12.72),
  197. new THREE.Vector3(-85.69, 2.18, 2.72),
  198. new THREE.Vector3(-85.69, 2.18, -3.85),
  199. new THREE.Vector3(-85.69, 0.78, -6.09),
  200. new THREE.Vector3(-85.69, 0.78, -12.92),
  201. new THREE.Vector3(80.25, 0.78, -12.92),
  202. ],
  203. true
  204. );
  205. // 左侧风机-备风机进风
  206. const curveFan2Left = this.generateSmokePath(
  207. [
  208. new THREE.Vector3(-85.69, -0.53, 12.72),
  209. new THREE.Vector3(-85.69, -0.53, 2.72),
  210. new THREE.Vector3(-85.69, -0.51, -3.85),
  211. new THREE.Vector3(-85.69, 0.78, -6.09),
  212. new THREE.Vector3(-85.69, 0.78, -12.92),
  213. new THREE.Vector3(80.25, 0.78, -12.92),
  214. ],
  215. true
  216. );
  217. // 右侧巷道-回风前段
  218. const curveTunnelRight = this.generateSmokePath([
  219. new THREE.Vector3(86.67, 0.78, -16.57),
  220. new THREE.Vector3(30.11, 0.78, -16.57),
  221. new THREE.Vector3(30.11, 0.78, -50.39),
  222. ]);
  223. // 左侧巷道-回风前段
  224. const curveTunnelLeft = this.generateSmokePath([new THREE.Vector3(30.11, 0.78, -50.39), new THREE.Vector3(-72.58, 0.78, -50.17)]);
  225. // 左侧巷道-回风全长
  226. const curveTunnelMajor = this.generateSmokePath([new THREE.Vector3(86.55, 0.78, -50.39), new THREE.Vector3(-72.58, 0.78, -50.17)]);
  227. const group1 = new THREE.Group();
  228. const smokeFan1Right = new Smoke('/model/img/texture-smoke.png', '#ffffff', 1, 0.75, 0.5, 600);
  229. smokeFan1Right.setPath(curveFan1Right);
  230. this.elements.push(smokeFan1Right);
  231. const smokeFan2Right = new Smoke('/model/img/texture-smoke.png', '#ffffff', 10, 0.75, 0.5, 400);
  232. smokeFan2Right.setPath(curveFan2Right);
  233. this.elements.push(smokeFan2Right);
  234. const smokeFan1Left = new Smoke('/model/img/texture-smoke.png', '#ffffff', 10, 0.75, 0.5, 600);
  235. smokeFan1Left.setPath(curveFan1Left);
  236. this.elements.push(smokeFan1Left);
  237. const smokeFan2Left = new Smoke('/model/img/texture-smoke.png', '#ffffff', 10, 0.75, 0.5, 400);
  238. smokeFan2Left.setPath(curveFan2Left);
  239. this.elements.push(smokeFan2Left);
  240. const smokeTunnelRight = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.35, 1.5, 150);
  241. smokeTunnelRight.setPath(curveTunnelRight);
  242. this.elements.push(smokeTunnelRight);
  243. const smokeTunnelLeft = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.35, 1.5, 150);
  244. smokeTunnelLeft.setPath(curveTunnelLeft);
  245. this.elements.push(smokeTunnelLeft);
  246. const smokeTunnelMajor = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.35, 1.5, 150);
  247. smokeTunnelMajor.setPath(curveTunnelMajor);
  248. this.elements.push(smokeTunnelMajor);
  249. await smokeFan1Right.setPoints();
  250. this.group?.add(smokeFan1Right.points);
  251. await smokeFan2Right.setPoints();
  252. this.group?.add(smokeFan2Right.points);
  253. await smokeFan1Left.setPoints();
  254. this.group?.add(smokeFan1Left.points);
  255. await smokeFan2Left.setPoints();
  256. this.group?.add(smokeFan2Left.points);
  257. await smokeTunnelRight.setPoints();
  258. this.group?.add(smokeTunnelRight.points);
  259. await smokeTunnelLeft.setPoints();
  260. this.group?.add(smokeTunnelLeft.points);
  261. await smokeTunnelMajor.setPoints();
  262. this.group?.add(smokeTunnelMajor.points);
  263. const fanLeftSelectors = [
  264. {
  265. query: '#inputBox2',
  266. position: [-85, 8, -16],
  267. scale: 0.1,
  268. },
  269. {
  270. query: '#T1_1',
  271. position: [93, 18, -65],
  272. scale: 0.2,
  273. },
  274. {
  275. query: '#T1_2',
  276. position: [35, 16, -59],
  277. scale: 0.175,
  278. },
  279. ];
  280. const fanRightSelectors = [
  281. {
  282. query: '#inputBox3',
  283. position: [-85, 8, 24],
  284. scale: 0.1,
  285. },
  286. {
  287. query: '#T2_1',
  288. position: [93, 18, -98],
  289. scale: 0.2,
  290. },
  291. {
  292. query: '#T2_2',
  293. position: [35, 16, -92],
  294. scale: 0.175,
  295. },
  296. ];
  297. const commonSelectors = [
  298. {
  299. query: '#T3',
  300. position: [-26, 14, -86],
  301. scale: 0.15,
  302. },
  303. ];
  304. const fanLeftSprites = this.initCssElement(fanLeftSelectors);
  305. const fanRightSprites = this.initCssElement(fanRightSelectors);
  306. const commonSprites = this.initCssElement(commonSelectors);
  307. // 双巷道的通风机都开启有4种情况
  308. this.modules.push({
  309. name: 'fan1RightOpen&fan1LeftOpen',
  310. context: group1,
  311. behavior: () => {
  312. // this.weakElements(this.elements);
  313. this.stopAnimation(this.elements).then(() => {
  314. // this.strongElements();
  315. this.startAnimation([smokeFan1Right, smokeFan1Left, smokeTunnelRight, smokeTunnelMajor]);
  316. });
  317. },
  318. });
  319. this.modules.push({
  320. name: 'fan2RightOpen&fan1LeftOpen',
  321. context: group1,
  322. behavior: () => {
  323. this.stopAnimation(this.elements).then(() => {
  324. this.startAnimation([smokeFan2Right, smokeFan1Left, smokeTunnelRight, smokeTunnelMajor]);
  325. });
  326. },
  327. });
  328. this.modules.push({
  329. name: 'fan1RightOpen&fan2LeftOpen',
  330. context: group1,
  331. behavior: () => {
  332. this.stopAnimation(this.elements).then(() => {
  333. this.startAnimation([smokeFan1Right, smokeFan2Left, smokeTunnelRight, smokeTunnelMajor]);
  334. });
  335. },
  336. });
  337. this.modules.push({
  338. name: 'fan2RightOpen&fan2LeftOpen',
  339. context: group1,
  340. behavior: () => {
  341. this.stopAnimation(this.elements).then(() => {
  342. this.startAnimation([smokeFan2Right, smokeFan2Left, smokeTunnelRight, smokeTunnelMajor]);
  343. });
  344. },
  345. });
  346. // 只有一个风机启动有4种情况
  347. this.modules.push({
  348. name: 'fan1RightOpen',
  349. context: group1,
  350. behavior: () => {
  351. this.stopAnimation(this.elements).then(() => {
  352. this.startAnimation([smokeFan1Right, smokeTunnelMajor]);
  353. });
  354. },
  355. });
  356. this.modules.push({
  357. name: 'fan2RightOpen',
  358. context: group1,
  359. behavior: () => {
  360. this.stopAnimation(this.elements).then(() => {
  361. this.startAnimation([smokeFan2Right, smokeTunnelMajor]);
  362. });
  363. },
  364. });
  365. this.modules.push({
  366. name: 'fan1LeftOpen',
  367. context: group1,
  368. behavior: () => {
  369. this.stopAnimation(this.elements).then(() => {
  370. this.startAnimation([smokeFan1Left, smokeTunnelRight, smokeTunnelLeft]);
  371. });
  372. },
  373. });
  374. this.modules.push({
  375. name: 'fan2LeftOpen',
  376. context: group1,
  377. behavior: () => {
  378. this.stopAnimation(this.elements).then(() => {
  379. this.startAnimation([smokeFan2Left, smokeTunnelRight, smokeTunnelLeft]);
  380. });
  381. },
  382. });
  383. // 只有一个风机启动有2种告示牌情况
  384. this.modules.push({
  385. name: 'fanLeftStrong',
  386. context: group1,
  387. behavior: () => {
  388. this.weakElements(this.elements);
  389. this.strongElements([...fanLeftSprites, ...commonSprites]);
  390. },
  391. });
  392. this.modules.push({
  393. name: 'fanRightStrong',
  394. context: group1,
  395. behavior: () => {
  396. this.weakElements(this.elements);
  397. this.strongElements([...fanRightSprites, ...commonSprites]);
  398. },
  399. });
  400. }
  401. /** 初始化css元素,将css元素选择器传入,该方法会将这些元素按顺序放入传入的锚点中 */
  402. initCssElement(selectors: { query: string; position: number[]; scale: number }[]) {
  403. const arr: CSS3DObject[] = [];
  404. selectors.forEach(({ query, position, scale }) => {
  405. const element = document.querySelector(query) as HTMLElement;
  406. if (element) {
  407. const css3D = new CSS3DObject(element);
  408. this.elements.push(css3D);
  409. arr.push(css3D);
  410. css3D.name = query;
  411. css3D.scale.set(scale, scale, scale);
  412. css3D.rotation.y = -Math.PI / 2;
  413. css3D.position.set(position[0], position[1], position[2]);
  414. this.group?.add(css3D);
  415. }
  416. });
  417. return arr;
  418. }
  419. /** 生成适用于 Smoke 的曲线数据,输入途径点,输出路径,如果是进风类型,首个线段将有扩散效果,出风则是末尾线段有扩散效果 */
  420. generateSmokePath(points: THREE.Vector3[], airIn?: boolean, airOut?: boolean) {
  421. if (!this.group) return;
  422. const result: any[] = [];
  423. for (let index = 1; index < points.length; index++) {
  424. const path0 = points[index - 1];
  425. const path1 = points[index];
  426. const path = {
  427. path0,
  428. path1,
  429. isSpread: false,
  430. spreadDirection: 0,
  431. // spreadRang: -10,
  432. };
  433. if (airIn && index === 1) {
  434. // 首个线段需要扩散,由大变小
  435. path.isSpread = true;
  436. path.spreadDirection = -1;
  437. }
  438. if (airOut && index === points.length - 1) {
  439. // 末个线段需要扩散,由小变大
  440. path.isSpread = false;
  441. path.spreadDirection = 1;
  442. }
  443. if (!airIn && !airOut) {
  444. path.isSpread = false;
  445. path.spreadDirection = 2;
  446. }
  447. result.push(path);
  448. }
  449. return result;
  450. }
  451. /** 添加风机描述,右侧风机是arr的第一项,左侧风机是第二项 */
  452. addText(arr) {
  453. const positions = [
  454. [-84.79, 0.82, 20.3],
  455. [-84.79, 0.82, 7.6],
  456. ];
  457. arr.forEach((e, i) => {
  458. this.addTextByData(e, positions[i], `text${i}`);
  459. });
  460. }
  461. // 从 .fanLocal.threejs.base 复制
  462. addTextByData(selectData, position, name) {
  463. if (!this.group) {
  464. return;
  465. }
  466. // @ts-ignore
  467. const screenDownText = get(VENT_PARAM, 'modalText', History_Type['type'] == 'remote' ? '国能神东煤炭集团监制' : '煤炭科学技术研究院有限公司研制');
  468. const screenDownTextX = 80 - (screenDownText.length - 10) * 6;
  469. const textArr = [
  470. {
  471. text: `智能局部通风机监测与控制系统`,
  472. font: 'normal 30px Arial',
  473. color: '#009900',
  474. strokeStyle: '#002200',
  475. x: 20,
  476. y: 108,
  477. },
  478. {
  479. text: `供风距离(m):`,
  480. font: 'normal 30px Arial',
  481. color: '#009900',
  482. strokeStyle: '#002200',
  483. x: 0,
  484. y: 152,
  485. },
  486. {
  487. text: `${
  488. selectData.airSupplyDistence_merge
  489. ? selectData.airSupplyDistence_merge
  490. : selectData.fchimenylength
  491. ? selectData.fchimenylength
  492. : selectData.airSupplyDistence_merge
  493. ? selectData.airSupplyDistence_merge
  494. : '-'
  495. }`,
  496. font: 'normal 30px Arial',
  497. color: '#009900',
  498. strokeStyle: '#002200',
  499. x: 228,
  500. y: 152,
  501. },
  502. {
  503. text: `风筒直径(mm): `,
  504. font: 'normal 30px Arial',
  505. color: '#009900',
  506. strokeStyle: '#002200',
  507. x: 0,
  508. y: 200,
  509. },
  510. {
  511. text: ` ${selectData.fchimenydiamlimit ? selectData.fchimenydiamlimit : selectData.ductDiameter_merge ? selectData.ductDiameter_merge : '-'}`,
  512. font: 'normal 30px Arial',
  513. color: '#009900',
  514. strokeStyle: '#002200',
  515. x: 220,
  516. y: 200,
  517. },
  518. {
  519. text: `故障诊断:`,
  520. font: 'normal 30px Arial',
  521. color: '#009900',
  522. strokeStyle: '#002200',
  523. x: 0,
  524. y: 245,
  525. },
  526. {
  527. text: `${selectData.warnLevel_str ? selectData.warnLevel_str : '-'}`,
  528. font: 'normal 30px Arial',
  529. color: '#009900',
  530. strokeStyle: '#002200',
  531. x: 220,
  532. y: 245,
  533. },
  534. {
  535. text: `型号功率:`,
  536. font: 'normal 30px Arial',
  537. color: '#009900',
  538. strokeStyle: '#002200',
  539. x: 0,
  540. y: 285,
  541. },
  542. {
  543. text: `${selectData.model_Power_merge ? selectData.model_Power_merge : '-'}`,
  544. font: 'normal 26px Arial',
  545. color: '#009900',
  546. strokeStyle: '#002200',
  547. x: 220,
  548. y: 285,
  549. },
  550. {
  551. text: screenDownText,
  552. font: 'normal 28px Arial',
  553. color: '#009900',
  554. strokeStyle: '#002200',
  555. x: screenDownTextX,
  556. y: 325,
  557. },
  558. ];
  559. getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
  560. const textMap = new THREE.CanvasTexture(canvas); // 关键一步
  561. const textMaterial = new THREE.MeshBasicMaterial({
  562. // 关于材质并未讲解 实操即可熟悉 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
  563. map: textMap, // 设置纹理贴图
  564. transparent: true,
  565. side: THREE.FrontSide, // 这里是双面渲染的意思
  566. });
  567. textMaterial.blending = THREE.CustomBlending;
  568. const monitorPlane = this.group?.getObjectByName(name);
  569. if (monitorPlane) {
  570. // @ts-ignore-next-line
  571. monitorPlane.material = textMaterial;
  572. } else {
  573. const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
  574. const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
  575. planeMesh.name = name;
  576. planeMesh.scale.set(0.0135, 0.0135, 0.0135);
  577. planeMesh.rotation.y = -Math.PI / 2;
  578. planeMesh.position.set(position[0], position[1], position[2]);
  579. this.group?.add(planeMesh);
  580. }
  581. });
  582. }
  583. }
  584. export default ModelContext;