vr全景看房的方案 three.js

WebGL3D引擎

http://www.webgl3d.cn/threejs/docs/#api/zh/core/Raycaster
一.客户端,加载六张图及按钮位置,点击按钮删除旧的图及按钮,加载下一组图

<template>
  <div class="home">
    <div>
      <div id="container" style="height: 900px;transition:all 0.5s"></div>
    </div>
  </div>
</template>

<script>
// @ is an alias to /src
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

export default {
  name: "Home",
  components: {
  },
  data(){
    return {
      camera:null,
      scene: null,
      renderer: null,
      controls: null,
      poiObjects: [],
      box:null,
      button:[],
      text:[],
    }
  },
  mounted() {
    this.scene = new THREE.Scene()
    this.initThree();
    this.drawOut()
    this.scroll()
    this.func()
    this.scecond();
  },
  methods: {
    scecond() {
      document.getElementById('container').style.transform = 'scale(1,1)'
      if(this.scene){
        this.button.forEach((item)=>{
          this.scene.remove(item)
        })
        this.scene.remove(this.box)
        this.text.forEach((item)=>{
          this.scene.remove(item)
        })
      }
      let data = {
        left:require("./images/scene_left1.jpg"),
        right:require("./images/scene_right1.jpg"),
        top:require("./images/scene_top1.jpg"),
        bottom:require("./images/scene_bottom1.jpg"),
        front:require("./images/scene_front1.jpg"),
        back:require("./images/scene_back1.jpg")
      }
      let hotPoints = [
        {
          position: {
            x: 0.45,
            y: 0,
            z: -0.3,
          },
          detail: {
            title: "卧室",
            path:'卧室'
          },
        },
        // {
        //   position: {
        //     x: -0.2,
        //     y: -0.05,
        //     z: 0.45,
        //   },
        //   detail: {
        //     title: "信息点2",
        //   },
        // },
      ];
      this.draw(data)
      this.firstButton(hotPoints)
      this.showText(hotPoints)
    },
    first() {
      document.getElementById('container').style.transform = 'scale(1,1)'
      if(this.scene){
        this.button.forEach((item)=>{
          this.scene.remove(item)
        })
        this.scene.remove(this.box)
        this.text.forEach((item)=>{
          this.scene.remove(item)
        })
      }
      // var texture = new THREE.TextureLoader().load("./images/scene.jpeg");
      // var sphereMaterial = new THREE.MeshBasicMaterial({ map: texture });

      // var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
      // // sphere.material.wireframe  = true;
      // var sphereGeometry = new THREE.SphereGeometry(/*半径*/ 1, 50, 50);
      // sphereGeometry.scale(1, 1, -1);
      let data = {
        left:require("./images/scene_left.jpg"),
        right:require("./images/scene_right.jpg"),
        top:require("./images/scene_top.jpg"),
        bottom:require("./images/scene_bottom.jpg"),
        front:require("./images/scene_front.jpg"),
        back:require("./images/scene_back.jpg")
      }
      let hotPoints = [
        {
          position: {
            x: 0.05,
            y: -0.2,
            z: -0.45,
          },
          detail: {
            title: "看书",
            path:'看书'
          },
        },
        {
          position: {
            x: 0.45,
            y: 0,
            z: -0.05,
          },
          detail: {
            title: "大厅",
            path:'大厅'
          },
        },
      ];
      this.draw(data)
      this.firstButton(hotPoints)
      this.showText(hotPoints)
    },
    firstButton(hotPoints){
      var pointTexture = new THREE.TextureLoader().load(
        require("./images/button.png")
      );
      var material = new THREE.SpriteMaterial({ map: pointTexture });
      this.poiObjects = [];
      this.button = []
      for (var i = 0; i < hotPoints.length; i++) {
        var sprite = new THREE.Sprite(material);
        sprite.scale.set(0.05, 0.05, 0.05);
        sprite.position.set(
          hotPoints[i].position.x,
          hotPoints[i].position.y,
          hotPoints[i].position.z
        );
        this.button.push(sprite)
        this.scene.add(sprite);
        sprite.detail = hotPoints[i].detail;
        this.poiObjects.push(sprite);
      }
    },
    showText(hotPoints) {
      this.text = []
      for (var i = 0; i < hotPoints.length; i++) {
        // var text = new THREE.FontLoader().load(require("./font/NotoKR-Black_Black.json"), function(text) {
        //   console.log(123)
        //   var gem = new THREE.TextGeometry('51JOB', {
        //       size: 20, //字号大小,一般为大写字母的高度
        //       height: 10, //文字的厚度
        //       weight: 'normal', //值为'normal'或'bold',表示是否加粗
        //       font: text, //字体,默认是'helvetiker',需对应引用的字体文件
        //       style: 'normal', //值为'normal'或'italics',表示是否斜体
        //       bevelThickness: 1, //倒角厚度
        //       bevelSize: 1, //倒角宽度
        //       curveSegments: 30,//弧线分段数,使得文字的曲线更加光滑
        //       bevelEnabled: true, //布尔值,是否使用倒角,意为在边缘处斜切
        //   });
        //   gem.center();
        //   var mat = new THREE.MeshPhongMaterial({
        //       color: 0xffe502,
        //       specular: 0x009900,
        //       shininess: 30,
        //       shading: THREE.FlatShading
        //   });
        //   var textObj = new THREE.Mesh(gem, mat);
        //   textObj.castShadow = true;
        //   console.log('!!!!',textObj)
        //   scene.add(textObj);
        //   new TWEEN.Tween(textObj.rotation).to({y: Math.PI * 2}, 2000).repeat(Infinity).yoyo(true).start();
        // });
        //创建canvas对象用来绘制文字
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext("2d");
        ctx.fillStyle = "red";
        ctx.font = "bolder 10px Arial ";
        ctx.fillText(hotPoints[i].detail.title, 140, 65);
        ctx.globalAlpha = 1;

        // 将画布生成的图片作为贴图给精灵使用,并将精灵创建在设定好的位置
        let texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;
        //创建精灵,将该材质赋予给创建的精灵
        // let spriteMaterial = new THREE.PointsMaterial({
        //   map: texture,
        //   // sizeAttenuation: true,
        //   // size: 30,
        //   transparent: true,
        //   opacity: 1,
        // });
        // //创建坐标点,并将材质给坐标
        // let geometry = new THREE.BufferGeometry();
        // let vertices = [0, 0, 0];
        // geometry.setAttribute(
        //   "position",
        //   new THREE.Float32BufferAttribute(vertices, 3)
        // );
        // let sprite = new THREE.Points(geometry, spriteMaterial);
        // sprite.position.set(position.x, position.y, position.z);
        // sprite.scale.set(0.01, 0.01, 0.01);
        // this.scene.add(sprite);


        // const canvasTexture = new THREE.CanvasTexture(
        //     document.querySelector("#canvas")
        // )
        // //canvasTexture.needsUpdate = true; //注意这句不能少
        const spritMaterial = new THREE.SpriteMaterial({
            map: texture
        })
        let sprite = new THREE.Sprite(spritMaterial)
        sprite.position.set(hotPoints[i].position.x, hotPoints[i].position.y, hotPoints[i].position.z);
        //精灵的默认大小很小估计是[1,1,1]
        sprite.scale.set(0.5, 0.5, 0.5);
        this.text.push(sprite)
        this.scene.add(sprite)
      }
    },
    initThree() {
        //镜头
        this.camera = new THREE.PerspectiveCamera(
          90,
          document.body.clientWidth / 900,
          0.1,
          100
        );
        // document.body.clientWidth / document.body.clientHeight

        this.camera.up.x = 0; //相机以哪个方向为上方
        this.camera.up.y = 1;
        this.camera.up.z = 0; //默认值

        // 镜头初始位置
        this.camera.position.set(0, 0, 0.01);
        // camera.lookAt(0,0,0) //使用了OrbitControls导致无法使用 改用controls的target
        //渲染器
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(document.body.clientWidth, 900);
        this.renderer.shadowMap.enabled = true; //告诉渲染器需要阴影效果
        document.getElementById("container").appendChild(this.renderer.domElement);
        //镜头控制器
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);

        this.controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度

        this.controls.dampingFactor = 0.14; //动态阻尼系数 就是鼠标拖拽旋转灵敏度
        this.controls.enableZoom = true; //是否可以缩放
        this.controls.zoomSpeed = 5;

        this.controls.autoRotate = true; //是否自动旋转
        this.controls.autoRotateSpeed = 0.5;

        this.controls.minDistance = 0; //设置相机距离原点的最小距离

        this.controls.maxDistance = 10; //设置相机距离原点的最远距离

        this.controls.enablePan = false; //是否开启右键拖拽平移
        this.controls.panSpeed = 10; //平移速度

        this.controls.enableKeys = false; //启用或禁用键盘控制
        this.controls.keyPanSpeed = 30; //键盘平移速度
        this.controls.keys = {
          LEFT: 37, //left arrow
          UP: 38, // up arrow
          RIGHT: 39, // right arrow
          BOTTOM: 40, // down arrow
        };

        let m = new THREE.Vector3();
        m.x = 0;
        m.y = 0;
        m.z = 0;
        this.controls.target = m; //控制看向某个方向
        //一会儿在这里添加3D物体
        this.loop();
    },
    //帧同步重绘
    loop() {
      this.controls.update();
      requestAnimationFrame(this.loop);
      this.renderer.render(this.scene, this.camera);
    },
    // 绘制六张图
    draw(datas){
      var materials = [];
      //根据左右上下前后的顺序构建六个面的材质集
      var texture_left = new THREE.TextureLoader().load(
        datas.left
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_left }));

      var texture_right = new THREE.TextureLoader().load(
        datas.right
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_right }));

      var texture_top = new THREE.TextureLoader().load(
        datas.top
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_top }));

      var texture_bottom = new THREE.TextureLoader().load(
        datas.bottom
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_bottom }));

      var texture_front = new THREE.TextureLoader().load(
        datas.front
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_front }));

      var texture_back = new THREE.TextureLoader().load(
        datas.back
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_back }));

      var box = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), materials);
      this.box = box
      this.scene.add(box);

      box.geometry.scale(1, 1, -1);
    },
    //绘制外层圆形轮廓
    drawOut(){
      var sphereGeometry = new THREE.SphereGeometry(
        /*半径*/ 1,
        /*垂直节点数量*/ 50,
        /*水平节点数量*/ 50
      ); //节点数量越大,需要计算的三角形就越多,影响性能

      var sphere = new THREE.Mesh(sphereGeometry);
      sphere.material.wireframe = true; //用线框模式大家可以看得清楚是个球体而不是圆形
      this.scene.add(sphere);
    },
    // 滚动事件
    scroll(){
      var fov = 90;
      var near = 45;
      var far = 100;
      var scrollFunc = (event) => {
        // event.preventDefault();
        //event.stopPropagation();
        if (event.wheelDelta) {
          //判断浏览器IE,谷歌滑轮事件
          if (event.wheelDelta > 0) {
            //当滑轮向上滚动时
            fov -= near < fov ? 1 : 0;
          } else {
            //当滑轮向下滚动时
            fov += fov < far ? 1 : 0;
          }
        }
        //改变fov值,并更新场景的渲染
        this.camera.fov = fov;
        this.camera.updateProjectionMatrix();
        this.renderer.render(this.scene, this.camera);
      };
      /*IE、Opera注册事件*/
      if (document.attachEvent) {
        document.attachEvent("onmousewheel", scrollFunc);
      }
      //Firefox使用addEventListener添加滚轮事件
      if (document.addEventListener) {
        //firefox
        document.addEventListener("DOMMouseScroll", scrollFunc, false);
      }
      //Safari与Chrome属于同一类型
      window.onmousewheel = document.onmousewheel = scrollFunc;
    },
    func(){
      document
        .querySelector("#container")
        .addEventListener("click", (event) => {
          event.preventDefault();

          var raycaster = new THREE.Raycaster();
          var mouse = new THREE.Vector2();

          mouse.x = (event.clientX / document.body.clientWidth) * 2 - 1;
          mouse.y = -(event.clientY / document.body.clientHeight) * 2 + 1;

          raycaster.setFromCamera(mouse, this.camera);
          var intersects = raycaster.intersectObjects(this.poiObjects);
          if (intersects.length > 0) {
            // camera.position.set(0, 0.1, 0.01);
            if(intersects[0].object.detail.path === '看书'){
              alert(intersects[0].object.detail.title)
            }else if(intersects[0].object.detail.path === '卧室'){
              document.getElementById('container').style.transform = 'scale(100,100)'
              setTimeout(()=>{
                this.first()
              },250)
            }else if(intersects[0].object.detail.path === '大厅'){
              document.getElementById('container').style.transform = 'scale(100,100)'
              setTimeout(()=>{
                this.scecond()
              },250)
            }
            // controls.screenSpacePanning = true

            // alert("点击了热点" + intersects[0].object.detail.title);
          }
        });
    }
  },
};
</script>

二、后台,上传六张图片后,开始创建场景scene,右上角设置了多个按钮,点击不同按钮可设置不同的功能(通过status显示到客户端,如弹窗介绍,跳转场景),点击按钮后场景中会按钮,可调整位置,并将位置保存

<template>
  <div class="home">
    <!-- <div id="pre" style="position:absolute;left:0;top:0;height:900px">
      <img style="height:900px;" :src="loadPic[now]" alt="">
      <div @click="this.preview" style="position:absolute;left:0;top:0">预览</div>
      <div style="position:absolute;left:50%;top:0">{{now}}</div>
    </div> -->
    <div>
      <div id="container" style="height: 900px;position:relative"></div>
      <!-- <canvas canvas-id="canvas"></canvas> -->
    </div>
    <div style="position:fixed;right:0;top:0;display:flex;flex-direction:column;">
      <img @click="addButton(item)" v-for="(item, index) in someButton" :key="index" style="width:40px;height:40px;" :src="item.img" alt="">
    </div>
    <div v-if="select" style="position:fixed;right:50%;bottom:0;display:flex;flex-direction:column;">
      <div>
        当前选中: <input type="text" v-model="select.detail.title">
      </div>
      <div>
        <span>
          x: <input type="text" v-model="select.position.x">
          y: <input type="text" v-model="select.position.y">
          z: <input type="text" v-model="select.position.z">
        </span>
      </div>
      <div @click="confirm">确认</div>
      <div @click="del">删除</div>
    </div>
  </div>
</template>

<script>
// @ is an alias to /src
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

export default {
  name: "Home",
  components: {
  },
  data(){
    return {
      loadPic:{
        left:require("./images/scene_left.jpg"),
        right:require("./images/scene_right.jpg"),
        top:require("./images/scene_top.jpg"),
        bottom:require("./images/scene_bottom.jpg"),
        front:require("./images/scene_front.jpg"),
        back:require("./images/scene_back.jpg")
      },
      someButton:[
        {
          img:require("./images/button.png"),
          status:1
        },
        {
          img:require("./images/button.png"),
          status:2
        },
        {
          img:require("./images/button.png"),
          status:3
        },
      ],
      point: [],
      select:null,
      now:'left',
      camera:null,
      scene: null,
      renderer: null,
      controls: null,
      poiObjects: [],
    }
  },
  mounted() {
    this.preview()
  },
  methods: {
    addButton(item){
      var detail = prompt("输入名称")
      let id = new Date().getTime()
      this.point.push({
        position:{
          x:0,
          y:0,
          z:-0.2
        },
        detail: {
          title: detail,
          path:'大厅',
          status:item.status,
          id
        }
      })
      this.firstButton([{
        position:{
          x:0,
          y:0,
          z:-0.2
        },
        detail: {
          title: detail,
          path:'大厅',
          status:item.status,
          id
        }
      }])
      this.showText([{
        position:{
          x:0,
          y:0,
          z:-0.2
        },
        detail: {
          title: detail,
          path:'大厅',
          status:item.status,
          id
        }
      }])
    },
    preview(){
      this.scene = new THREE.Scene()
      this.initThree();
      this.drawOut()
      this.scroll()
      this.func()
      this.first();
    },
    first() {
      document.getElementById('container').style.transform = 'scale(1,1)'
      // var texture = new THREE.TextureLoader().load("./images/scene.jpeg");
      // var sphereMaterial = new THREE.MeshBasicMaterial({ map: texture });

      // var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
      // // sphere.material.wireframe  = true;
      // var sphereGeometry = new THREE.SphereGeometry(/*半径*/ 1, 50, 50);
      // sphereGeometry.scale(1, 1, -1);
      let data = this.loadPic
      let hotPoints = this.point
      this.draw(data)
      this.firstButton(hotPoints)
      this.showText(hotPoints)
    },
    firstButton(hotPoints){
      var pointTexture = new THREE.TextureLoader().load(
        require("./images/button.png")
      );
      var material = new THREE.SpriteMaterial({ map: pointTexture });
      this.poiObjects = [];
      for (var i = 0; i < hotPoints.length; i++) {
        var sprite = new THREE.Sprite(material);
        sprite.scale.set(0.05, 0.05, 0.05);
        sprite.position.set(
          hotPoints[i].position.x,
          hotPoints[i].position.y,
          hotPoints[i].position.z
        );
        this.scene.add(sprite);
        sprite.detail = hotPoints[i].detail;
        this.poiObjects.push(sprite);
      }
    },
    showText(hotPoints) {
      this.text = []
      for (var i = 0; i < hotPoints.length; i++) {
        // var text = new THREE.FontLoader().load(require("./font/NotoKR-Black_Black.json"), function(text) {
        //   console.log(123)
        //   var gem = new THREE.TextGeometry('51JOB', {
        //       size: 20, //字号大小,一般为大写字母的高度
        //       height: 10, //文字的厚度
        //       weight: 'normal', //值为'normal'或'bold',表示是否加粗
        //       font: text, //字体,默认是'helvetiker',需对应引用的字体文件
        //       style: 'normal', //值为'normal'或'italics',表示是否斜体
        //       bevelThickness: 1, //倒角厚度
        //       bevelSize: 1, //倒角宽度
        //       curveSegments: 30,//弧线分段数,使得文字的曲线更加光滑
        //       bevelEnabled: true, //布尔值,是否使用倒角,意为在边缘处斜切
        //   });
        //   gem.center();
        //   var mat = new THREE.MeshPhongMaterial({
        //       color: 0xffe502,
        //       specular: 0x009900,
        //       shininess: 30,
        //       shading: THREE.FlatShading
        //   });
        //   var textObj = new THREE.Mesh(gem, mat);
        //   textObj.castShadow = true;
        //   console.log('!!!!',textObj)
        //   scene.add(textObj);
        //   new TWEEN.Tween(textObj.rotation).to({y: Math.PI * 2}, 2000).repeat(Infinity).yoyo(true).start();
        // });
        //创建canvas对象用来绘制文字
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext("2d");
        ctx.fillStyle = "red";
        ctx.font = "bolder 10px Arial ";
        ctx.fillText(hotPoints[i].detail.title, 140, 65);
        ctx.globalAlpha = 1;

        // 将画布生成的图片作为贴图给精灵使用,并将精灵创建在设定好的位置
        let texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;
        const spritMaterial = new THREE.SpriteMaterial({
            map: texture
        })
        let sprite = new THREE.Sprite(spritMaterial)
        sprite.position.set(hotPoints[i].position.x, hotPoints[i].position.y, hotPoints[i].position.z);
        //精灵的默认大小很小估计是[1,1,1]
        sprite.scale.set(0.5, 0.5, 0.5);
        sprite.detail = hotPoints[i].detail;
        this.text.push(sprite)
        this.scene.add(sprite)
      }
    },
    initThree() {
        //镜头
        this.camera = new THREE.PerspectiveCamera(
          90,
          document.body.clientWidth / 900,
          0.1,
          100
        );
        // document.body.clientWidth / document.body.clientHeight

        this.camera.up.x = 0; //相机以哪个方向为上方
        this.camera.up.y = 1;
        this.camera.up.z = 0; //默认值

        // 镜头初始位置
        this.camera.position.set(0, 0, 0.01);
        // camera.lookAt(0,0,0) //使用了OrbitControls导致无法使用 改用controls的target
        //渲染器
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(document.body.clientWidth, 900);
        this.renderer.shadowMap.enabled = true; //告诉渲染器需要阴影效果
        document.getElementById("container").appendChild(this.renderer.domElement);
        //镜头控制器
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);

        this.controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度

        this.controls.dampingFactor = 0.14; //动态阻尼系数 就是鼠标拖拽旋转灵敏度
        this.controls.enableZoom = true; //是否可以缩放
        this.controls.zoomSpeed = 5;

        // this.controls.autoRotate = true; //是否自动旋转
        // this.controls.autoRotateSpeed = 0.5;

        this.controls.minDistance = 0; //设置相机距离原点的最小距离

        this.controls.maxDistance = 10; //设置相机距离原点的最远距离

        this.controls.enablePan = false; //是否开启右键拖拽平移
        this.controls.panSpeed = 10; //平移速度

        this.controls.enableKeys = false; //启用或禁用键盘控制
        this.controls.keyPanSpeed = 30; //键盘平移速度
        this.controls.keys = {
          LEFT: 37, //left arrow
          UP: 38, // up arrow
          RIGHT: 39, // right arrow
          BOTTOM: 40, // down arrow
        };

        let m = new THREE.Vector3();
        m.x = 0;
        m.y = 0;
        m.z = 0;
        this.controls.target = m; //控制看向某个方向
        //一会儿在这里添加3D物体
        this.loop();
    },
    //帧同步重绘
    loop() {
      this.controls.update();
      requestAnimationFrame(this.loop);
      this.renderer.render(this.scene, this.camera);
    },
    // 绘制六张图
    draw(datas){
      var materials = [];
      //根据左右上下前后的顺序构建六个面的材质集
      var texture_left = new THREE.TextureLoader().load(
        datas.left
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_left }));

      var texture_right = new THREE.TextureLoader().load(
        datas.right
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_right }));

      var texture_top = new THREE.TextureLoader().load(
        datas.top
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_top }));

      var texture_bottom = new THREE.TextureLoader().load(
        datas.bottom
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_bottom }));

      var texture_front = new THREE.TextureLoader().load(
        datas.front
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_front }));

      var texture_back = new THREE.TextureLoader().load(
        datas.back
      );
      materials.push(new THREE.MeshBasicMaterial({ map: texture_back }));

      var box = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), materials);
      this.box = box
      this.scene.add(box);

      box.geometry.scale(1, 1, -1);
    },
    //绘制外层圆形轮廓
    drawOut(){
      var sphereGeometry = new THREE.SphereGeometry(
        /*半径*/ 1,
        /*垂直节点数量*/ 50,
        /*水平节点数量*/ 50
      ); //节点数量越大,需要计算的三角形就越多,影响性能

      var sphere = new THREE.Mesh(sphereGeometry);
      sphere.material.wireframe = true; //用线框模式大家可以看得清楚是个球体而不是圆形
      this.scene.add(sphere);
    },
    // 滚动事件
    scroll(){
      var fov = 90;
      var near = 45;
      var far = 100;
      var scrollFunc = (event) => {
        // event.preventDefault();
        //event.stopPropagation();
        if (event.wheelDelta) {
          //判断浏览器IE,谷歌滑轮事件
          if (event.wheelDelta > 0) {
            //当滑轮向上滚动时
            fov -= near < fov ? 1 : 0;
          } else {
            //当滑轮向下滚动时
            fov += fov < far ? 1 : 0;
          }
        }
        //改变fov值,并更新场景的渲染
        this.camera.fov = fov;
        this.camera.updateProjectionMatrix();
        this.renderer.render(this.scene, this.camera);
      };
      /*IE、Opera注册事件*/
      if (document.attachEvent) {
        document.attachEvent("onmousewheel", scrollFunc);
      }
      //Firefox使用addEventListener添加滚轮事件
      if (document.addEventListener) {
        //firefox
        document.addEventListener("DOMMouseScroll", scrollFunc, false);
      }
      //Safari与Chrome属于同一类型
      window.onmousewheel = document.onmousewheel = scrollFunc;
    },
    func(){
      document
        .querySelector("#container")
        .addEventListener("click", (event) => {
          event.preventDefault();

          var raycaster = new THREE.Raycaster();
          var mouse = new THREE.Vector2();

          mouse.x = (event.clientX / document.body.clientWidth) * 2 - 1;
          mouse.y = -(event.clientY / document.body.clientHeight) * 2 + 1;

          raycaster.setFromCamera(mouse, this.camera);
          
          var intersects = raycaster.intersectObjects(this.poiObjects);
          console.log(intersects, mouse)
          if (intersects.length > 0) {
            this.select = {
              position:intersects[0].object.position,
              detail:intersects[0].object.detail
            }
            // camera.position.set(0, 0.1, 0.01);
            // if(intersects[0].object.detail.path === '看书'){
            //   alert(intersects[0].object.detail.title)
            // }else if(intersects[0].object.detail.path === '卧室'){
            //   document.getElementById('container').style.transform = 'scale(100,100)'
            //   setTimeout(()=>{
            //     this.first()
            //   },250)
            // }else if(intersects[0].object.detail.path === '大厅'){
            //   document.getElementById('container').style.transform = 'scale(100,100)'
            //   setTimeout(()=>{
            //     this.scecond()
            //   },250)
            // }
          }
        });
        // document
        // .querySelector("#container")
        // .addEventListener("mousemove", (event) => {
        //   console.log(123)
        //   event.preventDefault();

        //   var raycaster = new THREE.Raycaster();
        //   var mouse = new THREE.Vector2();

        //   mouse.x = (event.clientX / document.body.clientWidth) * 2 - 1;
        //   mouse.y = -(event.clientY / document.body.clientHeight) * 2 + 1;

        //   raycaster.setFromCamera(mouse, this.camera);
        //   var intersects = raycaster.intersectObjects(this.poiObjects);
        //   if (intersects.length > 0) {
        //     // camera.position.set(0, 0.1, 0.01);
        //     if(intersects[0].object.detail.path === '看书'){
        //       alert(intersects[0].object.detail.title)
        //     }else if(intersects[0].object.detail.path === '卧室'){
        //       document.getElementById('container').style.transform = 'scale(100,100)'
        //       setTimeout(()=>{
        //         this.first()
        //       },250)
        //     }else if(intersects[0].object.detail.path === '大厅'){
        //       document.getElementById('container').style.transform = 'scale(100,100)'
        //       setTimeout(()=>{
        //         this.scecond()
        //       },250)
        //     }
        //     // controls.screenSpacePanning = true

        //     // alert("点击了热点" + intersects[0].object.detail.title);
        //   }
        // });
    },
    confirm(){
      let arr = this.scene.children.filter((item)=>{
        if(!item.detail) return false
        return item.detail.id === this.select.detail.id 
      })
      let index = this.point.findIndex(item=>item.detail.id === this.select.detail.id)
      this.point.splice(index,1,this.select)
      arr.forEach((item)=>{
        this.scene.remove(item)
      })
      this.firstButton([this.select])
      this.showText([this.select])
      this.select = null
    },
    del(){
      let arr = this.scene.children.filter((item)=>{
        if(!item.detail) return false
        return item.detail.id === this.select.detail.id 
      })
      let index = this.point.findIndex(item=>item.detail.id === this.select.detail.id)
      this.point.splice(index,1)
      arr.forEach((item)=>{
        this.scene.remove(item)
      })
      this.select = null
    }
  },
};
</script>

借鉴于https://blog.csdn.net/weixin_36774307/article/details/118090868

功能 Three.js清除场景/模型释放内存
https://blog.csdn.net/qq_44375977/article/details/115871217

THREE.js创建三维文字TextGeometry
https://blog.csdn.net/unirrrrr/article/details/80651837

一张全景图

<template>
  <div class="home">
    <div ref="container" id="container" style="width: 100%; height: 800px"></div>
  </div>
</template>

<script>
// @ is an alias to /src
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

export default {
  name: "Home",
  components: {
  },
  data(){
    return {
      sceneUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F01dead58f03a61a8012049ef124133.jpg%403000w_1l_2o_100sh.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1636353181&t=8986b8074d4093d2fdc187ee5f562bd0', // 需要预览的图片绝对路径
      camera: null,
      scene: null,
      renderer: null,
      isUserInteracting: false,
      onPointerDownPointerX: 0,
      onPointerDownPointerY: 0,
      lon: 0,
      onPointerDownLon: 0,
      lat: 0,
      onPointerDownLat: 0,
      phi: 0,
      theta: 0,
      target: new THREE.Vector3()
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      let textureLoader = new THREE.TextureLoader();

      textureLoader.load(this.sceneUrl, (texture) => {
        texture.mapping = THREE.UVMapping;

        this.initImg(texture);
        this.render();
      });
    },
    initImg(texture) {
      let container, mesh;
      // 容器宽度、高度
      let containerWidth = this.$refs.container.offsetWidth;
      let containerHeight = this.$refs.container.offsetHeight;
      container = document.getElementById('container');
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setPixelRatio(window.devicePixelRatio);
      // this.renderer.setSize(window.innerWidth, window.innerHeight);
      this.renderer.setSize(containerWidth, containerHeight);
      let childs = container.childNodes;
      if (container.childNodes.length > 0) {
        container.removeChild(childs[0]);
        container.appendChild(this.renderer.domElement);
      } else {
        container.appendChild(this.renderer.domElement);
      }

      this.scene = new THREE.Scene();
      this.camera = new THREE.PerspectiveCamera(60, containerWidth  / containerHeight , 1, 1000);
      mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(500, 32, 16), new THREE.MeshBasicMaterial({ map: texture }));
      mesh.geometry.scale(-1, 1, 1);
      this.scene.add(mesh);

      container.addEventListener('mousedown', this.onDocumentMouseDown, false);
      container.addEventListener('mousemove', this.onDocumentMouseMove, false);
      container.addEventListener('mouseup', this.onDocumentMouseUp, false);
      container.addEventListener('mousewheel', this.onDocumentMouseWheel, false);

      container.addEventListener('touchstart', this.onDocumentTouchStart, false);
      container.addEventListener('touchmove', this.onDocumentTouchMove, false);
    },
    onDocumentMouseDown(event) {
      event.preventDefault();

      this.isUserInteracting = true;

      this.onPointerDownPointerX = event.clientX;
      this.onPointerDownPointerY = event.clientY;

      this.onPointerDownLon = this.lon;
      this.onPointerDownLat = this.lat;
    },

    onDocumentMouseMove(event) {
      if (this.isUserInteracting) {
        this.lon = (this.onPointerDownPointerX - event.clientX) * 0.1 + this.onPointerDownLon;
        this.lat = (event.clientY - this.onPointerDownPointerY) * 0.1 + this.onPointerDownLat;
        this.render();
      }
    },

    onDocumentMouseUp(event) {
      this.isUserInteracting = false;
      this.render();
    },

    onDocumentMouseWheel(event) {
      this.camera.fov -= event.wheelDeltaY * 0.05;
      this.camera.updateProjectionMatrix();
      event = event || window.event;
      if (event.stopPropagation) { // 这是取消冒泡
        event.stopPropagation();
      } else {
        event.cancelBubble = true;
      };
      if (event.preventDefault) { // 这是取消默认行为
        event.preventDefault();
      } else {
        event.returnValue = false;
      };
      this.render();
    },

    onDocumentTouchStart(event) {
      if (event.touches.length == 1) {
        event.preventDefault();

        this.onPointerDownPointerX = event.touches[0].pageX;
        this.onPointerDownPointerY = event.touches[0].pageY;

        this.onPointerDownLon = this.lon;
        this.onPointerDownLat = this.lat;
      }
    },

    onDocumentTouchMove(event) {
      if (event.touches.length == 1) {
        event.preventDefault();

        this.lon = (this.onPointerDownPointerX - event.touches[0].pageX) * 0.1 + this.onPointerDownLon;
        this.lat = (event.touches[0].pageY - this.onPointerDownPointerY) * 0.1 + this.onPointerDownLat;

        this.render();
      }
    },
    render() {
      this.lon += 0.15;

      this.lat = Math.max(-85, Math.min(85, this.lat));
      this.phi = THREE.Math.degToRad(90 - this.lat);
      this.theta = THREE.Math.degToRad(this.lon);
      this.camera.position.x = 100 * Math.sin(this.phi) * Math.cos(this.theta);
      this.camera.position.y = 100 * Math.cos(this.phi);
      this.camera.position.z = 100 * Math.sin(this.phi) * Math.sin(this.theta);

      this.camera.lookAt(this.scene.position);
      this.renderer.render(this.scene, this.camera);
    }
  },
};
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值