实战篇:(四)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 和创建互动场景有所帮助。

进一步学习

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

相关推荐
樱花落木兰6 分钟前
分布式登录实战:Session 会话共享改造,Redis 存储用户登录状态
java·javascript·数据库·redis·分布式·缓存
wuyk5558 分钟前
Python 网络爬虫入门到实战 第 04 章:请求头、UA 伪装、超时、异常处理、基础反爬绕过
开发语言·爬虫·python
流形填表13 分钟前
题库去重实战:基于题干指纹的重复题清理
开发语言·c#
\光辉岁月/16 分钟前
3.java运算符
java·开发语言
知识分享小能手23 分钟前
C++ 学习教程,从入门到精通,string类和标准模板库 — 完整知识点详解(16)
开发语言·c++·学习
qq_4017004128 分钟前
Qt 炫酷曲线,图表,2D/3D开源库
开发语言·qt
liangshanbo121535 分钟前
面试题:线上 JavaScript 报错如何快速定位到源码?
开发语言·javascript·ecmascript
weixin_440730501 小时前
迭代器Iterator(列表生成器、可迭代的如何生成迭代器)
开发语言·python
朝朝辞暮i1 小时前
C++ 第 31C 课:Subscriber 到底是什么
开发语言·c++·算法
weixin_440730501 小时前
内置函数、json文本、pickle二进制
开发语言·python·json