继上一篇文章中实现了三维管道的可视化和流动模拟,经过反馈,对大家还是有一定帮助,因此就编写了一个续集,相当于增加了一些常见的通用共性功能,主要在前面的基础上增加了以下功能:
1.新增直角拐弯的管道,工业中很多管道都是横平竖直的,相当于我们装修的水管或电线等,不是曲线而是直线,夹角基本都是90度。
2.新增透明管道和不透明管道的动态模拟,通过材质和透明度属性(transparent)进行设置。
3.新增不同管道采用不同的材质和速度进行流动模拟,相当于管道总支和分支的动态模拟。
4.新增网格显示,便于做对齐校正、对比显示。
5.新增不同管道的点击时的详细信息框显示,比如显示管道名称、管径、长度、流动速度等。
开发环境和之前的一样,实现效果如下:
Vue+Three.js,实现原理和之前类似,通过不断改变管道的Texture实现管道动态流动模拟,不同管道设置不同的Texture和更新速度,重复代码请参加上一篇文章,这里主要显示不同的代码,代码详见pipe4.vue。
核心代码如下:
//pipe4.vue
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 = `基本信息
名称:${intersects[0].object.userData.name}
管径:${intersects[0].object.userData.radius}m
速度:${intersects[0].object.userData.speed}m/s
长度:${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;
}