Newer
Older
shipFront / src / views / device / device.vue
[wangxitong] on 29 Dec 2021 8 KB 气象站
<template>
  <div class="overview">
    <div class="top">
      <div  class="block" v-for="(value,key,index) in data" :key="index" @click="btnClick(value)">
        <image-block :data="value"/>
      </div>
    </div>
    <div ref="body" class="body">
      <left ref="left" class="left"/>
      <div ref="right" class="middle">
        <div class="title">{{active}}</div>
        <div class="angle">横滚角: {{roll}} <br/>俯仰角: {{pitch}} <br/>航向角: {{heading}} </div>
        <div ref="device"/>
      </div>
      <right ref="devright" class="right"/>
    </div>
  </div>
</template>

<script>

import { getRobotList,getRobotDetail,getRobotTask } from '@/api/robot'
import ImageBlock from "./components/imageBlock";
import Left from './left'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader'
import OrbitControls from 'three-orbitcontrols'
import dat from 'dat.gui'
import Right from "./right";
var refresh = false
export default {
  name: 'Device',
  components: {Right, Left,ImageBlock, THREE, dat,OrbitControls,GLTFLoader,STLLoader},
  data() {
    return {
      active: '飞翼滑翔机一号',
      roll: '45.21°',
      pitch: '51.41°',
      heading: '93.00°',
      arr:[],
      controls: null,
      scene: null,
      gltf: null,
      camera: null,
      renderer: null,
      plane:null,
      paramsThree: {
        modelName: '', // .glb模型的文件名字
        name: 'devGlb', // 模型加入场景的名字,此处统一是devGlb
      },
      data:[
        // {name:'飞翼滑翔机一号',gltf:''},
        // {name:'飞翼滑翔机二号',gltf:''},
        // {name:'飞翼滑翔机三号',gltf:''},
        // {name:'飞翼滑翔机四号',gltf:''},
        // {name:'飞翼滑翔机五号',gltf:''},
        // {name:'飞翼滑翔机六号',gltf:''},
        // {name:'飞翼滑翔机七号',gltf:''},
        // {name:'飞翼滑翔机八号',gltf:''}
      ]
    }
  },
  created() {
    this.$nextTick(() => {
      this.init()
    })
  },
  watch:{
    'camera.rotation.x':{
      handler: function() {
        this.pitch = (this.camera.rotation.x/Math.PI*180+this.arr[1]).toFixed(2) + '°'
        this.roll = (this.camera.rotation.y/Math.PI*180+this.arr[0]).toFixed(2) + '°'
        this.heading = (this.camera.rotation.z/Math.PI*180+this.arr[2]).toFixed(2) + '°'
      }
    }
  },
  methods: {
    btnClick(val){
      this.active = val.name
      getRobotTask(val.id).then(res => {
        if (res.code === 200) {
          this.$refs.left.initTask(res.data)
        }
      })
      getRobotDetail(val.id).then(res => {
        if (res.code === 200) {
          this.$refs.left.init(res.data)
          this.$refs.devright.init(res.data)
          this.roll = res.data.rollAngle + '°'
          this.pitch = res.data.pitchAngle + '°'
          this.heading = res.data.headingAngle + '°'
          this.arr = [res.data.rollAngle,res.data.pitchAngle,res.data.headingAngle]
          this.initModel(val.gltf,res.data.rollAngle,res.data.pitchAngle,res.data.headingAngle)
        }
      })
    },
    init () {
      this.initList()
      this.initMesh()
    },
    initModel(name,roll,pitch,heading){
      let that = this
      this.gltf = null
      if(this.scene&&this.paramsThree.modelName!==''){
        let objM = this.scene.getObjectByName(this.paramsThree.modelName)
        if (objM) this.scene.remove(objM)
        refresh = true
      }
      if(name==='') return
      const loader = new STLLoader();
      loader.load(`${process.env.BASE_URL}model/${name}.stl`, function ( geometry ) {

        const material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shininess: 200 } );
        const mesh = new THREE.Mesh( geometry, material );
        mesh.name = name
        mesh.position.set( 0,0,0);
        mesh.rotation.set( pitch*Math.PI/180, roll*Math.PI/180, heading*Math.PI/180 );
        mesh.scale.set( 0.03, 0.03, 0.03 );

        mesh.castShadow = true;
        mesh.receiveShadow = true;

        that.scene.add( mesh );
        that.paramsThree.modelName = name
        that.gltf = mesh
      } );
    },
    addShadowedLight( x, y, z, color, intensity ) {

      const directionalLight = new THREE.DirectionalLight( color, intensity );
      directionalLight.position.set( x, y, z );
      this.scene.add( directionalLight );

      directionalLight.castShadow = true;

      const d = 1;
      directionalLight.shadow.camera.left = - d;
      directionalLight.shadow.camera.right = d;
      directionalLight.shadow.camera.top = d;
      directionalLight.shadow.camera.bottom = - d;

      directionalLight.shadow.camera.near = 1;
      directionalLight.shadow.camera.far = 4;

      directionalLight.shadow.bias = - 0.002;

    },
    initList(){
      getRobotList().then(res => {
        if (res.code === 200) {
          this.data = res.data.map(item => {
            return {name:'飞翼滑翔机'+item.robotId+'号',id:item.robotId,gltf:item.modelType}
          })
          this.btnClick(this.data[0])
        }
      })
    },
    initMesh () {
      this.scene = new THREE.Scene() // 场景
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000) // 相机.视场,长宽比,近面,远面
      this.camera.position.set( 0, 0, 30 );
      this.camera.lookAt(this.scene.position)

      this.renderer = new THREE.WebGLRenderer({ antialias: true })// 渲染器
      this.renderer.setClearColor(0x179AC6, 1); //设置背景颜色
      this.renderer.setSize(this.$refs.right.clientWidth,this.$refs.right.clientHeight)
      this.renderer.shadowMapEnabled = true // 开启阴影

      this.scene.add( new THREE.HemisphereLight( 0x443333, 0x111122 ) );

      this.addShadowedLight( 1, 1, 1, 0xffffff, 1.35 );
      this.addShadowedLight( 0.5, 1, - 1, 0xffffff, 1 );

      this.$refs.device.append(this.renderer.domElement)
      this.renderer.render(this.scene, this.camera)
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);  //摄像机和容器div   注意事div
      this.controls.mouseButtons = {
        //左键平移
        LEFT: THREE.MOUSE.PAN,
        //滚轮滑动
        MIDDLE: THREE.MOUSE.DOLLY,
        //右键旋转
        RIGHT: THREE.MOUSE.ROTATE
      }
      // 使动画循环使用时阻尼或自转 意思是否有惯性
      this.controls.enableDamping = false;
      //是否可以缩放
      this.controls.enableZoom = true;
      //是否自动旋转
      this.controls.autoRotate = true;
      // //设置相机距离原点的最远距离
      // this.controls.minDistance = 200;
      //设置相机距离原点的最远距离
      this.controls.maxDistance = 600;
      //是否开启右键拖拽
      this.controls.enablePan = true;
      this.renderScene()
    },
    renderScene () {
      let {scene, camera, renderer} = this
      requestAnimationFrame(this.renderScene)
      if(refresh){
        refresh = false
        camera.position.set( 0, 0, 30 )
        camera.lookAt(scene.position)
      }
      renderer.render(scene, camera)
    }
  }
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
  .overview{
    display: flex;
    flex-direction: column;
    padding-right: 30px;
    width: 100%;
    height: 100%;
    .title{
      color: #ffffff;
      font-size: 20px;
      font-weight: bold;
      position: absolute;
      top: 30px;
      left: 360px;
    }
    .angle{
      color: #2f3244;
      font-size: 17px;
      position: absolute;
      top: 80px;
      left: 360px;
      line-height: 25px;
    }
    .top{
      margin: 10px 30px;
      display: flex;
      flex-direction: row;
      .block{
        width: 12.5%;
        height: 30px;
        margin-right: 10px;
      }
    }
    .body{
      position:relative;
      width: 100%;
      flex: 1;
      display: flex;
      flex-direction: row;
      .left{
        margin-left: 20px;
        min-width: 300px;
        width: 300px;
        display: flex;
        flex-direction: column;
        padding-bottom: 20px;
      }
      .right{
        margin-left: 20px;
        margin-right: 10px;
        min-width: 200px;
        width: 200px;
        display: flex;
        flex-direction: column;
        padding-bottom: 20px;
      }
      .middle{
        flex: 1;
        /*background-color: #E6A23C;*/
        margin-left: 20px;
        margin-top: 5px;
        margin-bottom: 25px;
      }
    }
    .map{
      width: 100%;
      flex: 1;
      background-color: white;
    }
  }
</style>