使用vue的组件和three.js画出3d模型图
直接上代码,有问题评论区联系吧,经常在线。qq:2277655147
<template>
<div class="card text-center m-b-20">
<div class="card-body text-muted" >
<h4 class="mt-0 header-title" style="font-weight: bold;font-size: 20px; height: 40px;">{
{
equipmentTitle}}</h4>
<div class="paramPanel" v-show="sensorModel.sphereModel">
<el-row>
<label>{
{
sensorModel.sensorName}}:{
{
sensorModel.sensorValue}}</label>
</el-row>
</div>
<el-carousel
trigger="click"
:autoplay="false"
:height="modelHeight"
arrow="always"
@change="equipmentChange"
>
<el-carousel-item v-for="(item,index) in equipmentData" :key="index" >
<div ref="panel3d" :style="'height: '+modelHeight"></div>
</el-carousel-item>
</el-carousel>
</div>
</div>
<!--<div ref="panel3d" style="height: 31vh;"></div>-->
</template>
<script>
import * as THREE from 'three'
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import {
STLLoader } from 'three/examples/jsm/loaders/STLLoader'
import * as TWEEN from '../../../Tween.js';
export default {
// props:['pointsInfo','sensorModel','equipmentTitle','parentActiveName','parentMethod','styleHeight'],
/*
*equipmentData:3d模型所需要的标题和监测点数据
* equipmentChangeParent:设备变化之后的方法
* sensorChangeParent:传感器变化之后的方法
* styleHeight:3d模型的高度
* initHighLight:是否初始化高亮
*/
props:['equipmentData','equipmentChangeParent','sensorChangeParent','styleHeight','initHighLight'],
data() {
let temp_height=this.styleHeight;
if(!this.styleHeight){
temp_height='35vh';
}
return{
//3d图
scene: null,
camera: null,
raycaster: null,
renderer: null,
controls: null,
material: null,
mesh: null,
INTERSECTED: null,
INTERSECTEDForcus: null,
pointsInfo: [],
points: null,
pointShells: null,
width: 0,
height: 0,
//固定模型
modelInfo:{
path:'/big.STL',
position:{
x:108,
y:0,
z:-137,
},
rotation:'-90',
scale:'0.052',
},
//模型的高度
modelHeight:temp_height,
//轮播图第一个
sensorModel:{
sphereModel:false,
sensorName:'',
sensorValue:'',
},
//变压器标题
equipmentTitle:'',
//所有监测点
parentActiveName:'',
//展示的第几个
index:0,
//所有的模型
indexs:[]
}
},
watch:{
'equipmentTitle'(value){
if(value==this.parentActiveName){
if(this.points){
if(!this.INTERSECTED){
this.sensorModel.sphereModel=false;
return false;
}
for(let i = 0; i < this.points.children.length; i++){
if(this.points.children[i] == this.INTERSECTED){
this.sensorModel.sphereModel=true;
this.sensorModel.sensorName=this.pointsInfo[i].sensorName;
this.sensorModel.sensorValue=this.pointsInfo[i].sensorValue;
}
}
}
}
},
},
created() {
this.getData();
},
methods: {
getData(){
this.$nextTick(function() {
if(this.equipmentData[this.index]){
this.equipmentTitle=this.equipmentData[this.index].equipmentName;
this.init3DModel(this.index);
this.pointsInfo=this.equipmentData[this.index].sensor;
}
// this.equipmentData.forEach((value, index)=> {
// });
this.sphere();
if(this.initHighLight){
this.initMouseDown();
}
});
},
initMouseDown(){
if(this.points.children[this.index]){
let point= this.points.children[this.index];
this.INTERSECTED = point;
this.INTERSECTEDForcus = false;
this.highLight();
}
},
init3DModel(index){
this.width = this.$refs.panel3d[index].clientWidth;
this.height = this.$refs.panel3d[index].clientHeight;
//初始化场景
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color( 0x1B4B9D );//0x006699
this.scene.fog = new THREE.FogExp2( 0x006699, 0.0007 );
//初始化相机配置
this.camera = new THREE.PerspectiveCamera(70, this.width / this.height, 1, 10000);
this.camera.position.set(600, 300, 0);
let tempLookAt = this.scene.position;
tempLookAt.y = -160;
this.camera.lookAt(tempLookAt);
this.raycaster = new THREE.Raycaster();
//初始化渲染器
this.renderer = new THREE.WebGLRenderer( {
alpha: true } );
this.renderer.setClearColor( 0x0000FF, 0 );
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.width, this.height);
this.$refs.panel3d[index].appendChild(this.renderer.domElement);
//光源
let light = new THREE.AmbientLight(0x888888, 0.6);
this.scene.add(light);
let directionalLight = new THREE.DirectionalLight(0x888888, 1.1);
directionalLight.position.set(300, 1000, 500);
directionalLight.target.position.set(0, 0, 0);
directionalLight.castShadow = true;
let d = 300;
directionalLight.shadow.camera = new THREE.OrthographicCamera(-d, d, d, -d, 500, 1600);
directionalLight.shadow.bias = 0.0001;
directionalLight.shadow.mapSize.width = directionalLight.shadow.mapSize.height = 1024;
this.scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0x888888, 1.1);
directionalLight.position.set(-300, -1000, -500);
directionalLight.target.position.set(0, 0, 0);
directionalLight.castShadow = true;
d = 300;
directionalLight.shadow.camera = new THREE.OrthographicCamera(-d, d, d, -d, 500, 1600);
directionalLight.shadow.bias = 0.0001;
directionalLight.shadow.mapSize.width = directionalLight.shadow.mapSize.height = 1024;
this.scene.add(directionalLight);
//网格
var gridHelper = new THREE.GridHelper(600, 60);
this.scene.add(gridHelper);
//控制器
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.25;
this.controls.rotateSpeed = 0.35;
//添加事件
window.addEventListener('resize', this.onWindowResize, false);
this.loop();
//模型材质
this.material = new THREE.MeshPhysicalMaterial({
color: 0xB0C4DE,
metalness: 0,
roughness: 0.5,
reflectivity: 0.5,
envMap: null
});
this.points = new THREE.Object3D();
this.pointShells = new THREE.Object3D();
let loader = new STLLoader();
let _this = this;
loader.load(_this.modelInfo.path, function(geometry) {
_this.mesh = new THREE.Mesh(geometry, _this.material);
_this.mesh.position.set(_this.modelInfo.position.x, _this.modelInfo.position.y, _this.modelInfo.position.z);
_this.mesh.scale.set(_this.modelInfo.scale, _this.modelInfo.scale, _this.modelInfo.scale);
_this.mesh.rotation.set(0, (_this.modelInfo.rotation / 180) * Math.PI, 0);
_this.mesh.castShadow = true;
_this.mesh.receiveShadow = true;
_this.mesh.name = 'model';
_this.scene.add(_this.mesh);
_this.renderer.domElement.addEventListener('mousedown', _this.onDocumentMouseDown, false);
});
},
sphere(){
if(this.scene && this.pointsInfo){
this.pointsInfo.forEach(info=>{
if(info.position){
var sphereGeo = new THREE.SphereGeometry(4, 8, 8);//创建球体
var sphereMat = new THREE.MeshLambertMaterial({
//创建材料
color:0x00FF00,
wireframe:false
});
var sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);//创建球体网格模型
sphereMesh.position.set(info.position.x,info.position.y,info.position.z);//设置球的坐标
sphereMesh.name = info.id;
this.points.add(sphereMesh);
var sphereMat = new THREE.MeshLambertMaterial({
//创建材料
color:0x00FF00,
opacity: 0, transparent: true
});
var sphereGeo = new THREE.SphereGeometry(20, 20, 20);//创建球体
var sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);//创建球体网格模型
sphereMesh.position.set(info.position.x,info.position.y,info.position.z);//设置球的坐标
sphereMesh.name = info.id;
this.pointShells.add(sphereMesh);
}
});
this.scene.add(this.points);
this.scene.add(this.pointShells);
}
},
loop() {
requestAnimationFrame(this.loop);
TWEEN.update();
this.render();
},
render(){
if(this.renderer){
this.renderer.render(this.scene, this.camera);
}
},
startTween(pointPosition, cameraPosition){
var x = pointPosition.x;
var newX = cameraPosition.x;
var y = pointPosition.y;
var newY = cameraPosition.y;
var z = pointPosition.z;
var newZ = cameraPosition.z;
var _this = this;
new TWEEN.Tween( this.camera.position )
.to( {
x: newX,
y: newY,
z: newZ
} )
.easing( TWEEN.Easing.Linear.None ).onUpdate( function () {
_this.camera.lookAt(pointPosition.x, pointPosition.y-160, pointPosition.z);
_this.controls.target.set(x, y-160, z);
} )
.onComplete( function () {
_this.camera.lookAt(pointPosition.x, pointPosition.y-160, pointPosition.z);
_this.controls.update();
} )
.start();
},
highLight(){
if(this.points){
for(let i = 0; i < this.points.children.length; i++){
this.points.children[i].material.emissive.setHex(0x000000);
if(this.points.children[i] == this.INTERSECTED){
this.points.children[i].material.emissive.setHex(0xff0000);//原来位绿色,加上红色为黄色
if(this.INTERSECTEDForcus == false){
this.startTween(this.points.children[i].position, this.pointsInfo[i].camera);
this.INTERSECTEDForcus = true;
this.sensorModel.sphereModel=true;
this.sensorModel.sensorName=this.pointsInfo[i].sensorName;
this.sensorModel.sensorValue=this.pointsInfo[i].sensorValue;
if(this.sensorChangeParent){
this.sensorChangeParent(this.pointsInfo[i].code,this.equipmentData[this.index].code,this.pointsInfo[i].sensorAllValue);
}
}
}
}
}
},
onDocumentMouseDown(event){
let mouse = new THREE.Vector2();
event.preventDefault();
let tempRect = this.renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX-tempRect.left)/this.width) * 2 - 1;
mouse.y = -((event.clientY-tempRect.top)/this.height) * 2 + 1;
this.raycaster.setFromCamera(mouse, this.camera);
let intersects = this.raycaster.intersectObjects(this.pointShells.children);
if (intersects.length > 0) {
let point;
for(let i = 0; i < this.points.children.length; i++){
if(this.points.children[i].name == intersects[ 0 ].object.name){
point = this.points.children[i];
}
}
if(intersects.length > 0 && this.INTERSECTED != point) {
this.INTERSECTED = point;
this.INTERSECTEDForcus = false;
this.highLight();
}
//失去焦点的时候
else if(intersects.length > 0 && this.INTERSECTED == point){
//取消焦点和位置数据
this.INTERSECTED = null;
this.INTERSECTEDForcus = false;
//改变颜色
this.highLight();
// //设置摄像头的位置
this.camera.position.set(400, 300, 0);
// //设置查看的位置
let tempLookAt = this.scene.position;
tempLookAt.y = -160;
this.camera.lookAt(tempLookAt);
//取消注释
this.sensorModel.sphereModel=false;
}
}
},
onWindowResize(){
if(!this.$refs.panel3d[this.index]){
return false;
}
this.width = this.$refs.panel3d[this.index].clientWidth;
this.height = this.$refs.panel3d[this.index].clientHeight;
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.width, this.height);
},
equipmentChange(newIndex,oldIndex){
this.index=newIndex;
//延时清除一下旧的canvas,
setTimeout(function (){
document.getElementsByTagName('canvas')[oldIndex].remove();
},600);
//标题
this.equipmentTitle=this.equipmentData[newIndex].equipmentName;
//监测点信息
this.pointsInfo=this.equipmentData[newIndex].sensor;
//场景
this.init3DModel(newIndex);
//球
this.sphere();
//对应当前选中的值清除一下
this.sensorModel.sphereModel=false;
//父类方法调用
if(this.equipmentChangeParent){
this.equipmentChangeParent(this.equipmentData[newIndex].code,this.equipmentData[newIndex]);
}
},
}
};
</script>