fanLocalDual.threejs.base.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 { setModalCenter } from '/@/utils/threejs/util';
  6. // import * as dat from 'dat.gui';
  7. // const gui = new dat.GUI();
  8. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  9. class ModelContext {
  10. model;
  11. // modelName = 'jbfj-hd';
  12. modelName = 'jbfj-dual';
  13. /** 本模型的根3D对象 */
  14. group?: THREE.Object3D;
  15. /** 本模型所包含的所有元素合集 */
  16. private elements: unknown[] = [];
  17. /** 本模型支持的 Object3DGroup 模块 */
  18. private modules: {
  19. /** 模块名称 */
  20. name: string;
  21. /** 控制该模块所用的上下文 */
  22. context: THREE.Object3D;
  23. /** 控制时行为声明 */
  24. behavior: (context: THREE.Object3D) => void;
  25. }[] = [];
  26. constructor(model) {
  27. this.model = model;
  28. }
  29. addLight() {
  30. // optional implementation
  31. }
  32. /** 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换 */
  33. setModelType(modelType: string) {
  34. this.modules.forEach(({ name, context, behavior }) => {
  35. if (name === modelType) {
  36. behavior(context);
  37. }
  38. });
  39. }
  40. /** 初始化css元素,将css元素选择器传入,该方法会将这些元素按顺序放入传入的锚点中 */
  41. initCssElement() {
  42. // selectors.forEach((selector, index) => {
  43. // const element = document.querySelector(selector) as HTMLElement;
  44. // if (element) {
  45. // const css3D = new CSS3DSprite(element);
  46. // this.cssSprites.push(css3D);
  47. // css3D.name = selector;
  48. // css3D.scale.set(0.05, 0.05, 0.05);
  49. // // const ff = gui.addFolder(`css元素${index}`);
  50. // // ff.add(css3D.position, 'x', -100, 100);
  51. // // ff.add(css3D.position, 'y', -100, 100);
  52. // // ff.add(css3D.position, 'z', -100, 100);
  53. // if (index < anchors.length) {
  54. // const [x, y, z] = anchors[index];
  55. // css3D.position.set(x, y, z);
  56. // this.group?.add(css3D);
  57. // } else {
  58. // console.warn(`指定的元素${selector}没有合适的位置放置`);
  59. // }
  60. // }
  61. // });
  62. }
  63. mountedThree() {
  64. return new Promise((resolve) => {
  65. this.model.setGLTFModel([this.modelName]).then(async (gltf) => {
  66. this.group = gltf[0];
  67. if (this.group) {
  68. this.addLight();
  69. this.setModalPosition();
  70. this.initModules();
  71. setModalCenter(this.group);
  72. resolve(null);
  73. }
  74. });
  75. });
  76. }
  77. destroy() {
  78. if (!this.model) return;
  79. this.elements.forEach((element) => {
  80. this.model.clearGroup(element);
  81. });
  82. }
  83. // 设置模型位置
  84. setModalPosition() {
  85. if (!this.group) return;
  86. this.group.scale.set(0.7, 0.7, 0.7);
  87. this.group.position.set(0, 6, -50);
  88. this.group.rotation.y = Math.PI / 2;
  89. }
  90. // hideElements(eles: THREE.Object3D[]) {
  91. // eles.forEach((g) => {
  92. // g.visible = false;
  93. // });
  94. // }
  95. // showElements(eles: THREE.Object3D[]) {
  96. // eles.forEach((g) => {
  97. // g.visible = true;
  98. // });
  99. // }
  100. weakElements(eles: unknown[]) {
  101. eles.forEach((g) => {
  102. if (g instanceof Smoke) {
  103. g.opacityFactor = 0.4;
  104. }
  105. if (g instanceof CSS3DObject) {
  106. g.element.style.setProperty('opacity', '0.5');
  107. }
  108. });
  109. }
  110. strongElements(eles: unknown[]) {
  111. eles.forEach((g) => {
  112. if (g instanceof Smoke) {
  113. g.opacityFactor = 0.75;
  114. }
  115. if (g instanceof CSS3DObject) {
  116. g.element.style.setProperty('opacity', '1');
  117. }
  118. });
  119. }
  120. startAnimation(eles: unknown[]) {
  121. eles.forEach((g) => {
  122. if (g instanceof Smoke) {
  123. g.startSmoke();
  124. }
  125. });
  126. }
  127. stopAnimation(eles: unknown[]) {
  128. eles.forEach((g) => {
  129. if (g instanceof Smoke) {
  130. g.stopSmoke();
  131. }
  132. });
  133. }
  134. /** 核心方法,初始化本模型的各个模块,这些模块可以实现特定场景的展示、控制等功能 */
  135. async initModules() {
  136. if (this.elements.length > 0) return;
  137. const curve1 = [
  138. {
  139. path0: new THREE.Vector3(10, 0, -10),
  140. path1: new THREE.Vector3(20, 0, -10),
  141. isSpread: false,
  142. spreadDirection: 0,
  143. },
  144. {
  145. path0: new THREE.Vector3(10, 0, -10),
  146. path1: new THREE.Vector3(10, 0, -20),
  147. isSpread: true,
  148. spreadDirection: 1, // 1是由小变大,-1是由大变小
  149. },
  150. ];
  151. const group1 = new THREE.Group();
  152. const smoke1 = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.75, 0.5, 400);
  153. smoke1.setPath(curve1);
  154. await smoke1.setPoints();
  155. this.elements.push(smoke1);
  156. const element = document.getElementById('inputBox') as HTMLElement;
  157. if (element) {
  158. const fanLocalCSS3D = new CSS3DObject(element);
  159. fanLocalCSS3D.name = 'text1';
  160. fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
  161. fanLocalCSS3D.rotation.y = -Math.PI / 2;
  162. fanLocalCSS3D.position.set(-85.68, 5.97, -3.39);
  163. group1.add(fanLocalCSS3D);
  164. this.elements.push(fanLocalCSS3D);
  165. }
  166. this.modules.push({
  167. name: 'state1',
  168. context: group1,
  169. behavior: () => {
  170. this.weakElements(this.elements);
  171. this.strongElements([smoke1]);
  172. },
  173. });
  174. }
  175. }
  176. export default ModelContext;