VR全景分析.md 9.51 KB

VR 全景分析

最后更新: 2026-02-09 相关文件:

  • src/components/VRViewer/index.vue - VR 全景查看器组件
  • src/api/map.js - 地图数据 API(包含全景图 URL)

技术栈

全景查看器库

Photo Sphere Viewer - 360° 全景查看器

版本 用途
photo-sphere-viewer 4.8.1 全景查看器(旧版本,已弃用)
@photo-sphere-viewer/core 5.7.3 全景查看器核心(新版本)
@photo-sphere-viewer/markers-plugin 5.7.3 标记点插件
@photo-sphere-viewer/virtual-tour-plugin 5.7.3 虚拟漫游插件
@photo-sphere-viewer/gallery-plugin 5.7.3 图库插件
@photo-sphere-viewer/gyroscope-plugin 5.7.3 陀螺仪插件
@photo-sphere-viewer/stereo-plugin 5.7.3 立体插件(VR 眼镜)

⚠️ 注意: 项目中同时存在 4.8.1 和 5.7.3 两个版本,建议统一使用 5.x 版本。

核心功能

1. 全景图查看

功能:

  • ✅ 360° 全景浏览
  • ✅ 缩放控制
  • ✅ 自动旋转
  • ✅ 陀螺仪控制(移动设备)

初始化:

import { Viewer } from '@photo-sphere-viewer/core';

const viewer = new Viewer({
  container: document.querySelector('#viewer'),
  panorama: '/path/to/panorama.jpg',
  defaultZoomLvl: 0,
  fisheye: true,
  loadingTxt: '加载中...',
});

2. 标记点 (Markers)

插件: @photo-sphere-viewer/markers-plugin

功能:

  • ✅ 添加标记点
  • ✅ 标记点点击事件
  • ✅ 自定义标记点样式
  • ✅ 多边形标记点

使用示例:

import { MarkersPlugin } from '@photo-sphere-viewer/markers-plugin';

const markersPlugin = new MarkersPlugin();

viewer.setPlugin(markersPlugin);

// 添加标记点
viewer.addMarker({
  id: 'marker1',
  position: { yaw: 0, pitch: 0 },
  html: '<div class="marker">标记点</div>',
  scale: [1, 1],
});

// 监听标记点点击
markersPlugin.addEventListener('select-marker', ({ marker }) => {
  console.log('点击标记点:', marker.id);
});

3. 虚拟漫游 (Virtual Tour)

插件: @photo-sphere-viewer/virtual-tour-plugin

功能:

  • ✅ 多场景切换
  • ✅ 场景之间的链接
  • ✅ 箭头指示器
  • ✅ 自动路径播放

使用示例:

import { VirtualTourPlugin } from '@photo-sphere-viewer/virtual-tour-plugin';

const virtualTour = new VirtualTourPlugin();

viewer.setPlugin(virtualTour);

// 设置节点
virtualTour.setNodes([
  {
    id: '1',
    panorama: '/path/to/panorama1.jpg',
    links: [
      {
        name: '场景 2',
        nodeId: '2',
        position: { yaw: -300, pitch: 0 },
        arrowStyle: {
          color: '#AEEEEE',
          hoverColor: 0xaa5500,
          outlineColor: 0x000000,
          scale: [1, 1],
        }
      },
    ],
    markers: [...],
  },
  {
    id: '2',
    panorama: '/path/to/panorama2.jpg',
    links: [...],
    markers: [...],
  },
]);

// 切换场景
virtualTour.setCurrentNode('2');

4. 图库 (Gallery)

插件: @photo-sphere-viewer/gallery-plugin

功能:

  • ✅ 全景图列表
  • ✅ 缩略图导航
  • ✅ 自动切换

使用示例:

import { GalleryPlugin } from '@photo-sphere-viewer/gallery-plugin';

const gallery = new GalleryPlugin({
  thumbnailSize: {
    width: 100,
    height: 100,
  },
});

viewer.setPlugin(gallery);

// 设置图库
gallery.setItems([
  {
    id: '1',
    panorama: '/path/to/panorama1.jpg',
    name: '场景 1',
    thumbnail: '/path/to/thumb1.jpg',
  },
  {
    id: '2',
    panorama: '/path/to/panorama2.jpg',
    name: '场景 2',
    thumbnail: '/path/to/thumb2.jpg',
  },
]);

5. 陀螺仪 (Gyroscope)

插件: @photo-sphere-viewer/gyroscope-plugin

功能:

  • ✅ 设备方向控制
  • ✅ 移动设备支持
  • ✅ VR 眼镜模式

使用示例:

import { GyroscopePlugin } from '@photo-sphere-viewer/gyroscope-plugin';

const gyroscope = new GyroscopePlugin();

viewer.setPlugin(gyroscope);

// 启用陀螺仪
gyroscope.toggle();

6. 立体模式 (Stereo)

插件: @photo-sphere-viewer/stereo-plugin

功能:

  • ✅ VR 眼镜模式
  • ✅ 立体视图

使用示例:

import { StereoPlugin } from '@photo-sphere-viewer/stereo-plugin';

const stereo = new StereoPlugin();

viewer.setPlugin(stereo);

// 启用立体模式
stereo.toggle();

组件使用

VRViewer 组件

路径: src/components/VRViewer/index.vue

Props:

{
  show: Boolean  // 控制显示/隐藏
}

使用示例:

<template>
  <VRViewer
    v-model:show="showVR"
    :panorama="panoramaUrl"
    :markers="markers"
    @marker-click="handleMarkerClick"
  />
</template>

<script setup>
import VRViewer from '@components/VRViewer/index.vue';
import { ref } from 'vue';

const showVR = ref(false);
const panoramaUrl = ref('/vr/panorama.jpg');
const markers = ref([
  {
    id: 'marker1',
    position: { yaw: 0, pitch: 0 },
    html: '<div class="marker">标记点</div>',
  }
]);

const handleMarkerClick = (marker) => {
  console.log('点击标记点:', marker);
};

// 打开 VR
const openVR = () => {
  showVR.value = true;
};
</script>

全景图格式

支持的格式

  • ✅ JPEG (推荐)
  • ✅ PNG
  • ✅ WebP (推荐,体积更小)

拍摄要求

等距柱状投影 (Equirectangular Projection):

  • 宽高比: 2:1
  • 分辨率: 至少 4096 x 2048
  • 格式: 等距柱状投影

文件大小建议: | 分辨率 | 文件大小 | |--------|---------| | 2048 x 1024 | < 2 MB | | 4096 x 2048 | 2-5 MB | | 8192 x 4096 | 5-15 MB |

图片优化

压缩建议:

  • JPEG 质量: 80-90%
  • WebP 质量: 80-90%
  • 使用渐进式 JPEG

工具推荐:

  • Adobe Lightroom
  • Photoshop
  • 在线压缩工具

性能优化

1. 懒加载

// 仅在需要时加载全景图
const loadPanorama = async (url) => {
  const viewer = new Viewer({
    container: document.querySelector('#viewer'),
    panorama: url,
    loadingTxt: '加载中...',
  });

  await viewer.ready();

  return viewer;
};

2. 缩略图

// 先加载缩略图,再加载高清图
const viewer = new Viewer({
  container: document.querySelector('#viewer'),
  panorama: thumbnailUrl,  // 缩略图
  requestFullscreen: true,
});

// 后台加载高清图
loadFullPanorama(fullUrl).then((fullUrl) => {
  viewer.setPanorama(fullUrl);
});

3. 缓存策略

// 缓存已加载的全景图
const panoramaCache = new Map();

export const getCachedPanorama = (url) => {
  if (panoramaCache.has(url)) {
    return Promise.resolve(panoramaCache.get(url));
  }

  return new Promise((resolve) => {
    const img = new Image();
    img.onload = () => {
      panoramaCache.set(url, url);
      resolve(url);
    };
    img.src = url;
  });
};

4. 资源释放

// 组件卸载时释放资源
onUnmounted(() => {
  if (viewer.value) {
    viewer.value.destroy();
    viewer.value = null;
  }
});

已知问题

1. 版本冲突

问题: 同时使用 4.x 和 5.x 版本

解决方案: 统一使用 5.x 版本

// ❌ 错误
import { Viewer } from 'photo-sphere-viewer'; // 4.x
import { Viewer } from '@photo-sphere-viewer/core'; // 5.x

// ✅ 正确
import { Viewer } from '@photo-sphere-viewer/core'; // 仅使用 5.x

2. jQuery 依赖

问题: 组件中使用 jQuery

解决方案: 逐步迁移到 Vue 原生 API

// ❌ 错误
$('.psv-zoom-button').css('display', '');

// ✅ 正确
document.querySelector('.psv-zoom-button').style.display = '';

3. 内存泄漏

问题: 未正确销毁查看器实例

解决方案: 组件卸载时销毁

onUnmounted(() => {
  if (viewer) {
    viewer.destroy();
  }
});

4. 移动端性能

问题: 高分辨率全景图加载慢

解决方案:

  • 使用 WebP 格式
  • 降低分辨率
  • 使用缩略图预加载

最佳实践

1. 组件使用

<!-- ✅ 推荐:使用 v-model -->
<VRViewer v-model:show="showVR" />

<!-- ❌ 不推荐:手动控制 -->
<VRViewer :show="showVR" @close="showVR = false" />

2. 全景图路径

// ✅ 推荐:使用别名
const panoramaUrl = ref('@images/vr/panorama.jpg');

// ❌ 不推荐:使用相对路径
const panoramaUrl = ref('../../images/vr/panorama.jpg');

3. 标记点定义

// ✅ 推荐:使用配置对象
const markerConfig = {
  id: 'marker1',
  position: { yaw: 0, pitch: 0 },
  html: '<div class="marker">标记点</div>',
};

// ❌ 不推荐:内联定义
viewer.addMarker({
  id: 'marker1',
  position: { yaw: 0, pitch: 0 },
  html: '<div class="marker">标记点</div>',
});

调试技巧

1. 查看查看器状态

// 在控制台查看查看器状态
console.log('查看器状态:', {
  position: viewer.getPosition(),
  zoom: viewer.getZoomLevel(),
  size: viewer.getSize(),
});

2. 监听事件

// 监听所有事件
viewer.addEventListener('ready', () => console.log('就绪'));
viewer.addEventListener('position-updated', (e) => console.log('位置更新:', e.position));
viewer.addEventListener('zoom-updated', (e) => console.log('缩放更新:', e.zoomLevel));

3. 手动控制

// 手动旋转
viewer.animate({
  yaw: 180,
  pitch: 0,
  zoom: 0,
  speed: 1000,
});

// 手动缩放
viewer.zoom(1);

参考文档