|
|
@@ -1,1085 +0,0 @@
|
|
|
-import { Ref, ref, watch } from 'vue';
|
|
|
-import * as THREE from 'three';
|
|
|
-import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
|
|
|
-import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
|
|
|
-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';
|
|
|
-
|
|
|
-// const cgqMarkerList = [];
|
|
|
-// const lljMarkerList = [];
|
|
|
-const zhuqiPipList = []; // 注气支管
|
|
|
-const zhuqiZkList = []; // 注气钻孔
|
|
|
-const gasUnitList = []; //瓦斯抽采单元
|
|
|
-const pipList = [];
|
|
|
-let mouseoverEvent: any;
|
|
|
-let mouseUpEvent: any;
|
|
|
-let clickSelecteObject: any;
|
|
|
-let pipDataList = [];
|
|
|
-export function modalAnimate(modal, data: Ref<any, any>) {
|
|
|
- const zhuqiPipDataRef = ref(null);
|
|
|
- const maxIndex = getPipIndex(data.value) || 0;
|
|
|
- const zhuqiModal = modal.scene.getObjectByName('zhuqi').getObjectByName('ZhuQiChangJing_1');
|
|
|
-
|
|
|
- watch(data, (newValue) => {
|
|
|
- const zhuqiData = newValue.msgTxt.find((item) => item.type.includes('injection'))?.datalist[0];
|
|
|
- if (zhuqiData) {
|
|
|
- const readData = zhuqiData.readData;
|
|
|
- const zzgData = {
|
|
|
- positionName: '总支管#',
|
|
|
- flowStdInstant: readData['flowStdInstant'], // 瞬时流量
|
|
|
- flowStdAccum: readData['flowStdAccum'], // 累计流量
|
|
|
- injectionTemperature: readData['injectionTemperature'], // 温度
|
|
|
- injectionPressure: readData['injectionPressure'], // 压力
|
|
|
- valveOpening: readData['valveOpening'], // 阀门开度
|
|
|
- paiqiStatus: readData['paiqiStatus'], // 阀门状态
|
|
|
- };
|
|
|
- zhuqiPipDataRef.value = zzgData;
|
|
|
-
|
|
|
- for (let i = 1; i <= maxIndex; i++) {
|
|
|
- if (pipDataList[i - 1]) {
|
|
|
- const zzgData = {
|
|
|
- positionName: `${i}#`,
|
|
|
- flowStdInstant: readData['flowStdInstant_' + i], // 瞬时流量
|
|
|
- flowStdAccum: readData['flowStdAccum_' + i], // 累计流量
|
|
|
- injectionTemperature: readData['injectionTemperature_' + i], // 温度
|
|
|
- injectionPressure: readData['injectionPressure_' + i], // 压力
|
|
|
- valveOpening: readData[`valve${i}Opening`], // 阀门开度
|
|
|
- paiqiStatus: readData['paiqiStatus_' + i], // 阀门状态
|
|
|
- };
|
|
|
- pipDataList[i - 1].value = zzgData;
|
|
|
- } else {
|
|
|
- const zzgData = ref({
|
|
|
- positionName: `${i}#`,
|
|
|
- flowStdInstant: readData['flowStdInstant_' + i], // 瞬时流量
|
|
|
- flowStdAccum: readData['flowStdAccum_' + i], // 累计流量
|
|
|
- injectionTemperature: readData['injectionTemperature_' + i], // 温度
|
|
|
- injectionPressure: readData['injectionPressure_' + i], // 压力
|
|
|
- valveOpening: readData[`valve${i}Opening`], // 阀门开度
|
|
|
- paiqiStatus: readData['paiqiStatus_' + i], // 阀门状态
|
|
|
- });
|
|
|
- pipDataList[i - 1] = zzgData;
|
|
|
- }
|
|
|
- // if (i > 4) {
|
|
|
- // zhuqiPipList[i - 1].visible = false;
|
|
|
- // zhuqiZkList[i - 1].visible = false;
|
|
|
- // }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- initAnimate(modal);
|
|
|
-
|
|
|
- const zhuqiData = data.value.msgTxt.find((item) => item.type.includes('injection'))?.datalist[0];
|
|
|
- if (zhuqiData) {
|
|
|
- const readData = zhuqiData.readData;
|
|
|
- const zzgData = {
|
|
|
- positionName: '总支管#',
|
|
|
- flowStdInstant: readData['flowStdInstant'], // 瞬时流量
|
|
|
- flowStdAccum: readData['flowStdAccum'], // 累计流量
|
|
|
- injectionTemperature: readData['injectionTemperature'], // 温度
|
|
|
- injectionPressure: readData['injectionPressure'], // 压力
|
|
|
- valveOpening: readData['valveOpening'], // 阀门开度
|
|
|
- paiqiStatus: readData['paiqiStatus'], // 阀门状态
|
|
|
- };
|
|
|
- zhuqiPipDataRef.value = zzgData;
|
|
|
- initPanel(modal, zhuqiModal, zhuqiPipDataRef);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function initAnimate(modal) {
|
|
|
- const curveNum = 8;
|
|
|
- const unitNum = 8;
|
|
|
-
|
|
|
- resetModalParam(modal);
|
|
|
-
|
|
|
- const bounds = {
|
|
|
- min: new THREE.Vector3(-25, -2, -35),
|
|
|
- max: new THREE.Vector3(10, 10, 30),
|
|
|
- };
|
|
|
-
|
|
|
- // 初始化多种颜色气泡
|
|
|
- const allBubbles = initGasAnimate(modal);
|
|
|
-
|
|
|
- const zhuqiModal = modal.scene.getObjectByName('zhuqi').getObjectByName('ZhuQiChangJing_1');
|
|
|
- const touming3 = zhuqiModal.getObjectByName('touming3');
|
|
|
- touming3.parent.remove(touming3);
|
|
|
-
|
|
|
- const time = Date.now() * 0.001;
|
|
|
-
|
|
|
- // 绘制注气钻孔
|
|
|
- const arrowObj = addArrow(zhuqiModal, curveNum);
|
|
|
-
|
|
|
- // 绘制注气支管
|
|
|
- const pipObj = addPip(zhuqiModal, curveNum);
|
|
|
-
|
|
|
- // 绘制抽采单元
|
|
|
- const unitObj = addUnit(zhuqiModal, unitNum);
|
|
|
-
|
|
|
- initCss2DContainer(modal);
|
|
|
- // 添加鼠标拾取
|
|
|
- initMouseEvent(modal, zhuqiModal);
|
|
|
-
|
|
|
- // const clock = new THREE.Clock();
|
|
|
- // 帧刷新
|
|
|
- modal.startAnimation = () => {
|
|
|
- /**气泡运动 - 遍历所有颜色组*/
|
|
|
- allBubbles.forEach((bubbleGroup) => {
|
|
|
- const { bubblesData, instancedMesh, bubbleCount, dummy } = bubbleGroup;
|
|
|
-
|
|
|
- for (let i = 0; i < bubbleCount; i++) {
|
|
|
- const data = bubblesData[i];
|
|
|
-
|
|
|
- // 1. 更新位置
|
|
|
- data.position.add(data.velocity);
|
|
|
-
|
|
|
- // 2. 添加正弦波动
|
|
|
- data.position.y += Math.sin(time + i) * 0.02;
|
|
|
-
|
|
|
- // 3. 边界检测与反弹
|
|
|
- if (data.position.x < bounds.min.x || data.position.x > bounds.max.x) {
|
|
|
- data.velocity.x *= -1;
|
|
|
- data.position.x = THREE.MathUtils.clamp(data.position.x, bounds.min.x, bounds.max.x);
|
|
|
- }
|
|
|
- if (data.position.y < bounds.min.y || data.position.y > bounds.max.y) {
|
|
|
- data.velocity.y *= -1;
|
|
|
- data.position.y = THREE.MathUtils.clamp(data.position.y, bounds.min.y, bounds.max.y);
|
|
|
- }
|
|
|
- if (data.position.z < bounds.min.z || data.position.z > bounds.max.z) {
|
|
|
- data.velocity.z *= -1;
|
|
|
- data.position.z = THREE.MathUtils.clamp(data.position.z, bounds.min.z, bounds.max.z);
|
|
|
- }
|
|
|
-
|
|
|
- // 4. 更新实例矩阵
|
|
|
- dummy.position.copy(data.position);
|
|
|
- dummy.scale.setScalar(data.scale);
|
|
|
- dummy.rotation.y = time * 0.5;
|
|
|
- dummy.rotation.z = time * 0.2;
|
|
|
- dummy.updateMatrix();
|
|
|
- instancedMesh.setMatrixAt(i, dummy.matrix);
|
|
|
- }
|
|
|
- instancedMesh.instanceMatrix.needsUpdate = true;
|
|
|
- });
|
|
|
-
|
|
|
- /**箭头流动效果*/
|
|
|
- if (arrowObj) {
|
|
|
- const { texture } = arrowObj;
|
|
|
- if (texture) {
|
|
|
- texture.offset.x -= 0.1776;
|
|
|
- }
|
|
|
- }
|
|
|
- if (unitObj) {
|
|
|
- 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 getPipIndex(data: Ref<any, any>) {
|
|
|
- if (data && data['msgTxt']) {
|
|
|
- const zhuqiData = data['msgTxt'].find((item) => item.type.includes('injection'))?.datalist[0];
|
|
|
- if (zhuqiData) {
|
|
|
- const readData = zhuqiData.readData;
|
|
|
- const max = 20;
|
|
|
- let maxIndex = 0;
|
|
|
- for (let i = 1; i < max; i++) {
|
|
|
- if (readData['flowWorkAccum_' + i] !== undefined) {
|
|
|
- continue;
|
|
|
- } else {
|
|
|
- maxIndex = i;
|
|
|
- }
|
|
|
- }
|
|
|
- for (let i = 1; i <= maxIndex; i++) {
|
|
|
- const zzgData = ref({
|
|
|
- positionName: `${i}#`,
|
|
|
- flowStdInstant: readData['flowStdInstant_' + i], // 瞬时流量
|
|
|
- flowStdAccum: readData['flowStdAccum_' + i], // 累计流量
|
|
|
- injectionTemperature: readData['injectionTemperature_' + i], // 温度
|
|
|
- injectionPressure: readData['injectionPressure_' + i], // 压力
|
|
|
- valveOpening: readData[`valve${i}Opening`], // 阀门开度
|
|
|
- paiqiStatus: readData['paiqiStatus_' + i], // 阀门状态
|
|
|
- });
|
|
|
- pipDataList.push(zzgData);
|
|
|
- }
|
|
|
- return maxIndex;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-// 初始化主支管面板
|
|
|
-function initPanel(modal, zhuqiModal, zhuqiPipDataRef) {
|
|
|
- const changjingpPipe38 = zhuqiModal.getObjectByName('guandao')?.getObjectByName('changjingpPipe38');
|
|
|
- if (changjingpPipe38) {
|
|
|
- const option = {
|
|
|
- instanceId: changjingpPipe38.name,
|
|
|
- sensorData: zhuqiPipDataRef,
|
|
|
- threshold: { temperature: 20 },
|
|
|
- position: [],
|
|
|
- scale: 0.005,
|
|
|
- };
|
|
|
- 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 + 0.6, 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 pipDataRef = pipDataList.find((item) => item.value.positionName === name);
|
|
|
- const option = {
|
|
|
- instanceId: clickSelecteObject.name,
|
|
|
- sensorData: pipDataRef,
|
|
|
- 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];
|
|
|
- console.log('创建面板', options.position);
|
|
|
-
|
|
|
- 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) {
|
|
|
- colorConfigs = [
|
|
|
- {
|
|
|
- name: 'gas',
|
|
|
- color: 0xffa2a244,
|
|
|
- emissive: 0xff4400,
|
|
|
- bubbleCount: 100,
|
|
|
- hslHue: 0.4, // 红色
|
|
|
- },
|
|
|
- {
|
|
|
- name: 'n2',
|
|
|
- color: 0x4fedf788,
|
|
|
- emissive: 0x0044aa,
|
|
|
- bubbleCount: 300,
|
|
|
- hslHue: 0.5, // 蓝色
|
|
|
- },
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- // 1. 定义容器边界 (矩形)
|
|
|
- const bounds = {
|
|
|
- min: new THREE.Vector3(-25, -2, -35),
|
|
|
- max: new THREE.Vector3(10, 10, 30),
|
|
|
- };
|
|
|
-
|
|
|
- const allBubbles = [] as {
|
|
|
- bubblesData: { position: THREE.Vector3; velocity: THREE.Vector3; scale: number }[];
|
|
|
- instancedMesh: THREE.InstancedMesh;
|
|
|
- bubbleCount: number;
|
|
|
- dummy: THREE.Object3D;
|
|
|
- }[];
|
|
|
-
|
|
|
- // 2. 为每种颜色配置创建气泡
|
|
|
- colorConfigs.forEach((config) => {
|
|
|
- const { bubbleCount, color, emissive, hslHue } = config;
|
|
|
- const geometry = new THREE.SphereGeometry(1, 16, 16);
|
|
|
-
|
|
|
- // 创建材质
|
|
|
- const material = new THREE.MeshPhysicalMaterial({
|
|
|
- color: color,
|
|
|
- emissive: emissive,
|
|
|
- emissiveIntensity: 0.4,
|
|
|
- transparent: true,
|
|
|
- opacity: 0.1,
|
|
|
- depthWrite: false,
|
|
|
- roughness: 0.0,
|
|
|
- metalness: 0.1,
|
|
|
- clearcoat: 1.0,
|
|
|
- clearcoatRoughness: 0.1,
|
|
|
- transmission: 0.7,
|
|
|
- thickness: 0.5,
|
|
|
- ior: 1.0004,
|
|
|
- // blending: THREE.AdditiveBlending,
|
|
|
- side: THREE.DoubleSide,
|
|
|
- });
|
|
|
-
|
|
|
- // 创建实例化网格
|
|
|
- const instancedMesh = new THREE.InstancedMesh(geometry, material, bubbleCount);
|
|
|
- modal.scene.add(instancedMesh);
|
|
|
-
|
|
|
- // 存储气泡运动数据
|
|
|
- const dummy = new THREE.Object3D();
|
|
|
- const bubblesData = [] as { position: THREE.Vector3; velocity: THREE.Vector3; scale: number }[];
|
|
|
-
|
|
|
- for (let i = 0; i < bubbleCount; i++) {
|
|
|
- const x = THREE.MathUtils.randFloat(bounds.min.x, bounds.max.x);
|
|
|
- const y = THREE.MathUtils.randFloat(bounds.min.y, bounds.max.y);
|
|
|
- const z = THREE.MathUtils.randFloat(bounds.min.z, bounds.max.z);
|
|
|
- const scale = THREE.MathUtils.randFloat(0.2, 0.8);
|
|
|
- const velocity = new THREE.Vector3(
|
|
|
- THREE.MathUtils.randFloat(-0.05, 0.05),
|
|
|
- THREE.MathUtils.randFloat(-0.05, 0.05),
|
|
|
- THREE.MathUtils.randFloat(-0.05, 0.05)
|
|
|
- );
|
|
|
-
|
|
|
- bubblesData.push({ position: new THREE.Vector3(x, y, z), velocity, scale });
|
|
|
-
|
|
|
- dummy.position.copy(bubblesData[i].position);
|
|
|
- dummy.scale.setScalar(bubblesData[i].scale);
|
|
|
- dummy.updateMatrix();
|
|
|
- instancedMesh.setMatrixAt(i, dummy.matrix);
|
|
|
- }
|
|
|
-
|
|
|
- // 设置实例颜色
|
|
|
- const colorObj = new THREE.Color();
|
|
|
- for (let i = 0; i < bubbleCount; i++) {
|
|
|
- colorObj.setHSL(hslHue, 0.5, 0.8 + Math.random() * 0.2);
|
|
|
- instancedMesh.setColorAt(i, colorObj);
|
|
|
- }
|
|
|
- instancedMesh.instanceColor.needsUpdate = true;
|
|
|
-
|
|
|
- allBubbles.push({ bubblesData, instancedMesh, bubbleCount, dummy });
|
|
|
- });
|
|
|
-
|
|
|
- return allBubbles;
|
|
|
-}
|
|
|
-
|
|
|
-function addZhuqiAnimate(zhuqiModal, modal) {
|
|
|
- return null;
|
|
|
- const renderer = modal.renderer;
|
|
|
-
|
|
|
- const renderScene = new RenderPass(modal.scene, modal.camera);
|
|
|
- const BLOOM_SCENE = 1;
|
|
|
-
|
|
|
- const bloomLayer = new THREE.Layers();
|
|
|
- bloomLayer.set(BLOOM_SCENE);
|
|
|
-
|
|
|
- const params = {
|
|
|
- threshold: 0,
|
|
|
- strength: 0,
|
|
|
- radius: 0.001,
|
|
|
- exposure: 0,
|
|
|
- };
|
|
|
-
|
|
|
- const materials = {};
|
|
|
-
|
|
|
- const darkMaterial = new THREE.MeshBasicMaterial({ color: 'black' });
|
|
|
-
|
|
|
- const bloomPass = new UnrealBloomPass(new THREE.Vector2(renderer.domElement.innerWidth, renderer.domElement.innerHeight), 1.5, 0.4, 0.85);
|
|
|
- bloomPass.threshold = params.threshold;
|
|
|
- bloomPass.strength = params.strength;
|
|
|
- bloomPass.radius = params.radius;
|
|
|
-
|
|
|
- const bloomRenderTarget = new THREE.WebGLRenderTarget(renderer.domElement.innerWidth, renderer.domElement.innerHeight, {
|
|
|
- type: THREE.HalfFloatType,
|
|
|
- });
|
|
|
- const bloomComposer = new EffectComposer(renderer, bloomRenderTarget);
|
|
|
- bloomComposer.renderToScreen = false;
|
|
|
- bloomComposer.addPass(renderScene);
|
|
|
- bloomComposer.addPass(bloomPass);
|
|
|
- const shader = new THREE.ShaderMaterial({
|
|
|
- uniforms: {
|
|
|
- baseTexture: { value: null },
|
|
|
- bloomTexture: { value: bloomComposer.renderTarget2.texture },
|
|
|
- bloomStrength: { value: params.strength },
|
|
|
- },
|
|
|
- vertexShader: `varying vec2 vUv;
|
|
|
-
|
|
|
- void main() {
|
|
|
-
|
|
|
- vUv = uv;
|
|
|
-
|
|
|
- gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
|
-
|
|
|
- }`,
|
|
|
- fragmentShader: `uniform sampler2D baseTexture;
|
|
|
- uniform sampler2D bloomTexture;
|
|
|
- uniform float bloomStrength;
|
|
|
-
|
|
|
- varying vec2 vUv;
|
|
|
-
|
|
|
- void main() {
|
|
|
-
|
|
|
- gl_FragColor = ( texture2D( baseTexture, vUv ) + texture2D( bloomTexture, vUv ) * bloomStrength );
|
|
|
-
|
|
|
- }`,
|
|
|
- defines: {},
|
|
|
- });
|
|
|
-
|
|
|
- const mixPass = new ShaderPass(shader, 'baseTexture');
|
|
|
- mixPass.needsSwap = true;
|
|
|
-
|
|
|
- const outputPass = new OutputPass();
|
|
|
-
|
|
|
- const finalRenderTarget = new THREE.WebGLRenderTarget(modal.canvasContainer.clientWidth, modal.canvasContainer.clientHeight, {
|
|
|
- type: THREE.HalfFloatType,
|
|
|
- samples: 4,
|
|
|
- });
|
|
|
- const finalComposer = new EffectComposer(renderer, finalRenderTarget);
|
|
|
- finalComposer.addPass(renderScene);
|
|
|
- finalComposer.addPass(mixPass);
|
|
|
- finalComposer.addPass(outputPass);
|
|
|
-
|
|
|
- // 注气动画
|
|
|
- const changjingzhuqiguan = zhuqiModal.getObjectByName('changjingzhuqiguan');
|
|
|
- if (changjingzhuqiguan) {
|
|
|
- const zhuqiPips = changjingzhuqiguan.children.filter((item) => {
|
|
|
- return item.name.includes('changjingwire');
|
|
|
- });
|
|
|
- zhuqiPips.forEach((item) => {
|
|
|
- // modal.scene.add(item);
|
|
|
- const material = new THREE.MeshStandardMaterial({ color: '#f00', roughness: 1, metalness: 1 });
|
|
|
- item.material = material;
|
|
|
- item.layers.enable(BLOOM_SCENE);
|
|
|
- });
|
|
|
-
|
|
|
- return { zhuqiPips, bloomComposer, finalComposer, materials, darkMaterial, shader, bloomLayer };
|
|
|
- }
|
|
|
- return null;
|
|
|
-}
|
|
|
-
|
|
|
-function addArrow(zhuqiModal, curveNum = 8) {
|
|
|
- const changjing5 = zhuqiModal.getObjectByName('changjing5');
|
|
|
- if (changjing5) {
|
|
|
- const pCube53 = changjing5.getObjectByName('pCube53');
|
|
|
- pCube53.material.color.set('#888');
|
|
|
- // 盒子
|
|
|
- const box = new THREE.Box3();
|
|
|
- box.setFromObject(pCube53);
|
|
|
- const min = box.min;
|
|
|
- const max = box.max;
|
|
|
- const height = -300;
|
|
|
- // 获取包围盒的四个顶点
|
|
|
- const vertices = [
|
|
|
- new THREE.Vector3(min.x + 200, min.y + 500, min.z), // 点 4
|
|
|
- new THREE.Vector3(max.x, min.y + 500, min.z), //点3
|
|
|
- new THREE.Vector3(min.x + 200, max.y, min.z), // 起点1
|
|
|
- new THREE.Vector3(max.x, max.y, min.z), // 点2
|
|
|
- ];
|
|
|
-
|
|
|
- // 绘制钻孔曲线
|
|
|
- // 根据份数计算均线位置, max.x - min.x 为总长, 端点坐标
|
|
|
- // 纵长
|
|
|
- const num1 = curveNum + 1; // 钻孔个数+1
|
|
|
- const gap = (max.x - (min.x + 200)) / num1;
|
|
|
- const curvePoints: THREE.Vector3[] = [];
|
|
|
- for (let i = 0; i < num1; i++) {
|
|
|
- if (i !== 0) {
|
|
|
- const x = min.x + 200 + gap * i;
|
|
|
- const y = min.y + 500;
|
|
|
- const z = min.z + height;
|
|
|
- const position = new THREE.Vector3(x, y, z);
|
|
|
- curvePoints.push(position);
|
|
|
-
|
|
|
- // const ball = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshStandardMaterial({ color: '#f00' }));
|
|
|
- // ball.position.set(position.x, position.y, position.z);
|
|
|
- // pCube53.add(ball);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 绘制终点集合
|
|
|
- // (max.y - min.y + 300)
|
|
|
- const startP = min.y + 300 + (max.y - (min.y + 300)) / 2; // 起点
|
|
|
- const len = max.y - startP;
|
|
|
- const curvePoints1: THREE.Vector3[] = [];
|
|
|
- for (let i = 0; i < curveNum; i++) {
|
|
|
- const x = curvePoints[curvePoints.length - i - 1].x;
|
|
|
- const y = startP + (len / curveNum) * i;
|
|
|
- const z = min.z + height;
|
|
|
- const position = new THREE.Vector3(x, y, z);
|
|
|
- curvePoints1.push(position);
|
|
|
-
|
|
|
- // const ball = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshStandardMaterial({ color: '#ff0' }));
|
|
|
- // ball.position.set(position.x, position.y, position.z);
|
|
|
- // pCube53.add(ball);
|
|
|
- }
|
|
|
-
|
|
|
- // 绘制起点集合
|
|
|
- const curvePoints0: THREE.Vector3[] = [];
|
|
|
- for (let i = 0; i < curvePoints.length; i++) {
|
|
|
- const position = new THREE.Vector3(vertices[2].x + 50 * i, vertices[2].y - 50, min.z);
|
|
|
- curvePoints0.unshift(position);
|
|
|
- // const ball = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshStandardMaterial({ color: '#0ff' }));
|
|
|
- // ball.position.copy(position);
|
|
|
- // pCube53.add(ball);
|
|
|
- }
|
|
|
-
|
|
|
- // 绘制控制点
|
|
|
- const curvePoints2: THREE.Vector3[] = [];
|
|
|
- for (let i = 0; i < curvePoints.length; i++) {
|
|
|
- const y = curvePoints1[i].y + (vertices[2].y - curvePoints1[i].y) / 2;
|
|
|
- const x = curvePoints1[i].x - gap / 2;
|
|
|
- const position = new THREE.Vector3(x, y, min.z + height / 2);
|
|
|
- curvePoints2.push(position);
|
|
|
- // const ball = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshStandardMaterial({ color: '#00f' }));
|
|
|
- // ball.position.copy(position);
|
|
|
- // pCube53.add(ball);
|
|
|
- }
|
|
|
-
|
|
|
- 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 = 50;
|
|
|
- texture.repeat.y = 6;
|
|
|
- // 设置管道纹理偏移数,便于对中
|
|
|
- texture.offset.y = 100;
|
|
|
- const tubeMaterial = new THREE.MeshPhongMaterial({
|
|
|
- map: texture,
|
|
|
- color: '#fff',
|
|
|
- transparent: true,
|
|
|
- opacity: 1.0,
|
|
|
- });
|
|
|
-
|
|
|
- // 根据起点curvePoints0、控制点curvePoints2、终点curvePoints1集合 绘制多条管道
|
|
|
- for (let i = 0; i < curvePoints0.length; i++) {
|
|
|
- const contrlP2 = new THREE.Vector3(curvePoints1[i].x, curvePoints1[i].y - 500 * (i + 1), curvePoints1[i].z);
|
|
|
- const points = [curvePoints0[i], curvePoints2[i], curvePoints1[i], contrlP2];
|
|
|
- const vec3List = new THREE.CubicBezierCurve3(...points).getPoints();
|
|
|
- vec3List.push(curvePoints[curvePoints0.length - i - 1]);
|
|
|
- const geometry = new THREE.TubeGeometry(new THREE.CatmullRomCurve3(vec3List), 100, 10, 8, false);
|
|
|
- const material = new THREE.MeshStandardMaterial({
|
|
|
- color: '#4F4F4F',
|
|
|
- roughness: 0.31,
|
|
|
- metalness: 0.74,
|
|
|
- });
|
|
|
- const mesh = new THREE.Mesh(geometry, material);
|
|
|
- pCube53.add(mesh);
|
|
|
-
|
|
|
- const geometry1 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3(vec3List), 100, 40, 8, false);
|
|
|
- const mesh1 = new THREE.Mesh(geometry1, tubeMaterial.clone());
|
|
|
- mesh.name = 'zk' + i;
|
|
|
- pCube53.add(mesh1);
|
|
|
- pCube53.updateMatrixWorld();
|
|
|
- pCube53.updateMatrix();
|
|
|
- mesh1.renderOrder = 1;
|
|
|
- zhuqiZkList.push(mesh1);
|
|
|
- }
|
|
|
-
|
|
|
- zhuqiZkList.reverse();
|
|
|
- return { texture };
|
|
|
- }
|
|
|
- return null;
|
|
|
-}
|
|
|
-
|
|
|
-function addUnit(zhuqiModal, unitNum = 8) {
|
|
|
- const changjingzhuqiguan = zhuqiModal.getObjectByName('changjingzhuqiguan');
|
|
|
- if (changjingzhuqiguan) {
|
|
|
- changjingzhuqiguan.parent.remove(changjingzhuqiguan);
|
|
|
- }
|
|
|
- const choucaiguandao = zhuqiModal.getObjectByName('choucaiguandao');
|
|
|
- if (choucaiguandao) {
|
|
|
- choucaiguandao.parent.remove(choucaiguandao);
|
|
|
- }
|
|
|
-
|
|
|
- const changjing5 = zhuqiModal.getObjectByName('changjing5');
|
|
|
- if (changjing5) {
|
|
|
- const pCube53 = changjing5.getObjectByName('pCube53');
|
|
|
- // 盒子
|
|
|
- const box = new THREE.Box3();
|
|
|
- box.setFromObject(pCube53);
|
|
|
- const min = box.min;
|
|
|
- const max = box.max;
|
|
|
- const height = 300;
|
|
|
- // 获取包围盒的四个顶点
|
|
|
- const vertices = [
|
|
|
- new THREE.Vector3(min.x, min.y + 400, min.z + height), // 点 4
|
|
|
- new THREE.Vector3(max.x, min.y + 400, min.z + height), //点3
|
|
|
- new THREE.Vector3(min.x, max.y - 700, min.z + height), // 起点1
|
|
|
- new THREE.Vector3(max.x, max.y - 700, min.z + height), // 点2
|
|
|
- ];
|
|
|
-
|
|
|
- // const num = 4;
|
|
|
- // // 绘制 mun 个小球
|
|
|
- // for (let i = 0; i < num; i++) {
|
|
|
- // const ball = new THREE.Mesh(new THREE.SphereGeometry(100, 32, 32), new THREE.MeshStandardMaterial({ color: '#f00' }));
|
|
|
- // ball.position.set(vertices[i].x, vertices[i].y, vertices[i].z);
|
|
|
- // pCube53.add(ball);
|
|
|
- // }
|
|
|
-
|
|
|
- const textureLoader = new THREE.TextureLoader();
|
|
|
- const texture = textureLoader.load(`/texture/3-2.png`);
|
|
|
-
|
|
|
- // 设置阵列模式 RepeatWrapping
|
|
|
- texture.wrapS = THREE.RepeatWrapping;
|
|
|
- texture.wrapT = THREE.RepeatWrapping;
|
|
|
- // 设置x方向的重复数(沿着管道路径方向)
|
|
|
- // 设置y方向的重复数(环绕管道方向)
|
|
|
- texture.repeat.x = 0.4;
|
|
|
- texture.repeat.y = 1;
|
|
|
- // // 设置管道纹理偏移数,便于对中
|
|
|
- texture.offset.y = 1;
|
|
|
- const tubeMaterial = new THREE.MeshPhongMaterial({
|
|
|
- map: texture,
|
|
|
- // color: '#FF3B40',
|
|
|
- color: '#FFC4C4',
|
|
|
- transparent: true,
|
|
|
- opacity: 0.5,
|
|
|
- side: THREE.DoubleSide,
|
|
|
- });
|
|
|
-
|
|
|
- // 横长
|
|
|
- const len = max.y - 700 - (min.y + 400);
|
|
|
- const gap = len / unitNum;
|
|
|
- const curvePoints: THREE.Vector3[] = [];
|
|
|
- // 绘制区域面
|
|
|
- let lastP = new THREE.Vector3(vertices[0].x, vertices[0].y, vertices[0].z);
|
|
|
- for (let i = 0; i < unitNum; i++) {
|
|
|
- let p1, p2, p3, p4;
|
|
|
- if (i == 0) {
|
|
|
- const x = vertices[0].x;
|
|
|
- const y = vertices[0].y + gap;
|
|
|
- const z = vertices[0].z;
|
|
|
- p1 = lastP.clone();
|
|
|
- p2 = new THREE.Vector3(x, y, z);
|
|
|
- p3 = new THREE.Vector3(max.x, y, z);
|
|
|
- p4 = new THREE.Vector3(max.x, vertices[0].y, vertices[0].z);
|
|
|
- lastP = p2.clone();
|
|
|
- } else {
|
|
|
- p1 = lastP.clone();
|
|
|
- p2 = new THREE.Vector3(p1.x, p1.y + gap, p1.z);
|
|
|
- p3 = new THREE.Vector3(max.x, p2.y, p2.z);
|
|
|
- p4 = new THREE.Vector3(max.x, p1.y, p1.z);
|
|
|
- lastP = p2.clone();
|
|
|
- }
|
|
|
-
|
|
|
- // 绘制面
|
|
|
- if (p1 && p2 && p3 && p4) {
|
|
|
- const geometry = new THREE.BufferGeometry();
|
|
|
- geometry.setFromPoints([p1, p2, p3, p3, p4, p1]);
|
|
|
- const material = new THREE.MeshPhongMaterial({
|
|
|
- color: '#f00',
|
|
|
- });
|
|
|
- const mesh = new THREE.Mesh(geometry, tubeMaterial.clone());
|
|
|
- pCube53.add(mesh);
|
|
|
-
|
|
|
- // p1 p2 p3 p4
|
|
|
- // 在该区域内绘制管道, p2->p3走向的管道
|
|
|
- const num = 5; // 管道数量-1
|
|
|
- let startGap = getMinGapThreshold(gap, num - 2);
|
|
|
- startGap = startGap + startGap / 3;
|
|
|
- const unitGap = (gap - startGap * 2) / (num - 2);
|
|
|
- const gapStartP = new THREE.Vector3(p1.x, p1.y + startGap, p1.z);
|
|
|
- for (let i = 0; i < num - 1; i++) {
|
|
|
- const startP = new THREE.Vector3(gapStartP.x, gapStartP.y + unitGap * i, gapStartP.z);
|
|
|
- const endP = new THREE.Vector3(max.x, startP.y, startP.z);
|
|
|
- const geometry = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([startP, endP]), 100, 6, 8, false);
|
|
|
- const material = new THREE.MeshStandardMaterial({
|
|
|
- color: '#6F6F6F',
|
|
|
- roughness: 0.31,
|
|
|
- metalness: 0.74,
|
|
|
- });
|
|
|
- const mesh = new THREE.Mesh(geometry, material);
|
|
|
- pCube53.add(mesh);
|
|
|
- }
|
|
|
-
|
|
|
- const y = p1.y + (p2.y - p1.y) / 2;
|
|
|
- const startP = new THREE.Vector3(p1.x, y, p1.z - 20);
|
|
|
- const endP = new THREE.Vector3(max.x, y, p1.z - 20);
|
|
|
- const cuver = new THREE.CatmullRomCurve3([endP, startP]);
|
|
|
- const points = cuver.getPoints(64);
|
|
|
- // const geometry1 = new THREE.TubeGeometry(new THREE.CatmullRomCurve3([endP, startP]), 64, 50, 4, false);
|
|
|
- // const mesh1 = new THREE.Mesh(geometry1, tubeMaterial);
|
|
|
- // pCube53.add(mesh1);
|
|
|
-
|
|
|
- const pathPointList = new PathPointList();
|
|
|
- const up = new THREE.Vector3(0, 0, -1);
|
|
|
- pathPointList.set(points, 0, 0, up, false);
|
|
|
- const geometry1 = new PathGeometry(points.length, false);
|
|
|
- geometry1.update(pathPointList, {
|
|
|
- width: 200,
|
|
|
- arrow: false,
|
|
|
- });
|
|
|
- const mesh1 = new THREE.Mesh(geometry1, tubeMaterial.clone());
|
|
|
- mesh1.renderOrder = 99;
|
|
|
- pCube53.add(mesh1);
|
|
|
- gasUnitList.push(mesh1);
|
|
|
- }
|
|
|
- }
|
|
|
- return { arrowTexture: texture };
|
|
|
- }
|
|
|
- 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);
|
|
|
- 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.clone());
|
|
|
- mesh.position.copy(zhuqiguandao.position);
|
|
|
- mesh.name = 'pip' + i;
|
|
|
- zhuqiModal.add(mesh);
|
|
|
- zhuqiPipList.push(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 - 总长度
|
|
|
- * @param {number} num - 数量/分段数
|
|
|
- * @returns {number} 返回 gap 必须大于的这个值
|
|
|
- */
|
|
|
-function getMinGapThreshold(len, num) {
|
|
|
- if (num <= 0) {
|
|
|
- throw new Error('num 必须大于 0');
|
|
|
- }
|
|
|
- if (len <= 0) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- // 公式推导结果: 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);
|
|
|
-}
|
|
|
-/***绘制波纹标识 */
|