Vue+Three.js实现三维管道可视化及流动模拟续集

上一篇文章中实现了三维管道的可视化和流动模拟,经过反馈,对大家还是有一定帮助,因此就编写了一个续集,相当于增加了一些常见的通用共性功能,主要在前面的基础上增加了以下功能:
1.新增直角拐弯的管道,工业中很多管道都是横平竖直的,相当于我们装修的水管或电线等,不是曲线而是直线,夹角基本都是90度。
2.新增透明管道和不透明管道的动态模拟,通过材质和透明度属性(transparent)进行设置。
3.新增不同管道采用不同的材质和速度进行流动模拟,相当于管道总支和分支的动态模拟。
4.新增网格显示,便于做对齐校正、对比显示。
5.新增不同管道的点击时的详细信息框显示,比如显示管道名称、管径、长度、流动速度等。

开发环境和之前的一样,实现效果如下:

Vue+Three.js,实现原理和之前类似,通过不断改变管道的Texture实现管道动态流动模拟,不同管道设置不同的Texture和更新速度,重复代码请参加上一篇文章,这里主要显示不同的代码,代码详见pipe4.vue。

核心代码如下:

javascript 复制代码
//pipe4.vue
<template>  
  <div class="home" id="myDiv" ref="container">  
    <div id="objInfor"></div>  
  </div>
</template>
const z=20;//管道垂直下移数量  
export default {  
  name: "pipe4",
  mounted() {  
	  this.init();  
	  this.initGrid();//加入网格  
  },
  methods:{  
  /**  
   * 初始化方法  
   */  
  init() {
	  // 4.Mesh 渲染对象,包括Mesh 几何体 (形状等)和材质。4.1和4.2  
	  this.initTubeModel();
	  //增加鼠标点击事件,用于处理管道信息框的显示
	  document.addEventListener("mousedown",this.getClickObj,false);
	  
  },
  initGrid(){  
  let grid = new THREE.GridHelper( 300, 8, '#bfc7d3', 'rgb(126,151,176)' );  
  grid.position.set(0,-100,-50);//xzy  
  this.scene.add( grid );  
},  
initTubeModel() {  
  //第一条管线数据,可来自实际业务数据  
  var pointsArr = [  
    [42, z, 10],  
    [21, z, 10],  
    [1, z, 24],  
    [-27, z, 24],  
    [-27, z, 18],  
    [-46, z, 19],  
    [-46, z, -4],  
    [-25, z, -6],  
    [-25, z, -19],  
    [-35, z, -20],  
    [-35, z, -26],  
    [-30, z, -30],  
    [3, z, -30],  
    [42, z, -30]  
  ];  
  //第二条管线数据,可来自实际业务数据  
  var pointsArr2 = [  
    [1, z, 10],  
    [1, z, 2],  
    [30, z, 2],  
    [30, z, -10],  
    [40, z, -10],  
    [42, z, -30]  
  ];  
  var curve = createPath(pointsArr);  
  this.createTube(curve,'arrow8.png',0.0066,'管道1');  
  var curve2 = createPath(pointsArr2);  
  this.createTube(curve2,'arrow7.png',0.0036,'管道2');  
},
//createTube进行的重现,主要接受了三个参数,分别为坐标生成的管道对象,材质图像,移动速度,管道名称等。
createTube(curve,textureImage,textureSpeed,name){  
  var tubeGeometry = new THREE.TubeGeometry(curve, 100, 1.5, 200, false);  
  var textureLoader = new THREE.TextureLoader();  
  var texture = textureLoader.load('http://localhost:8082/static/data/'+textureImage); //./ZS箭头.svg  ./arrow.jpg  
  // 设置阵列模式为 RepeatWrapping  texture.wrapS = THREE.RepeatWrapping  
  texture.wrapT = THREE.RepeatWrapping  
  texture.repeat.x = 50;  
  texture.repeat.y = 2;  
  texture.offset.y = 0.3;  
  
  var tubeMaterial = new THREE.MeshPhongMaterial({  
    map: texture,  
    transparent: true,  
    // color: 'rgba(ff,ff,ff,0.05)',//'rgba(237,149,3,0.05)'  
    side: THREE.DoubleSide,  
    opacity: 0.7,  
  });  
  
  // 设置数组材质对象作为网格模型材质参数  
  var mesh = new THREE.Mesh(tubeGeometry, tubeMaterial); //网格模型对象Mesh  
  mesh.position.y = 2;  
  mesh.rotateZ(3.14);  
  mesh.scale.set(2, 2, 2);  
  // 使用加减法可以设置不同的运动方向  
  setInterval(() => {  
    texture.offset.x -= textureSpeed  
  });  
  //添加用户自定义的数据,可自定义增加任意数据,json格式。  
  mesh.userData={'name':name,'radius':tubeGeometry.parameters.radius,'width':200,'speed':textureSpeed*10000};  
  this.scene.add(mesh); //网格模型添加到场景中  
},  
//鼠标点击事件,获取对象信息,对象信息在mesh.userData  
getClickObj(event){  
  //申明raycaster和mouse变量  
  var raycaster = new THREE.Raycaster();  
  var mouse = new THREE.Vector2();  
  //通过鼠标点击的地位计算出raycaster所须要的点的地位,以屏幕核心为原点,值的范畴为-1到1.  
  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;  
  mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;    
  // 通过鼠标点的地位和以后相机的矩阵计算出raycaster  
  raycaster.setFromCamera( mouse, this.camera );  
  
  // 获取raycaster直线和所有模型相交的数组汇合  
  var intersects = raycaster.intersectObjects( this.scene.children );  
  //有相交物体时  
  if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型  
    console.log('显示');  
    //设置信息  
    infoBox.innerHTML = `<div style=\"background-color: rgba(122,243,215,0.85)\">基本信息</div>  
						名称:${intersects[0].object.userData.name}  
						<br>管径:${intersects[0].object.userData.radius}m  
						<br>速度:${intersects[0].object.userData.speed}m/s  
						<br>长度:${intersects[0].object.userData.width}m`;
    objInfor.style.display = "block";  
    console.log(event.clientX);  
    objInfor.style.left = event.clientX + "px"; //记得一定要拼接px  
    objInfor.style.top = event.clientY + "px"  
  }  
}
}
}
// 根据三维点数据形成三维曲线路径。  
function createPath(pointsArr) {  
  pointsArr = pointsArr.map((point) => new THREE.Vector3(...point)); // 将参数数组转换成点数组的形式  
  
  // 方法一:自定义三维路径 curvePath  const path = new THREE.CurvePath();  
  for (let i = 0; i < pointsArr.length - 1; i++) {  
    const lineCurve = new THREE.LineCurve3(pointsArr[i], pointsArr[i + 1]); // 每两个点之间形成一条三维直线  
    path.curves.push(lineCurve); // curvePath有一个curves属性,里面存放组成该三维路径的各个子路径  
  }  
  return path;  
}
相关推荐
Mike_jia20 分钟前
Memos:知识工作者的理想开源笔记系统
前端
前端大白话20 分钟前
前端崩溃瞬间救星!10 个 JavaScript 实战技巧大揭秘
前端·javascript
loveoobaby21 分钟前
Shadertoy着色器移植到Three.js经验总结
前端
蓝易云24 分钟前
在Linux、CentOS7中设置shell脚本开机自启动服务
前端·后端·centos
浩龙不eMo25 分钟前
前端获取环境变量方式区分(Vite)
前端·vite
一千柯橘31 分钟前
Nestjs 解决 request entity too large
javascript·后端
土豆骑士35 分钟前
monorepo 实战练习
前端
土豆骑士37 分钟前
monorepo最佳实践
前端
见青..38 分钟前
【学习笔记】文件包含漏洞--本地远程包含、伪协议、加密编码
前端·笔记·学习·web安全·文件包含
举个栗子dhy1 小时前
如何处理动态地址栏参数,以及Object.entries() 、Object.fromEntries()和URLSearchParams.entries()使用
javascript