超简单实现vr看房子、360全景图(附完整demo)

10,885 阅读6分钟

啥也不说,先上图和具体代码

背景

需要实现一个类似于贝壳和安居客vr看房的vr导航图,在研究了很多之后,发现像贝壳和安居客的vr看房其实是使用了图片算法,把拍摄的图片根据算法进行建模,这样子建模出来的vr效果更真实,也不会有拉伸效果,但技术难点太高,就放弃了。 之后调研了three.js,css原生实现,css-3d,pannellum,pano2vr等方案,最后是使用pannellum来实现360全景图

实现的效果如下

  • 全景图全方位浏览
  • 自定义热点
  • 跳转场景
  • 地图
  • 手机端vr效果展示
  • 。。。

线上demo 效果在这里 (温馨提示 手机预览效果更好哦)

几种实现方式对比

实现方式pannellumthree.jscss原生pano2vr
优点可扩展性强,github的issue活跃,使用方式简单功能强大纯css代码实现,简单可视化工具,上传图片就行,不用写代码
缺点全英文文档很难上手不好添加交互不好扩展

经过对比这些实现方式,最后是决定使用pannellum插件来实现vr 360全景图效果, 地址在这里,是全英文文档,但是使用翻译还是基本上可以看懂,文档有很多例子,可以跟着例子一步一步走,GitHub的issue很活跃,最近一个月作者都在进行回复

实现方式

1.实现一个全景图

实现一个全景图有两种方式

1.第一个是六个方位的图片拼成一个立方体,把视角放在立方体内部

2.第二个是使用一张全景图,贴在球形上,再把视角放在球体内部

具体的动画效果去网上自己搜,我这里直接上代码(引入cdn这些就不放在代码里了) 完整代码在最上方

          const viewer = pannellum.viewer("panorama", {
            // 共同的配置
            default: {
              firstScene: "first",
              orientationOnByDefault: false, // 是否开启vr效果 协议需要为https否则会报错
              autoLoad: true, // 自动加载
              autoRotate: -2, // 自动旋转
              autoRotateInactivityDelay: 1000, // 用户操作页面后,自动旋转延迟
              friction: 0.15, // 控制摩擦器 0.1 到 1 值越大停的越快 默认值0.15
              showZoomCtrl: false, // 是否显示缩放控件
              showFullscreenCtrl: true, // 是否显示全屏控件
              touchPanSpeedCoeffFactor: 1, // 触摸时平移速度 默认1
              yaw: 0, // 垂直方向左右旋转角度 正值向右 负值向左
              pitch: -60, // 水平方向左右旋转角度 正值向上 负值向下 仰视太大 导致图片拉伸
              minPitch: -60, // 最小pitch 默认-180
              maxPitch: 60, // 最大pitch 默认180
              roll: 0, // z轴 横着的
              hfov: 60, // 摄像机视角
              minHfov: 10, // 摄像机最小视角
              maxHfov: 60, // 摄像机最大视角
              escapeHTML: true, // HTML 将从配置字符串中转义,以帮助缓解可能的 DOM XSS 攻击。
              crossOrigin: "anonymous", // 使用的 CORS 请求类型,可以设置为 anonymous或use-credentials。默认为anonymous.
              sceneFadeDuration: 1000, // 切换场景时动画持续时间
              // compass: true, // 指南针
              // northOffset: 90, // 指南针角度
              // horizonRoll: 10, // 指定图像水平的俯仰/滚动
              // hotSpotDebug: true, // 打印移动时的yaw pitch roll
              preview: 'xxx' // 预览图片地址
            },
            // 场景相关配置
            scenes: {
              first: {
                type: "cubemap", // 全景图类型 可以是`equirectangular`、`cubemap`或 `multires`。默认为`equirectangular`,不同类型图片参数不同,可在官方文档查看
                cubeMap: [
                  //立方体全景图六张图
                  'xxx',
                  'xxx',
                  ...
                ],
              },
            },
      });

以上代码运行时将会展示一个vr、360全景图的效果 后面的代码都是在这个基础上添加的,我只贴出来需要加这个效果需要加的代码

2.自定义热点添加

    scenes: {
        first: {
                type: "cubemap", // 全景图类型
                cubeMap: [
                  //立方体全景图六张图
                ],
                hotSpots: [
                  {
                    yaw: -30,
                    pitch: -16,
                    // type有两种类型 'info' 或 'scene',设置'scene'时,设置sceneId会实现跳转, 设置为'info'时是正常的热点
                    type: "scene", 
                    // 当前热点跳转的页面
                    sceneId: "second",
                    // 自定义样式, 不设置是默认样式
                    cssClass: "point", 
                     // 放大缩小时热点是否一起变化
                    scale: true,
                  },
                  {
                    yaw: -6,
                    pitch: -26,
                    cssClass: "test",
                    clickHandlerFunc: clickTestBtn, // 设置热点自定义事件
                    scale: true,
                  },
                  {
                    yaw: 10,
                    pitch: 15,
                    roll: -10,
                    type: 'info',
                    text: '我是信息xxx'
                  },
            ],
        },
        second: {
            "type": "equirectangular", // 全景图类型
            "panorama": "" // 全景图片地址
        }
   }

3.添加地图或自定义组件

如果要添加地图或其他自定义组件,直接写成HTML元素将z-index设置高一点就可以了,可以把vr、360全景图看成一个背景,开发其他东西时正常开发即可,这也是使用这个插件来开发的原因,可扩展性很强。 下面分享一下我开发地图和vr控制器的思路

  • 使用HTML+CSS实现组件的结构和样式
  • 事件监听组件的各种事件
  • 通过pannellum.viewer返回的对象,使用其中的API和监听方法 下面展示的所有方法都在文档里面,这边简单列几个使用方法,其他的自己去文档看 监听pannellum加载,场景切换等
// 获取pannellum实例对象
const viewer = pannellum.viewer(...各种配置)
// load
viewer.load(e => {
    //全景图加载时触发
})
// scenechange
viewer.on('scenechange, e => {
    // 切换场景时触发,在load之前触发
    // e为切换场景的id
})

使用API实现添加热点,切换等

// 获取pannellum实例对象
const viewer = pannellum.viewer(...各种配置)
// 添加热点 hs 热点的配置 sceneId 添加到的场景
viewer.addHotSpot(hs, sceneId)
// 加载场景
viewer.loadScene(sceneId)
// 开启vr
viewer.startOrientation();
// 关闭vr
viewer.stopOrientation();

地图里面指示点,随着画面旋转效果

document.addEventListener("mousemove", () => {
    let deg = viewer.getYaw();
    // 获取旋转角度 赋值给知识点
});

开启vr后,如果要监听手机移动,可以使用window.addEventListener("devicemotion",function () {})来实现监听,但是前提是协议地址必须满足协议为https,或者域名为localhost,满足条件后才会有效,否则不会监听

总结

通过以上的文字,大概把pannellum(帕拉勒姆)的基础用法分享了一遍,其中还有很多API和配置项都没有使用,如果你需要某个效果,但是我这边没有分享,可以去文档查看,这边在总结一下遇到的几个坑

  • 对于 yaw pitch roll这三个位置参数,这边贴一个图供大家理解,其实自己去多尝试设置不同的值就能理解每个值代表的控制那个位置了

image.png

  • 如果要使用vr效果,协议必须为https才可以,否则会报错,因为devicemotion是只会在https协议下才会执行
  • 如果出现info提示图片could not be accessed,并且图片地址没有问题时,去检查图片服务器的跨域设置

结尾

对于pannellum的使用就分享到这里,在这边主要是自己做个记录,如果代码有问题的请在评论区指出,或有其它不理解的地方也请在评论区指出,觉得帮助到你了,点个赞!!!。