import * as THREE from 'three'; import UseThree from '../../../../utils/threejs/useThree'; import { animateCamera } from '/@/utils/threejs/util'; import useEvent from '../../../../utils/threejs/useEvent'; import { getDictItemsByCode } from '/@/utils/dict'; /** 模型总控制器 */ let model: UseThree; /** 当前展示的具体模型的 Object3D 对象 */ let group: THREE.Object3D; /** 当前展示的具体模型及状态组成的判断唯一性的key */ let cacheKey: string = ''; /** 具体模型内容列表,包含此模型总控制器下的所有可用的具体模型内容 */ const modelContextList: { /** 当前模型类型,在控制器下有多个具体模型时分辨它们 */ type: string; /** 模型的具体内容,即负责模型导入、绘制的上下文对象,一个控制器可以新建多个 */ context?: FanLocal | FanLocalDual | FanLocalTwo; }[] = []; const { mouseDownFn } = useEvent(); /** 分发鼠标事件到具体实现方法 */ function dispatchMouseEvent(event) { if (event.button == 0 && model && group) { mouseDownFn(model, group, event, () => {}); console.log(model.camera, model.orbitControls); } } /** 为模型控制器设置非默认的摄像头位置 */ function setCamera() { // if (!model || !model.camera) return; // model.camera.position.set(0, -2000, 1000); // model.camera.far = 10000; // model.orbitControls?.update(); // model.camera.updateProjectionMatrix(); } /** 初始化模型CSS展示框的鼠标事件,应该在模型总控制器初始化后调用 */ function initEventListender() { if (!model) return; model.canvasContainer?.addEventListener('mousedown', (e) => dispatchMouseEvent(e)); // model.orbitControls?.addEventListener('change', () => render()); } /** 渲染并更新总模型 */ // function render() { // if (model && model.isRender && model.renderer) { // // model.animationId = requestAnimationFrame(render); // model.css3dRender?.render(model.scene as THREE.Scene, model.camera as THREE.PerspectiveCamera); // model.renderer.render(model.scene as THREE.Scene, model.camera as THREE.PerspectiveCamera); // model.stats?.update(); // } // } /** 刷新(再渲染)总模型 */ // export function refreshModal() { // render(); // // modelContextList.forEach((item) => { // // if (item.context) { // // item.context.render(); // // } // // }); // } /** 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换 */ export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | 'fanLocalSingle' | string, subModelType: string, data?: any) { return new Promise((resolve, reject) => { if (!model) return reject('模型控制器未初始化'); // 判断是否是同一个/类模型 if (cacheKey === `${modelType}-${subModelType}`) return resolve(null); // const isUpdate = cacheKey.startsWith(modelType); cacheKey = `${modelType}-${subModelType}`; modelContextList.forEach(({ type, context }) => { if (!context || !context.group) return; // 先把模型相关的内容隐藏,另起的隐藏子元素的代码是为了隐藏 CSS 元素 context.group.visible = false; context.group.children.forEach((e) => { e.visible = false; }); // model.scene?.remove(context.group); if (modelType === type) { group = context?.group as THREE.Object3D; if (context.setModelType) context.setModelType(subModelType, data); // 还没添加到控制器的添加进去 if (!model.scene?.getObjectByName(group.name) && group) { model.scene?.add(group); } group.visible = true; group.children.forEach((e) => { e.visible = true; }); // 模型发生了替换,需要使用摄像头动画// 模型不同需要不同的初始角度与位置 if (type == 'fanLocal') { const oldCameraPosition = { x: 615, y: 275, z: 744 }; 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); } if (type == 'fanLocalTwo') { const oldCameraPosition = { x: 615, y: 275, z: 744 }; 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); } if (type == 'fanLocalDual') { const oldCameraPosition = { x: -693, y: 474, z: 398 }; animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, { x: 14.83, y: 16.9, z: 36.46 }, { x: 0, y: 0, z: 0 }, model, 0.8); } resolve(null); } }); }); } /** 挂载模型控制器,sceneSelctor表示放置模型的元素选择器,cssSelectors表示放置类似详情框的元素选择器,其中第一项需要是根元素选择器 */ export function mountedThree(sceneSelctor: string, cssSelectors: string[]) { return new Promise(async (resolve) => { const [rootSelector] = cssSelectors; model = new UseThree(sceneSelctor, rootSelector); model.setEnvMap('test1.hdr'); /** @ts-ignore-next-line */ model.renderer.toneMappingExposure = 1.0; if (model.renderer) { model.renderer.sortObjects = true; } // 这里根据字典判断 const dictCodes = getDictItemsByCode('fanlocal_install_kind'); if (dictCodes && dictCodes.length > 0) { for (let i = 0; i < dictCodes.length; i++) { const dict = dictCodes[i]; switch (dict.value) { case 'single': const FanLocal = await import('./fanLocal.threejs.base'); const model1 = new FanLocal.default(model); await model1.mountedThree(); modelContextList.push({ type: 'fanLocal', context: model1, }); break; case 'dual_inner': case 'dual_outer': if (modelContextList.find((item) => item.type == 'fanLocalDual')) continue; const FanLocalDual = await import('./fanLocalDual.threejs.base'); const model2 = new FanLocalDual.default(model); await model2.mountedThree(); // 暂时先不加双行 modelContextList.push({ type: 'fanLocalDual', context: model2, }); break; case 'fanLocalTwo': const FanLocalTwo = await import('./fanLocal.threejs.Two'); const model3 = new FanLocalTwo.default(model); const flag = await model3.mountedThree(); if (flag) modelContextList.push({ type: 'fanLocalTwo', context: model3, }); break; case 'fanlocal_1': const FanLocalSingle = await import('./fanLocal.threejs.single'); const model4 = new FanLocalSingle.default(model); await model4.mountedThree(); modelContextList.push({ type: 'fanLocalSingle', context: model4, }); break; } } } initEventListender(); setCamera(); model.animate(); resolve(null); }); } export const destroy = () => { if (!model) return; model.isRender = false; modelContextList.forEach((item) => { if (item.context) item.context.destroy(); }); model.destroy(); }; // 为了兼容性而添加的方法导出 export function addText(d, e) { if (modelContextList[0]) modelContextList[0].context?.addText(d); if (modelContextList[1]) modelContextList[1].context?.addText(e); if (modelContextList[2]) modelContextList[2].context?.addText(d); } export function addCssText() { if (modelContextList[0] && modelContextList[0].context && modelContextList[0].context['addCssText']) modelContextList[0].context['addCssText'](); if (modelContextList[2] && modelContextList[2].context && modelContextList[2].context['addCssText']) modelContextList[2].context['addCssText'](); } export function playSmoke(d) { for (let i = 0; i < modelContextList.length; i++) { const item = modelContextList[i]; if (item.context && item.context.playSmoke) item.context.playSmoke(d); } }