vue-three 基础模板

2021-12-01  本文已影响0人  name_howe
<template>
  <div>
    <div id="three"></div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
export default {
  data() {
    return {
      scene: {}, // 场景
      camera: {}, // 摄像机
      renderer: {}, // 渲染器
      parts: [], // 几何图形储存器
      mixer: null, // 动画
      clock: {}
    };
  },
  mounted(){
    this.threes();
    this.resize(); // 自适应
    this.mousedown(); // 鼠标点击事件
    this.mod();
  },
  methods: {
    // 浏览器窗口发生变化时 自适应
    resize(){
      window.addEventListener('resize', () => {

        // 初始化摄像机
        this.camera.aspect = window.innerWidth/window.innerHeight;

        // 摄像机矩阵效果
        this.camera.updateProjectionMatrix();

        // 初始化渲染器
        this.renderer.setSize(window.innerWidth, window.innerHeight);

      })
    },

    threes() {
      // 创建场景
      this.scene = new THREE.Scene();

      // 创建摄像机 // 参数含义: 视角、窗口投影长宽比、摄像机从哪里开始渲染、距离摄像机多远截至渲染
      this.camera = new THREE.PerspectiveCamera(100, window.innerWidth/window.innerHeight, 0.1, 1000);

      // 创建three渲染器 参数: 去锯齿
      this.renderer = new THREE.WebGLRenderer({ antialias: true });

      // 设置渲染器场景背景颜色
      this.renderer.setClearColor(0x000000, .2)

      // 开启阴影,加上阴影渲染
      this.renderer.shadowMapEnabled = true;

      // 设置渲染器场景大小 参数: 宽,高
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      
      // 把渲染器添加到页面中
      document.getElementById('three').appendChild(this.renderer.domElement);

      this.plane() // 平面模型

      this.wall({x: 500, y: 60, z: 10}, {x: 0, y: 30, z: -145}) // 外墙壁 1
      this.wall({x: 500, y: 60, z: 10}, {x: 0, y: 30, z: 145}) // 外墙壁 2
      this.wall({x: 10, y: 60, z: 300}, {x: 250, y: 30, z: 0}) // 外墙壁 3
      this.wall({x: 10, y: 60, z: 300}, {x: -250, y: 30, z: 0}) // 外墙壁 4

      this.wall({x: 10, y: 60, z: 120}, {x: 160, y: 30, z: -80}) // 内墙壁 5
      this.wall({x: 90, y: 60, z: 10}, {x: 200, y: 30, z: -20}) // 内墙壁 6

      for(let i = 0; i < 4; i ++){
        // this.chartlet(-220, 30, (-100 +  i * 41)) // 横排
        this.chartlet((-220 + i * 35), 30, -100) // 纵排
        this.chartlet((-220 + i * 35), 30, -55) // 纵排
        this.chartlet((-220 + i * 35), 30, 100) // 纵排
        this.chartlet((-220 + i * 35), 30, 55) // 纵排
      }
      this.vavAair(100,50,135)

      // 将网格对象添加到场景中
      this.parts.forEach(item => {
        this.scene.add(item);
      });
      
      // 创建光源
      this.createLight()

      // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
      this.axesHelper = new THREE.AxesHelper(500);

      // 将坐标系添加到场景中
      this.scene.add(this.axesHelper);

      // 摄像机空间轴位置
      this.camera.position.z = 300
      this.camera.position.y = 350
      this.camera.position.x = 100

      // 创建鼠标控件对象
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);

      this.animate()
    },

    // 添加帧渲染
    animate(){
      let that = this
      requestAnimationFrame(this.animate);
      // 网格对象自动旋转
      // this.cube.rotation.x += 0.005
      // this.cube.rotation.y += 0.005

      if (this.mixer !== null){
        that.mixer.update(that.clock.getDelta());
      }

      // 初始化controls
      this.controls.update()

      this.render()
    },

    // 渲染器渲染场景和摄像机
    render(){
      this.renderer.render(this.scene, this.camera)
    },

    // 创建光源
    createLight () {
      // 环境光
      const ambint = new THREE.AmbientLight(0xffffff)
      this.scene.add(ambint)
      // 聚光灯光源
      this.spotLight(0x03FF6A, 245, 60, 140, 600)
      this.spotLight(0xff0000, -245, 60, 140, 500)
      // this.pointLight(0xffffff, 0, 900, 0, 1000)
      this.pointLight(0x0070ee, 205, 100, -80, 130)
    },

    // 聚光灯光源
    spotLight (color, x, y, z, dis) {
      const spotLight = new THREE.SpotLight(color)
      spotLight.position.set(x, y, z); // 光源位置
      spotLight.castShadow = true; //开启灯光投射阴影
      spotLight.intensity = 3 // 强度
      spotLight.angle = 0.3; // 角度
      spotLight.penumbra = 1; // 半影
      spotLight.decay = 1; // 衰退
      spotLight.distance = dis; // 距离

      this.scene.add(spotLight)

      // 辅助线
      // let spotLightHelper = new THREE.SpotLightHelper(spotLight, 0x976fb6);
      // this.scene.add(spotLightHelper)

      // 光源寄托
      this.createLightView(color, x, y, z)
    },
    // 点光灯光源
    pointLight (color, x, y, z, dis) {
      const pointLight = new THREE.PointLight(color)
      pointLight.position.set(x, y, z); // 光源位置
      pointLight.castShadow = true; //开启灯光投射阴影
      pointLight.intensity = 4 // 强度
      // pointLight.angle = 0.3; // 角度
      pointLight.penumbra = 1; // 半影
      // pointLight.decay = 1; // 衰退
      pointLight.distance = dis; // 距离

      this.scene.add(pointLight)

      // 辅助线
      // let spotLightHelper = new THREE.SpotLightHelper(pointLight, 0x976fb6);
      // this.scene.add(spotLightHelper)

      // 光源寄托
      this.createLightView(color, x, y, z)
    },

    // 光源寄托
    createLightView(color, x, y, z){
      let geometry = new THREE.SphereGeometry(3, 3, 3);
      let material = new THREE.MeshPhongMaterial({ color });
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(x, y, z)
      this.scene.add(cube)
    },

    // 平面模型
    plane(){
      let geometry = new THREE.PlaneGeometry(640, 400, 1, 1);
      let material = new THREE.MeshPhongMaterial({ color: 0xE5E5E5, wireframe: false });
      let cube = new THREE.Mesh(geometry, material);
      cube.rotation.x = -0.5 * Math.PI
      cube.position.set(0, 0, 0)
      cube.receiveShadow = true

      this.parts.push(cube)
    },

    // 墙壁
    wall(size, position){
      let texture = new THREE.TextureLoader().load(require('@/assets/three/tile.jpg'));
      texture.anisotropy = 4
      let data = {
        map: texture,
        // color: 0x07313F,
        transparent: true,
        opacity: 1
      }
      let geometry = new THREE.BoxGeometry(size.x, size.y,size.z);
      let material = new THREE.MeshLambertMaterial(data);
      let cube = new THREE.Mesh(geometry, material);
      cube.position.set(position.x, position.y, position.z)
      this.scene.add(cube);
    },

    // 机柜
    chartlet(x, y, z){
      let map = new THREE.TextureLoader().load(require('@/assets/three/jigui.jpg'));
      let group = new THREE.Mesh();
      let mats = [];
      mats.push(new THREE.MeshPhongMaterial({ map }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0x3C3B42
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0x3C3B42
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0x3C3B42
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0x3C3B42
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0x3C3B42
      }));

      let cubeGeom = new THREE.BoxBufferGeometry(15, 50, 30);
      let cube = new THREE.Mesh(cubeGeom, mats);
      cube.position.set(x, y, z)

      group.add(cube);
      this.scene.add(group)
    },

    // 空调
    vavAair(x, y, z){
      let map = new THREE.TextureLoader().load(require('@/assets/three/kt.png'));
      let group = new THREE.Mesh();
      let mats = [];
      mats.push(new THREE.MeshPhongMaterial({ color: 0xffffff }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0xffffff
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0xffffff
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0xffffff
      }));
      mats.push(new THREE.MeshPhongMaterial({
        color: 0xffffff
      }));
      mats.push(new THREE.MeshPhongMaterial({
        map
      }));

      let cubeGeom = new THREE.BoxBufferGeometry(40, 15, 15);
      let cube = new THREE.Mesh(cubeGeom, mats);
      cube.position.set(x, y, z)

      group.add(cube);
      this.scene.add(group)
    },

    // 鼠标点击事件
    mousedown(){
      let raycaster = new THREE.Raycaster(); //光线投射,用于确定鼠标点击位置
      let mouse1 = new THREE.Vector2()
      let mouse2 = new THREE.Vector2()

      let top = 69

      window.addEventListener("pointerdown", (event) => {
        mouse1.x = ( event.clientX / window.innerWidth ) * 2 - 1;
        mouse1.y = - ( (event.clientY - top) / window.innerHeight ) * 2 + 1;
      });
      window.addEventListener("pointerup", (event) => {
        mouse2.x = ( event.clientX / window.innerWidth ) * 2 - 1;
        mouse2.y = - ( (event.clientY - top) / window.innerHeight ) * 2 + 1;
        if(mouse1.x === mouse2.x && mouse1.y === mouse2.y){
          //以camera为z坐标,确定所点击物体的3D空间位置
          raycaster.setFromCamera(mouse1, this.camera);
          //确定所点击位置上的物体数量
          let intersects = raycaster.intersectObjects(this.scene.children);
          //选中后进行的操作
          if(intersects.length){
            console.log(intersects)
            // intersects[0].object.material.color.set( 0xff0000 );
          }
        }
      });
    },

    // 引入模型 人物
    mod(){
      let that = this
      let loader = new FBXLoader()
      loader.load('three/SambaDancing.fbx', function(obj){
        obj.scale.set(.35, .35, .35); // 放大缩小
        obj.position.set(205, 0, -80); // 位置
        obj.rotation.y += 1.55; // 旋转
        that.scene.add(obj)

        that.clock = new THREE.Clock()
        // obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
        that.mixer = new THREE.AnimationMixer(obj);
        let animationAction = that.mixer.clipAction(obj.animations[0]);
        // animationAction.timeScale = 1; //默认1,可以调节播放速度
        // animationAction.loop = THREE.LoopOnce; //不循环播放
        // animationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
        animationAction.play(); //播放动画
      }, undefined, function ( error ) {
        console.error( error );
      });
    },

  }

};
</script>

<style scoped>
body {
  margin: 0;
  padding: 0;
  background-color: #000;
  color: #fff;
  font-family: Monospace;
  font-size: 13px;
  line-height: 24px;
  overscroll-behavior: none;
}
#info {
  position: absolute;
  top: 0px;
  width: 100%;
  padding: 0;
  box-sizing: border-box;
  text-align: center;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
  pointer-events: none;
  z-index: 1; /* TODO Solve this in HTML */
}
</style>
上一篇下一篇

猜你喜欢

热点阅读