实战篇:(四)Vue2 + Three.js 创建可交互的360度全景视图,可控制旋转、缩放完整代码

Vue2 + Three.js 创建可交互的360度全景视图,可控制旋转、缩放

引言

在现代网页开发中,三维图形技术已经成为提升用户体验的重要工具。本文将展示如何使用 Three.js 创建一个简单的可交互360度全景视图。通过这一项目,你将能够学习到基本的场景设置、相机控制以及用户交互的实现方式。

效果展示

环境准备

首先,你需要在项目中引入 Three.js。可以通过 npm 安装:

bash 复制代码
npm install three

确保你的项目结构中有一个名为 images 的文件夹,并放入一张全景图像(如 001.jpg),以便后续使用。

代码示例

下面是实现可交互360度全景视图的 Vue.js 组件代码:

js 复制代码
<template>
  <div class="c-width c-height" id="containerVr"></div>
</template>

<script>
import * as THREE from 'three';
import PANO0001 from './images/001.jpg';

export default {
  name: 'containerVr',
  data() {
      return {
          scene: null,
          camera: null,
          renderer: null,
      };
  },
  mounted() {
      this.init();
  },
  methods: {
      init(img) {
          img = img ? img : PANO0001;
          const containerVr = document.getElementById('containerVr');
          containerVr.innerHTML = '';
          
          // 初始化用户交互变量
          let isUserInteracting = false,
              onPointerDownMouseX = 0, onPointerDownMouseY = 0,
              lon = 0, onPointerDownLon = 0,
              lat = 0, onPointerDownLat = 0,
              phi = 0, theta = 0;

          // 创建相机对象
          const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
          
          // 创建场景对象
          const scene = new THREE.Scene();
          
          // 创建球体几何体,表示全景图的表面
          const geometry = new THREE.SphereGeometry(500, 60, 40);
          geometry.scale(-1, 1, 1);
          
          // 加载并设置全景图纹理
          const texture = new THREE.TextureLoader().load(img);
          texture.colorSpace = THREE.SRGBColorSpace;
          const material = new THREE.MeshBasicMaterial({ map: texture });
          
          // 创建网格对象,将几何体和材质结合
          const mesh = new THREE.Mesh(geometry, material);
          scene.add(mesh);
          
          // 创建渲染器并设置参数
          const renderer = new THREE.WebGLRenderer();
          renderer.setSize(window.innerWidth, window.innerHeight);
          renderer.setPixelRatio(window.devicePixelRatio);
          
          // 将渲染器的DOM元素添加到容器中
          containerVr.appendChild(renderer.domElement);
          containerVr.style.touchAction = 'none';
          
          // 添加事件监听器以处理用户交互
          containerVr.addEventListener('pointerdown', onPointerDown);
          document.addEventListener('wheel', onDocumentMouseWheel);
          
          // 窗口大小调整事件
          window.addEventListener('resize', onWindowResize);
          function onWindowResize() {
              camera.aspect = window.innerWidth / window.innerHeight;
              camera.updateProjectionMatrix();
              renderer.setSize(window.innerWidth, window.innerHeight);
          }

          // Pointer Down事件处理
          function onPointerDown(event) {
              if (event.isPrimary === false) return;
              isUserInteracting = true;
              onPointerDownMouseX = event.clientX;
              onPointerDownMouseY = event.clientY;
              onPointerDownLon = lon;
              onPointerDownLat = lat;
              document.addEventListener('pointermove', onPointerMove);
              document.addEventListener('pointerup', onPointerUp);
          }

          // Pointer Move事件处理
          function onPointerMove(event) {
              if (event.isPrimary === false) return;
              lon = (onPointerDownMouseX - event.clientX) * 0.1 + onPointerDownLon; 
              lat = (event.clientY - onPointerDownMouseY) * 0.1 + onPointerDownLat;
          }

          // Pointer Up事件处理
          function onPointerUp() {
              if (event.isPrimary === false) return;
              isUserInteracting = false;
              document.removeEventListener('pointermove', onPointerMove);
              document.removeEventListener('pointerup', onPointerUp);
          }

          // 滚轮事件处理
          function onDocumentMouseWheel(event) {
              if (event.toElement.getAttribute('data-engine') && event.toElement.getAttribute('data-engine').indexOf('three.js') > -1) {
                  const fov = camera.fov + event.deltaY * 0.05; 
                  camera.fov = THREE.MathUtils.clamp(fov, 10, 75); 
                  camera.updateProjectionMatrix(); 
              }
          }

          // 动画循环
          function animate() {
              requestAnimationFrame(animate);
              update();
          }

          // 更新函数,处理相机位置和渲染
          function update() {
              if (isUserInteracting === false) {
                  lon += 0.02; 
              }
              lat = Math.max(-85, Math.min(85, lat));
              phi = THREE.MathUtils.degToRad(90 - lat);
              theta = THREE.MathUtils.degToRad(lon);
              const x = 500 * Math.sin(phi) * Math.cos(theta);
              const y = 500 * Math.cos(phi);
              const z = 500 * Math.sin(phi) * Math.sin(theta);
              camera.lookAt(x, y, z); 
              renderer.render(scene, camera); 
          }
          animate(); 
      },
      // 设置图像的方法
      setImg(url) {
          let loader = new THREE.TextureLoader(); 
          let texture = loader.load(url); 
          let material = new THREE.MeshBasicMaterial({
              map: texture, 
              side: THREE.DoubleSide 
          });
          return material; 
      },
  }
}
</script>

<style scoped>
#containerVr {
  width: 100% !important; 
  flex: 1 !important; 
}
#containerVr >>> canvas {
  max-width: 100%; 
  max-height: 100%; 
}
</style>

代码解析

  • 组件结构 :该组件使用 Vue.js 的 <template><script><style> 标签组织代码。
  • 初始化方法 :在 mounted 钩子中调用 init 方法,初始化 Three.js 的场景、相机和渲染器。
  • 用户交互:实现了鼠标按下、移动和滚动事件,用户可以通过拖动鼠标来旋转视图。
  • 自适应窗口:通过监听窗口大小变化事件,动态更新相机和渲染器的尺寸。

总结

通过本文,你可以学习如何使用 Three.js 创建一个基础的360度全景视图。这种技术可以广泛应用于虚拟现实、在线展示以及游戏开发等多个领域。希望这篇文章对你理解 Three.js 和创建互动场景有所帮助。

进一步学习

通过这种方式,读者不仅可以理解代码的具体实现,还能了解到如何在实际项目中应用这些技术。希望这个结构能帮助你更好地撰写博客!如果你有其他想法或需要进一步的帮助,请告诉我。

相关推荐
每天写点bug10 分钟前
【go每日一题】:并发任务调度器
开发语言·后端·golang
一个不秃头的 程序员12 分钟前
代码加入SFTP Go ---(小白篇5)
开发语言·后端·golang
数据小爬虫@21 分钟前
Python爬虫抓取数据,有哪些常见的问题?
开发语言·爬虫·python
2401_8570262324 分钟前
依托 SSM 与 Vue 的电脑测评系统:展现电脑真实实力
前端·javascript·vue.js
2401_8576100327 分钟前
解析基于 SSM 框架 Vue 电脑测评系统:把握电脑测评精髓
前端·javascript·vue.js
烂不烂问厨房28 分钟前
前端项目发布后打开报错Uncaught SyntaxError: Unexpected token ‘<‘ (at chunk-vendors)
前端·javascript·vue.js·前端打包发布
总爱写点小BUG28 分钟前
可搜索的下拉选择框:filterable属性详解
前端·javascript·vue.js
程序媛_MISS_zhang_011030 分钟前
el-table中合并垂直方向的单元格
前端·javascript·vue.js
逊嘘35 分钟前
【Java数据结构】ArrayList相关的算法
java·开发语言
基哥的奋斗历程1 小时前
初识Go语言
开发语言·后端·golang