|
|
@@ -5,24 +5,22 @@ import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
|
|
|
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
|
|
|
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
|
|
|
import { PathPointList, PathGeometry } from 'three.path';
|
|
|
-
|
|
|
+import { modelMouseHandler } from '/@/utils/threejs/useEvent';
|
|
|
+import { panelManager } from './PanelManager';
|
|
|
+import gsap from 'gsap';
|
|
|
+import { e } from 'unocss';
|
|
|
+
|
|
|
+const cgqMarkerList = [];
|
|
|
+const lljMarkerList = [];
|
|
|
+const pipList = [];
|
|
|
+let mouseoverEvent: any;
|
|
|
+let mouseUpEvent: any;
|
|
|
+let clickSelecteObject: any;
|
|
|
export function modalAnimate(modal) {
|
|
|
- modal.renderer.toneMappingExposure = 1.2;
|
|
|
-
|
|
|
- console.log('初始化模型', modal);
|
|
|
- modal.isRender = true;
|
|
|
+ const curveNum = 8;
|
|
|
+ const unitNum = 8;
|
|
|
|
|
|
- // 【关键步骤】设置旋转速度
|
|
|
- // 默认是 1.0,设置为 0.5 会让移动幅度减半(更慢/更精细)
|
|
|
- modal.orbitControls.rotateSpeed = 0.5;
|
|
|
-
|
|
|
- // 可选:如果你也想减慢缩放和平移的速度
|
|
|
- modal.orbitControls.zoomSpeed = 0.5; // 缩放速度
|
|
|
- modal.orbitControls.panSpeed = 0.5; // 平移速度
|
|
|
-
|
|
|
- // 启用阻尼效果(可选,让运动更有惯性,感觉更平滑)
|
|
|
- modal.orbitControls.enableDamping = true;
|
|
|
- modal.orbitControls.dampingFactor = 0.9;
|
|
|
+ resetModalParam(modal);
|
|
|
|
|
|
const bounds = {
|
|
|
min: new THREE.Vector3(-25, -2, -35),
|
|
|
@@ -37,12 +35,19 @@ export function modalAnimate(modal) {
|
|
|
touming3.parent.remove(touming3);
|
|
|
|
|
|
const time = Date.now() * 0.001;
|
|
|
- const clock = new THREE.Clock();
|
|
|
|
|
|
- const bloomObj = addZhuqiAnimate(zhuqiModal, modal);
|
|
|
- const arrowObj = addArrow(zhuqiModal);
|
|
|
- const unitObj = addUnit(zhuqiModal);
|
|
|
+ const arrowObj = addArrow(zhuqiModal, curveNum);
|
|
|
+ const unitObj = addUnit(zhuqiModal, unitNum);
|
|
|
+ const pipObj = addPip(zhuqiModal, curveNum);
|
|
|
+ console.log('模型对象', zhuqiModal);
|
|
|
+
|
|
|
+ initCss2DContainer(modal);
|
|
|
+ // 添加鼠标拾取
|
|
|
+ initMouseEvent(modal, zhuqiModal);
|
|
|
+
|
|
|
+ initPanel(modal, zhuqiModal);
|
|
|
|
|
|
+ const clock = new THREE.Clock();
|
|
|
// 帧刷新
|
|
|
modal.startAnimation = () => {
|
|
|
/**气泡运动 - 遍历所有颜色组*/
|
|
|
@@ -83,19 +88,6 @@ export function modalAnimate(modal) {
|
|
|
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
|
});
|
|
|
|
|
|
- /**自发光*/
|
|
|
- if (bloomObj) {
|
|
|
- // const { zhuqiPips, bloomComposer, finalComposer, materials, darkMaterial, shader, bloomLayer } = bloomObj;
|
|
|
- // modal.scene.traverse((item) => {
|
|
|
- // darkenNonBloomed(item, bloomLayer, materials, darkMaterial);
|
|
|
- // });
|
|
|
- // bloomComposer.render();
|
|
|
- // modal.scene.traverse((item) => {
|
|
|
- // restoreMaterial(item, materials);
|
|
|
- // });
|
|
|
- // finalComposer.render();
|
|
|
- }
|
|
|
-
|
|
|
/**箭头流动效果*/
|
|
|
if (arrowObj) {
|
|
|
const { texture } = arrowObj;
|
|
|
@@ -107,9 +99,158 @@ export function modalAnimate(modal) {
|
|
|
const { arrowTexture } = unitObj;
|
|
|
arrowTexture.offset.x -= 0.0576;
|
|
|
}
|
|
|
+
|
|
|
+ if (pipObj) {
|
|
|
+ const { texture } = pipObj;
|
|
|
+ texture.offset.x -= 0.1076;
|
|
|
+ }
|
|
|
+
|
|
|
+ [...cgqMarkerList, ...lljMarkerList].forEach((marker: THREE.Mesh) => {
|
|
|
+ // 更新水波纹动画
|
|
|
+ const delta = clock.getElapsedTime();
|
|
|
+ if (marker.userData.update) {
|
|
|
+ marker.userData.update(delta);
|
|
|
+ }
|
|
|
+ });
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+function initPanel(modal, zhuqiModal) {
|
|
|
+ const changjingpPipe38 = zhuqiModal.getObjectByName('guandao')?.getObjectByName('changjingpPipe38');
|
|
|
+ if (changjingpPipe38) {
|
|
|
+ const option = {
|
|
|
+ instanceId: changjingpPipe38.name,
|
|
|
+ sensorData: {
|
|
|
+ positionName: '总支管#',
|
|
|
+ temperature: 65,
|
|
|
+ smoke: 80,
|
|
|
+ co: 45,
|
|
|
+ },
|
|
|
+ threshold: { temperature: 20 },
|
|
|
+ position: [],
|
|
|
+ scale: 0.006,
|
|
|
+ };
|
|
|
+ createMonitorPanel3D(modal, changjingpPipe38, option);
|
|
|
+ const position = panelManager.getPanel(changjingpPipe38.name)?.vm.cssObject.position.clone();
|
|
|
+ panelManager.getPanel(changjingpPipe38.name)?.vm.cssObject.position.set(position.x, position.y + 1, position.z + 3.5);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function initMouseEvent(modal, zhuqiModal) {
|
|
|
+ const zhuqiModalGroup = zhuqiModal.getObjectByName('zhuqiModalGroup');
|
|
|
+ mouseoverEvent = (event) => {
|
|
|
+ modelMouseHandler(modal, pipList, event, (intersects) => {
|
|
|
+ partEvent(intersects, pipList, modal, event);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ mouseUpEvent = (event) => {
|
|
|
+ modelMouseHandler(modal, pipList, event, (intersects) => {
|
|
|
+ partEvent(intersects, pipList, modal, event);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ modal.canvasContainer?.addEventListener('mousemove', mouseoverEvent);
|
|
|
+ modal.canvasContainer?.addEventListener('mouseup', mouseUpEvent);
|
|
|
+}
|
|
|
+
|
|
|
+function partEvent(intersects, partitionList, modal, event) {
|
|
|
+ partitionList.forEach((partition) => {
|
|
|
+ if (!clickSelecteObject || (clickSelecteObject && partition.name !== clickSelecteObject.name)) {
|
|
|
+ partition.visible = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (intersects && intersects.length > 0) {
|
|
|
+ const partitionObj = intersects.find((item) => {
|
|
|
+ if (item.object.type === 'Line') {
|
|
|
+ const partition = partitionList.find((partition) => partition.name === item.object.name);
|
|
|
+ if (partition) {
|
|
|
+ partition.visible = true;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ // 如果是点击事件
|
|
|
+ if (event.type === 'mouseup' && event.button == 0) {
|
|
|
+ if (clickSelecteObject) {
|
|
|
+ panelManager.destroyPanel(clickSelecteObject.name);
|
|
|
+ clickSelecteObject = null;
|
|
|
+ }
|
|
|
+ if (partitionObj) {
|
|
|
+ clickSelecteObject = partitionObj.object;
|
|
|
+ const index = clickSelecteObject.name.split('pipLine')[1];
|
|
|
+ const name = parseInt(index) + 1 + '#';
|
|
|
+ const option = {
|
|
|
+ instanceId: clickSelecteObject.name,
|
|
|
+ sensorData: {
|
|
|
+ positionName: name,
|
|
|
+ temperature: 65,
|
|
|
+ smoke: 80,
|
|
|
+ co: 45,
|
|
|
+ },
|
|
|
+ threshold: { temperature: 20 },
|
|
|
+ position: [],
|
|
|
+ scale: 0.004,
|
|
|
+ };
|
|
|
+ createMonitorPanel3D(modal, clickSelecteObject, option);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return partitionObj;
|
|
|
+ } else {
|
|
|
+ if (event.type === 'mouseup' && event.button == 0) {
|
|
|
+ if (clickSelecteObject) {
|
|
|
+ panelManager.destroyPanel(clickSelecteObject.name);
|
|
|
+ clickSelecteObject = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function createMonitorPanel3D(modal, partition, options?) {
|
|
|
+ const box = new THREE.Box3();
|
|
|
+ box.setFromObject(partition);
|
|
|
+ const center = box.getCenter(new THREE.Vector3());
|
|
|
+ options.position = [center.x, center.y, center.z];
|
|
|
+
|
|
|
+ panelManager.createPanel(modal.scene, options);
|
|
|
+
|
|
|
+ // // 点击后相机
|
|
|
+ // const target0 = modal.camera.position.clone();
|
|
|
+ // const target1 = modal.orbitControls.target.clone();
|
|
|
+ // gsap.fromTo(
|
|
|
+ // modal.orbitControls.target,
|
|
|
+ // { x: target1.x, y: target1.y, z: target1.z },
|
|
|
+ // {
|
|
|
+ // x: center.x - 4,
|
|
|
+ // y: center.y + 1,
|
|
|
+ // z: center.z,
|
|
|
+ // duration: 0.4,
|
|
|
+ // ease: 'easeInCirc',
|
|
|
+ // onUpdate: function (object) {
|
|
|
+ // if (object) modal.camera?.lookAt(new THREE.Vector3(object.x, object.y, object.z));
|
|
|
+ // },
|
|
|
+ // }
|
|
|
+ // );
|
|
|
+}
|
|
|
+
|
|
|
+function resetModalParam(modal) {
|
|
|
+ modal.renderer.toneMappingExposure = 1.35;
|
|
|
+
|
|
|
+ console.log('初始化模型', modal);
|
|
|
+ modal.isRender = true;
|
|
|
+
|
|
|
+ // 【关键步骤】设置旋转速度
|
|
|
+ // 默认是 1.0,设置为 0.5 会让移动幅度减半(更慢/更精细)
|
|
|
+ modal.orbitControls.rotateSpeed = 0.3;
|
|
|
+ // 可选:如果你也想减慢缩放和平移的速度
|
|
|
+ modal.orbitControls.zoomSpeed = 0.3; // 缩放速度
|
|
|
+ modal.orbitControls.panSpeed = 0.3; // 平移速度
|
|
|
+
|
|
|
+ // 启用阻尼效果(可选,让运动更有惯性,感觉更平滑)
|
|
|
+ modal.orbitControls.enableDamping = true;
|
|
|
+ modal.orbitControls.dampingFactor = 0.9;
|
|
|
+}
|
|
|
+
|
|
|
function initGasAnimate(modal, colorConfigs: any[] = []) {
|
|
|
// 默认配置:如果没有传入颜色配置,使用默认的红蓝两种
|
|
|
if (colorConfigs.length === 0) {
|
|
|
@@ -118,14 +259,14 @@ function initGasAnimate(modal, colorConfigs: any[] = []) {
|
|
|
name: 'gas',
|
|
|
color: 0xffa2a244,
|
|
|
emissive: 0xff4400,
|
|
|
- bubbleCount: 200,
|
|
|
+ bubbleCount: 100,
|
|
|
hslHue: 0.4, // 红色
|
|
|
},
|
|
|
{
|
|
|
name: 'n2',
|
|
|
color: 0x4fedf788,
|
|
|
emissive: 0x0044aa,
|
|
|
- bubbleCount: 500,
|
|
|
+ bubbleCount: 300,
|
|
|
hslHue: 0.5, // 蓝色
|
|
|
},
|
|
|
];
|
|
|
@@ -303,75 +444,6 @@ function addZhuqiAnimate(zhuqiModal, modal) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
-function addArrow1(zhuqiModal) {
|
|
|
- const changjingzhuqiguan = zhuqiModal.getObjectByName('changjing5');
|
|
|
- if (changjingzhuqiguan) {
|
|
|
- const zhuqiPips = changjingzhuqiguan.children.filter((item) => {
|
|
|
- return item.name.includes('changjingcurve10');
|
|
|
- });
|
|
|
-
|
|
|
- const flowUniforms = {
|
|
|
- uTime: { value: 0 },
|
|
|
- uColor: { value: new THREE.Color(0x00aaff) }, // 流体颜色
|
|
|
- uSpeed: { value: 0.5 }, // 流动速度
|
|
|
- uBaseColor: { value: new THREE.Color(0x222222) }, // 管道底色
|
|
|
- };
|
|
|
-
|
|
|
- const flowMaterial = new THREE.ShaderMaterial({
|
|
|
- uniforms: flowUniforms,
|
|
|
- vertexShader: `
|
|
|
- varying vec2 vUv;
|
|
|
- void main() {
|
|
|
- vUv = uv;
|
|
|
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
|
- }
|
|
|
- `,
|
|
|
- fragmentShader: `
|
|
|
- uniform float uTime;
|
|
|
- uniform vec3 uColor;
|
|
|
- uniform float uSpeed;
|
|
|
- uniform vec3 uBaseColor;
|
|
|
- varying vec2 vUv;
|
|
|
-
|
|
|
- void main() {
|
|
|
- // 核心:沿 V 轴 (长度方向) 移动纹理
|
|
|
- // fract 实现无限循环
|
|
|
- float flow = fract(vUv.y + uTime * uSpeed);
|
|
|
-
|
|
|
- // 简单的条纹效果
|
|
|
- float stripe = step(0.8, fract(flow * 5.0));
|
|
|
-
|
|
|
- // 混合颜色:底色 + 流动的高亮色
|
|
|
- vec3 finalColor = mix(uBaseColor, uColor, stripe * 0.8);
|
|
|
-
|
|
|
- // 增加一点菲涅尔效果让它看起来更立体 (可选)
|
|
|
- gl_FragColor = vec4(finalColor, 1.0);
|
|
|
- }
|
|
|
- `,
|
|
|
- side: THREE.DoubleSide,
|
|
|
- });
|
|
|
-
|
|
|
- const material1 = new THREE.MeshStandardMaterial({
|
|
|
- color: '#f00',
|
|
|
- roughness: 1,
|
|
|
- metalness: 1,
|
|
|
- });
|
|
|
- debugger;
|
|
|
- zhuqiPips.forEach((item) => {
|
|
|
- // const oldGeometry = item.geometry.clone();
|
|
|
- // // const geometry = new THREE.TubeGeometry(oldGeometry.parameters.path, oldGeometry.parameters.tubularSegments, 0.05, 8, false);
|
|
|
- // const newMesh = new THREE.Mesh(oldGeometry, flowMaterial.clone());
|
|
|
- // item.parent.add(newMesh);
|
|
|
- // // item.parent.remove(item);
|
|
|
- // item.visible = false;
|
|
|
- // // material.needsUpdate = true;
|
|
|
- // // item.material = material;
|
|
|
- });
|
|
|
- return { zhuqiPips, flowMaterial };
|
|
|
- }
|
|
|
- return null;
|
|
|
-}
|
|
|
-
|
|
|
function addArrow(zhuqiModal, curveNum = 8) {
|
|
|
const changjing5 = zhuqiModal.getObjectByName('changjing5');
|
|
|
if (changjing5) {
|
|
|
@@ -394,7 +466,7 @@ function addArrow(zhuqiModal, curveNum = 8) {
|
|
|
// 绘制钻孔曲线
|
|
|
// 根据份数计算均线位置, max.x - min.x 为总长, 端点坐标
|
|
|
// 纵长
|
|
|
- const num1 = 9; // 钻孔个数+1
|
|
|
+ const num1 = curveNum + 1; // 钻孔个数+1
|
|
|
const gap = (max.x - (min.x + 200)) / num1;
|
|
|
const curvePoints: THREE.Vector3[] = [];
|
|
|
for (let i = 0; i < num1; i++) {
|
|
|
@@ -451,7 +523,7 @@ function addArrow(zhuqiModal, curveNum = 8) {
|
|
|
}
|
|
|
|
|
|
const textureLoader = new THREE.TextureLoader();
|
|
|
- const texture = textureLoader.load(`/public/texture/2-1.png`);
|
|
|
+ const texture = textureLoader.load(`/texture/2-1.png`);
|
|
|
|
|
|
// 设置阵列模式 RepeatWrapping
|
|
|
texture.wrapS = THREE.RepeatWrapping;
|
|
|
@@ -486,6 +558,7 @@ function addArrow(zhuqiModal, curveNum = 8) {
|
|
|
|
|
|
const geometry1 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3(vec3List), 100, 40, 8, false);
|
|
|
const mesh1 = new THREE.Mesh(geometry1, tubeMaterial);
|
|
|
+ mesh.name = 'zk' + i;
|
|
|
pCube53.add(mesh1);
|
|
|
mesh1.renderOrder = 1;
|
|
|
}
|
|
|
@@ -530,7 +603,7 @@ function addUnit(zhuqiModal, unitNum = 8) {
|
|
|
// }
|
|
|
|
|
|
const textureLoader = new THREE.TextureLoader();
|
|
|
- const texture = textureLoader.load(`/public/texture/3-2.png`);
|
|
|
+ const texture = textureLoader.load(`/texture/3-2.png`);
|
|
|
|
|
|
// 设置阵列模式 RepeatWrapping
|
|
|
texture.wrapS = THREE.RepeatWrapping;
|
|
|
@@ -632,6 +705,159 @@ function addUnit(zhuqiModal, unitNum = 8) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+function addPip(zhuqiModal, curveNum = 8) {
|
|
|
+ const zhuqiguandao = zhuqiModal.getObjectByName('zhuqiguandao');
|
|
|
+ const changjingpPipe37 = zhuqiModal.getObjectByName('guandao').getObjectByName('changjingpPipe37');
|
|
|
+ const box = new THREE.Box3();
|
|
|
+ box.setFromObject(changjingpPipe37);
|
|
|
+ const min = box.min;
|
|
|
+ const max = box.max;
|
|
|
+ const endP = new THREE.Vector3(max.x - 30, min.y + (max.y - min.y) / 2, min.z + (max.z - min.z) / 2);
|
|
|
+ const startP = new THREE.Vector3(min.x + 30, min.y + (max.y - min.y) / 2, min.z + (max.z - min.z) / 2);
|
|
|
+
|
|
|
+ const endP0 = new THREE.Vector3(max.x, min.y + (max.y - min.y) / 2, min.z + (max.z - min.z) / 2);
|
|
|
+ const startP0 = new THREE.Vector3(min.x, min.y + (max.y - min.y) / 2, min.z + (max.z - min.z) / 2);
|
|
|
+
|
|
|
+ const len = endP.x - startP.x;
|
|
|
+ const gap = len / curveNum;
|
|
|
+
|
|
|
+ const zhuqiguandaoList: THREE.Object3D[] = [];
|
|
|
+
|
|
|
+ for (let i = 0; i < curveNum; i++) {
|
|
|
+ const position = new THREE.Vector3(0 + gap * i, 0, 0);
|
|
|
+ const zhuqiguandaoClone = zhuqiguandao.clone(); // 创建克隆
|
|
|
+ zhuqiguandaoClone.name = 'zhuqiguandao' + i;
|
|
|
+ zhuqiguandaoClone.position.copy(position);
|
|
|
+
|
|
|
+ // 添加点击标识
|
|
|
+ zhuqiModal.add(zhuqiguandaoClone);
|
|
|
+ // addMarker(zhuqiguandaoClone);
|
|
|
+ zhuqiguandaoList.push(zhuqiguandaoClone);
|
|
|
+ }
|
|
|
+ zhuqiguandao.visible = false;
|
|
|
+
|
|
|
+ const { texture } = pipAnimation(zhuqiguandaoList, startP0, endP0, zhuqiModal);
|
|
|
+
|
|
|
+ return { texture };
|
|
|
+}
|
|
|
+
|
|
|
+function pipAnimation(zhuqiguandaoList, startP, endP, zhuqiModal) {
|
|
|
+ const zhuqiModalGroup = new THREE.Object3D();
|
|
|
+ zhuqiModalGroup.name = 'zhuqiModalGroup';
|
|
|
+
|
|
|
+ const textureLoader = new THREE.TextureLoader();
|
|
|
+ const texture = textureLoader.load(`/texture/2-1.png`);
|
|
|
+
|
|
|
+ // 设置阵列模式 RepeatWrapping
|
|
|
+ texture.wrapS = THREE.RepeatWrapping;
|
|
|
+ texture.wrapT = THREE.RepeatWrapping;
|
|
|
+ // 设置x方向的重复数(沿着管道路径方向)
|
|
|
+ // 设置y方向的重复数(环绕管道方向)
|
|
|
+ texture.repeat.x = 20;
|
|
|
+ texture.repeat.y = 6;
|
|
|
+ // 设置管道纹理偏移数,便于对中
|
|
|
+ texture.offset.y = 100;
|
|
|
+ const tubeMaterial = new THREE.MeshPhongMaterial({
|
|
|
+ map: texture,
|
|
|
+ color: '#fff',
|
|
|
+ transparent: true,
|
|
|
+ opacity: 1.0,
|
|
|
+ });
|
|
|
+ const material = new THREE.MeshStandardMaterial({
|
|
|
+ color: '#4F4F4F',
|
|
|
+ roughness: 0.31,
|
|
|
+ metalness: 0.74,
|
|
|
+ });
|
|
|
+
|
|
|
+ const zhuqi_dian = zhuqiModal.getObjectByName('zhuqi_dian');
|
|
|
+ const dian4 = zhuqi_dian.getObjectByName('dian4');
|
|
|
+ const dian3 = zhuqi_dian.getObjectByName('dian3');
|
|
|
+
|
|
|
+ const center = new THREE.Vector3();
|
|
|
+ const box4 = new THREE.Box3();
|
|
|
+ box4.setFromObject(dian4);
|
|
|
+ box4.getCenter(center);
|
|
|
+
|
|
|
+ const pipSP = new THREE.Vector3();
|
|
|
+ const box3 = new THREE.Box3();
|
|
|
+ box3.setFromObject(dian3);
|
|
|
+ box3.getCenter(pipSP);
|
|
|
+
|
|
|
+ // 构建三段管道
|
|
|
+ const pipGeometry1 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([pipSP, center], false, 'centripetal'), 30, 8, 10, false);
|
|
|
+ const pipGeometry2 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([center, startP], false, 'centripetal'), 30, 8, 10, false);
|
|
|
+ const pipGeometry3 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([center, endP], false, 'centripetal'), 30, 8, 10, false);
|
|
|
+
|
|
|
+ const pip1 = new THREE.Mesh(pipGeometry1, tubeMaterial);
|
|
|
+ const pip2 = new THREE.Mesh(pipGeometry2, tubeMaterial);
|
|
|
+ const pip3 = new THREE.Mesh(pipGeometry3, tubeMaterial);
|
|
|
+
|
|
|
+ zhuqiModal.add(pip1, pip2, pip3);
|
|
|
+
|
|
|
+ try {
|
|
|
+ for (let i = 0; i < zhuqiguandaoList.length; i++) {
|
|
|
+ const zhuqiguandao = zhuqiguandaoList[i];
|
|
|
+ const zhuqi_dian_1 = zhuqiguandao.getObjectByName('zhuqi_dian_1');
|
|
|
+
|
|
|
+ const dian1 = zhuqi_dian_1?.getObjectByName('dian2') as THREE.Object3D;
|
|
|
+ const dian2 = zhuqi_dian_1?.getObjectByName('dian1') as THREE.Object3D;
|
|
|
+ const dian3 = zhuqi_dian_1?.getObjectByName('dian') as THREE.Object3D;
|
|
|
+
|
|
|
+ const position1 = new THREE.Vector3();
|
|
|
+ const position2 = new THREE.Vector3();
|
|
|
+ const position3 = new THREE.Vector3();
|
|
|
+
|
|
|
+ const box1 = new THREE.Box3();
|
|
|
+ box1.setFromObject(dian1);
|
|
|
+ box1.getCenter(position1);
|
|
|
+
|
|
|
+ const box2 = new THREE.Box3();
|
|
|
+ box2.setFromObject(dian2);
|
|
|
+ box2.getCenter(position2);
|
|
|
+
|
|
|
+ const box3 = new THREE.Box3();
|
|
|
+ box3.setFromObject(dian3);
|
|
|
+ box3.getCenter(position3);
|
|
|
+
|
|
|
+ const position21 = position2.clone().setY(position2.y - 5);
|
|
|
+ const position22 = position2.clone().setZ(position2.z + 5);
|
|
|
+ const curve = new THREE.QuadraticBezierCurve3(position22, position2, position21);
|
|
|
+ const points = curve.getPoints(30);
|
|
|
+
|
|
|
+ const geometry = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([position1, ...points, position3], false, 'chordal'), 20, 6, 10, false);
|
|
|
+ const mesh = new THREE.Mesh(geometry, tubeMaterial);
|
|
|
+ mesh.position.copy(zhuqiguandao.position);
|
|
|
+ mesh.name = 'pip' + i;
|
|
|
+ zhuqiModal.add(mesh);
|
|
|
+
|
|
|
+ // 绘制点击区域
|
|
|
+ // 鼠标经过时显示线框
|
|
|
+ const material = new THREE.MeshBasicMaterial({
|
|
|
+ color: '#f00',
|
|
|
+ transparent: true,
|
|
|
+ opacity: 1,
|
|
|
+ });
|
|
|
+ const geometry1 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([position1, ...points, position3], false, 'chordal'), 20, 6, 10, false);
|
|
|
+ // const mesh1 = new THREE.Mesh(geometry1, material);
|
|
|
+ const mesh1 = new THREE.Line(geometry1, material);
|
|
|
+ mesh1.position.copy(zhuqiguandao.position);
|
|
|
+ mesh1.name = 'pipLine' + i;
|
|
|
+ // mesh1.visible = false;
|
|
|
+ zhuqiModal.add(mesh1);
|
|
|
+ pipList.push(mesh1);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ debugger;
|
|
|
+ }
|
|
|
+ // zhuqiModal.add(zhuqiModalGroup);
|
|
|
+
|
|
|
+ return { texture };
|
|
|
+}
|
|
|
+
|
|
|
+function initCss2DContainer(modal) {
|
|
|
+ modal.initCSS3Renderer('#css3dContainer');
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* 计算满足不等式 gap*2 > (len - gap*2)/num 的最小临界值
|
|
|
* @param {number} len - 总长度
|
|
|
@@ -649,3 +875,105 @@ function getMinGapThreshold(len, num) {
|
|
|
// 公式推导结果: gap > len / (2 * (num + 1))
|
|
|
return len / (2 * (num + 1));
|
|
|
}
|
|
|
+
|
|
|
+function createRippleMarker() {
|
|
|
+ // 主容器(方便整体控制)
|
|
|
+ const marker = new THREE.Group();
|
|
|
+
|
|
|
+ // --------------------------
|
|
|
+ // 配置参数(可自由修改)
|
|
|
+ // --------------------------
|
|
|
+ const config = {
|
|
|
+ radius: 10, // 标注大小
|
|
|
+ baseColor: 0x00aaff, // 底色
|
|
|
+ rippleColor: 0xffffff, // 波纹颜色
|
|
|
+ rippleCount: 3, // 波纹层数
|
|
|
+ animateSpeed: 1.5, // 动画速度
|
|
|
+ opacity: 0.8, // 整体透明度
|
|
|
+ };
|
|
|
+
|
|
|
+ // --------------------------
|
|
|
+ // 1)底层静态圆形
|
|
|
+ // --------------------------
|
|
|
+ const baseGeometry = new THREE.CircleGeometry(config.radius, 32);
|
|
|
+ const baseMaterial = new THREE.MeshBasicMaterial({
|
|
|
+ color: config.baseColor,
|
|
|
+ transparent: true,
|
|
|
+ opacity: config.opacity * 0.3,
|
|
|
+ });
|
|
|
+ const baseCircle = new THREE.Mesh(baseGeometry, baseMaterial);
|
|
|
+ marker.add(baseCircle);
|
|
|
+
|
|
|
+ // --------------------------
|
|
|
+ // 2)动态波纹(多层)
|
|
|
+ // --------------------------
|
|
|
+ const ripples = [];
|
|
|
+ for (let i = 0; i < config.rippleCount; i++) {
|
|
|
+ const geo = new THREE.RingGeometry(
|
|
|
+ 0, // 内半径
|
|
|
+ config.radius, // 外半径
|
|
|
+ config.radius * 2
|
|
|
+ );
|
|
|
+ const mat = new THREE.MeshBasicMaterial({
|
|
|
+ color: config.rippleColor,
|
|
|
+ transparent: true,
|
|
|
+ opacity: 0,
|
|
|
+ side: THREE.DoubleSide,
|
|
|
+ depthWrite: false, // 防止透明遮挡
|
|
|
+ });
|
|
|
+ const ripple = new THREE.Mesh(geo, mat);
|
|
|
+ ripple.userData.delay = i * 0.4; // 错开动画
|
|
|
+ ripple.userData.speed = config.animateSpeed;
|
|
|
+ ripples.push(ripple);
|
|
|
+ marker.add(ripple);
|
|
|
+ }
|
|
|
+
|
|
|
+ // --------------------------
|
|
|
+ // 3)动画更新函数
|
|
|
+ // --------------------------
|
|
|
+ marker.userData.update = (delta) => {
|
|
|
+ ripples.forEach((rip: THREE.Mesh) => {
|
|
|
+ let t = (delta * rip.userData.speed - rip.userData.delay) % 3;
|
|
|
+ if (t < 0) t += 3;
|
|
|
+
|
|
|
+ // 波纹从中心向外扩散
|
|
|
+ const progress = Math.min(t / 2, 1);
|
|
|
+ const radius = progress * config.radius;
|
|
|
+
|
|
|
+ // 更新环形大小
|
|
|
+ rip.geometry.dispose();
|
|
|
+ rip.geometry = new THREE.RingGeometry(radius * 0.8, radius, 32);
|
|
|
+
|
|
|
+ // 透明度:出现 → 最亮 → 消失
|
|
|
+ rip.material.opacity = progress < 0.5 ? progress * 2 : (1 - progress) * 0.8;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // marker.userData.lookAtCamera = true;
|
|
|
+ return marker;
|
|
|
+}
|
|
|
+
|
|
|
+function addMarker(zhuqiguandao: THREE.Object3D) {
|
|
|
+ const posObj1 = zhuqiguandao?.getObjectByName('网格004_6');
|
|
|
+ const box1 = new THREE.Box3();
|
|
|
+ box1.setFromObject(posObj1);
|
|
|
+ const center1 = box1.getCenter(new THREE.Vector3());
|
|
|
+ const marker_cgq = createRippleMarker();
|
|
|
+ const position = new THREE.Vector3(center1.x, center1.y, center1.z);
|
|
|
+ marker_cgq.position.copy(position.setZ(position.z - 10));
|
|
|
+ marker_cgq.name = 'cgq';
|
|
|
+ marker_cgq.rotateY(Math.PI / 2);
|
|
|
+ zhuqiguandao.add(marker_cgq);
|
|
|
+ cgqMarkerList.push(marker_cgq);
|
|
|
+
|
|
|
+ const posObj2 = zhuqiguandao?.getObjectByName('网格004_2');
|
|
|
+ const box2 = new THREE.Box3();
|
|
|
+ box2.setFromObject(posObj2);
|
|
|
+ const center2 = box2.getCenter(new THREE.Vector3());
|
|
|
+ const marker_llj = createRippleMarker();
|
|
|
+ const pos = new THREE.Vector3(center2.x, center2.y, center2.z);
|
|
|
+ marker_llj.position.copy(pos);
|
|
|
+ marker_llj.name = 'llj';
|
|
|
+ zhuqiguandao.add(marker_llj);
|
|
|
+ lljMarkerList.push(marker_llj);
|
|
|
+}
|