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

进一步学习

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

相关推荐
ROC_bird..2 分钟前
C++类和对象——第四关通关
开发语言·c++
白如意i5 分钟前
如何打包和分发 Python 应用程序
开发语言·python
only_Klein5 分钟前
python函数
开发语言·python
落雨无风8 分钟前
perl 给特定文件加上特定内容
开发语言·perl
落雨无风9 分钟前
perl替换文件中的特定内容
开发语言·perl
The_tuber_sadness13 分钟前
【Flutter】- go_router路由
javascript·flutter·golang
宋一诺3314 分钟前
12-Union联合类型注解
java·开发语言
安冬的码畜日常32 分钟前
【玩转 JS 函数式编程_014】4.1 JavaScript 纯函数的相关概念(下):纯函数的优势
开发语言·javascript·ecmascript·函数式编程·js·functional·原生js
影子落人间37 分钟前
JAVA使用SM2算法生成密钥对加密解密加签验签
java·开发语言·算法·安全
LIjin_100638 分钟前
pytorch resnet源码分析
开发语言·python·深度学习