fanLocal.threejs.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import * as THREE from 'three';
  2. import UseThree from '../../../../utils/threejs/useThree';
  3. import FanLocal from './fanLocal.threejs.base';
  4. import FanLocalDual from './fanLocalDual.threejs.base';
  5. import { animateCamera } from '/@/utils/threejs/util';
  6. import useEvent from '../../../../utils/threejs/useEvent';
  7. import { modal } from 'vxe-table';
  8. /** 模型总控制器 */
  9. let model: UseThree;
  10. /** 当前展示的具体模型的 Object3D 对象 */
  11. let group: THREE.Object3D;
  12. /** 当前展示的具体模型及状态组成的判断唯一性的key */
  13. let cacheKey: string = '';
  14. /** 具体模型内容列表,包含此模型总控制器下的所有可用的具体模型内容 */
  15. const modelContextList: {
  16. /** 当前模型类型,在控制器下有多个具体模型时分辨它们 */
  17. type: string;
  18. /** 模型的具体内容,即负责模型导入、绘制的上下文对象,一个控制器可以新建多个 */
  19. context?: FanLocal | FanLocalDual;
  20. }[] = [];
  21. const { mouseDownFn } = useEvent();
  22. /** 分发鼠标事件到具体实现方法 */
  23. function dispatchMouseEvent(event) {
  24. if (event.button == 0 && model && group) {
  25. mouseDownFn(model, group, event, () => {});
  26. console.log(model.camera, model.orbitControls);
  27. }
  28. }
  29. /** 为模型控制器设置非默认的摄像头位置 */
  30. function setCamera() {
  31. // if (!model || !model.camera) return;
  32. // model.camera.position.set(0, -2000, 1000);
  33. // model.camera.far = 10000;
  34. // model.orbitControls?.update();
  35. // model.camera.updateProjectionMatrix();
  36. }
  37. /** 初始化模型CSS展示框的鼠标事件,应该在模型总控制器初始化后调用 */
  38. function initEventListender() {
  39. if (!model) return;
  40. model.canvasContainer?.addEventListener('mousedown', (e) => dispatchMouseEvent(e));
  41. // model.orbitControls?.addEventListener('change', () => render());
  42. }
  43. /** 渲染并更新总模型 */
  44. // function render() {
  45. // if (model && model.isRender && model.renderer) {
  46. // // model.animationId = requestAnimationFrame(render);
  47. // model.css3dRender?.render(model.scene as THREE.Scene, model.camera as THREE.PerspectiveCamera);
  48. // model.renderer.render(model.scene as THREE.Scene, model.camera as THREE.PerspectiveCamera);
  49. // model.stats?.update();
  50. // }
  51. // }
  52. /** 刷新(再渲染)总模型 */
  53. // export function refreshModal() {
  54. // render();
  55. // // modelContextList.forEach((item) => {
  56. // // if (item.context) {
  57. // // item.context.render();
  58. // // }
  59. // // });
  60. // }
  61. /** 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换 */
  62. export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | string, subModelType: string) {
  63. return new Promise((resolve, reject) => {
  64. if (!model) return reject('模型控制器未初始化');
  65. // 判断是否是同一个/类模型
  66. if (cacheKey === `${modelType}-${subModelType}`) return resolve(null);
  67. cacheKey = `${modelType}-${subModelType}`;
  68. modelContextList.forEach(({ type, context }) => {
  69. if (!context || !context.group) return;
  70. // 先把模型相关的内容隐藏,另起的隐藏子元素的代码是为了隐藏 CSS 元素
  71. context.group.visible = false;
  72. context.group.children.forEach((e) => {
  73. e.visible = false;
  74. });
  75. if (modelType === type) {
  76. group = context?.group as THREE.Object3D;
  77. context.setModelType(subModelType);
  78. setTimeout(async () => {
  79. // 还没添加到控制器的添加进去
  80. if (!model.scene?.getObjectByName(group.name) && group) {
  81. model.scene?.add(group);
  82. }
  83. group.visible = true;
  84. group.children.forEach((e) => {
  85. e.visible = true;
  86. });
  87. // const oldCameraPosition = { x: -693, y: 474, z: 398 };
  88. // const position = { x: 14.826074594663222, y: 16.901762713393836, z: 36.459944037951004 };
  89. // await animateCamera(
  90. // oldCameraPosition,
  91. // { x: 0, y: 0, z: 0 },
  92. // { x: position.x, y: position.y, z: position.z },
  93. // { x: 0, y: 0, z: 0 },
  94. // model,
  95. // 0.8
  96. // );
  97. // 模型不同需要不同的初始角度与位置
  98. const oldCameraPosition = { x: 615, y: 275, z: 744 };
  99. await animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, { x: -1.85, y: 13.58, z: 37.39 }, { x: -1.83, y: 2.58, z: -0.75 }, model, 0.8);
  100. resolve(null);
  101. }, 400);
  102. }
  103. });
  104. });
  105. }
  106. /** 挂载模型控制器,sceneSelctor表示放置模型的元素选择器,cssSelectors表示放置类似详情框的元素选择器,其中第一项需要是根元素选择器 */
  107. export function mountedThree(sceneSelctor: string, cssSelectors: string[]) {
  108. return new Promise(async (resolve) => {
  109. const [rootSelector] = cssSelectors;
  110. model = new UseThree(sceneSelctor, rootSelector);
  111. model.setEnvMap('test1.hdr');
  112. /** @ts-ignore-next-line */
  113. model.renderer.toneMappingExposure = 1.0;
  114. if (model.renderer) {
  115. model.renderer.sortObjects = true;
  116. }
  117. const model1 = new FanLocal(model);
  118. await model1.mountedThree();
  119. modelContextList.push({
  120. type: 'fanLocal',
  121. context: model1,
  122. });
  123. const model2 = new FanLocalDual(model);
  124. await model2.mountedThree();
  125. // 暂时先不加双行
  126. // modelContextList.push({
  127. // type: 'fanLocalDual',
  128. // context: model2,
  129. // });
  130. initEventListender();
  131. setCamera();
  132. model.animate();
  133. resolve(null);
  134. });
  135. }
  136. export const destroy = () => {
  137. if (!model) return;
  138. model.isRender = false;
  139. modelContextList.forEach((item) => {
  140. if (item.context) item.context.destroy();
  141. });
  142. model.destroy();
  143. };
  144. // 为了兼容性而添加的方法导出
  145. export function addText(d) {
  146. if (modelContextList[0]) {
  147. // @ts-ignore
  148. modelContextList[0].context?.addText(d);
  149. }
  150. }
  151. export function addCssText() {
  152. if (modelContextList[0]) {
  153. // @ts-ignore
  154. modelContextList[0].context?.addCssText();
  155. }
  156. }
  157. export function playSmoke(d) {
  158. if (modelContextList[0]) {
  159. // @ts-ignore
  160. modelContextList[0].context?.playSmoke(d);
  161. }
  162. }