简介
Pannellum是一款基于WebGL和JavaScript的轻量级开源全景组件,能用作在网页端和移动端展示全景图片或者是全景视频。GitHub地址,官网地址。官方图演示如下:
Pannellum特性:
轻量、体积小(15kb)
不同投影类型全景图片
全景标注(Hotspot)
全景漫游(Tour)
全景视频(video)
多清晰度图片(full-resolution)
图片方向定位(指南针)
添加图片场景、作者信息。
Pannellum对于各个浏览器的兼容性如下:
完全兼容:Firefox 10+ ,Chrome 15+,Safari 8+,Internet Explorer 11+,Edge。
不完全兼容(无法使用全屏功能):Firefox 4+,Chrome 9+。
不兼容:Internet Explorer 10 及其早期版本。
使用
准备图片
要使用Pannellum来展示全景图片,首先需要有用来展示的全景图片,现在有很多网站提供免费的全景图片下载,读者可自行百度下载合成好的全景图片或者也可以使用Hugin等软件合成自己的全景图片。并且Pannellum不仅可以展示单张合成好的图片,也可以将不同方向的若干张非全景图片直接展示为全景图片,笔者这里准备了两种图片:
合成好的全景图片:
由合成好的全景图拆分出的不同方向的鱼眼图片:
这里使用已合成好的图片来拆分成不同方向的图片,获取拆分全景图的方法有两种:
1、读者可以直接使用广角鱼眼镜头分别拍摄六个方向(前后左右上下)的图片来作为源图片。拍摄广角图片的目的是为了拍摄后将各个图片进行“缝合”的时候能够找到更多的缝合点,如下图
2、可以直接使用Pannellum提供的generate.py工具,该工具需要安装Python和Hugin,因为generate.py工具使用的nona程序是Hugin的一部分,并且还需要将hugin的bin路径添加进系统环境变量中,然后运行
python generate.py pano_image.jpg
就可以生成一个multires目录,里面存放着拆分后的图片。pano_image.jpg是需要拆分的全景图
3、因为方法2里面的工具也是依赖Hugin的nona程序,所以也可以直接在命令行里操作nona程序将全景图进行拆分而不需要Python。这样还能设置拆分后的图片大小、宽高、像素等额外的参数,nona的特性可以看官方介绍,使用API可以参考这里。
下载组件
在Pannellum的GitHub上直接clone项目或者下载zip压缩包后导入web项目,就可以使用了。
doc 文件夹里有Pannellum组件的API说明以及全景图片坐标系转换的具体数学公式。
examples 文件夹里是Pannellum组件的不同使用实例
src 文件夹里有Pannellum的源文件
utils 里有各种帮助构建使用的工具,包括刚才提到的generate.py,生成的multires文件夹也会在utils下。
全景图片展示
首先需要一个展示全景图片的html页面pannellum.htm,引入pannellum相关的js文件和css文件:
该页面作为显示全景图的页面,可以嵌入到其他的页面的<iframe>标签中,也可以作为一个显示全景图的独立页面。
Pannellum支持四种处理全景图片的方式:
equirectangular,partial,cubic,multi-resolution
其中第一和第二个是针对单张全景图片的处理方式,第三和第四是针对拆分全景图片的处理方式,接下来分别进行说明:
1、equirectangular:圆柱投影,百度百科解释如下:
假想一个圆柱与地球相切或相割,以圆柱面作为投影面,将球面上的经纬线投影到圆柱面上,在正常位置的圆柱投影中,圆柱面展平后纬线为平行直线,经线也是平行直线,而且与纬线直交。
圆柱投影的变形仅随纬度而变化,即在同纬线上各点的变形相同而与经度无关。
简单来说就是把一个球体的表面使用圆柱体投影到圆柱体的侧面上,这个过程的逆过程就变成了一张全景图投影到球体上,这样就能够实现全方位的全景体验,这也使得全景图跟普通的"大图"不一样,全景图还需要包含上下两个方向的图像信息,具体表现就是全景图有“顶”和“底”的,如下图:
而如果只是使用普通的大图,就会出现图像的边缘无法重合以及顶部底部没有图像的问题:
关于圆柱体投影的更多资料读者可以参考维基百科和Pannellum的圆柱体投影算法。
使用方法:在页面中嵌入
<iframe width="480" height="390" allowfullscreen style="border-style:none" src="../src/standalone/pannellum.htm?panorama=../../examples/school.jpg&title=全景图" ></iframe>
其中panorama参数是需要显示的全景图片路径,这里还设置了title为“全景图”,显示效果就是上面的全景图效果,独立页面显示全景图就在页面后添加viewer:
由于Pannellum使用闭包的方式向外提供接口,因此就可以将pannellum作为一个类来操作,viewer(arg1,arg2)作为构造函数来构造全景显示器,arg1就是页面中用于展示全景图的<div>,arg2是一系列参数的集合,定义了全景的各项显示参数,上图定义了在id为‘container’的<div>中显示school全景图,全景图投影类型为圆柱体投影(equirectangular)。
2、partial 局部圆柱体投影
在理解partial投影之前,需要知道Pannellum的投影坐标系,坐标系很简单,一图以概括:
圆圈中的直线代表视角方向,水平方向用yaw值表示,取值为180度到-180度,竖直方向用pitch值表示,取值为90度到-90度,yaw和pitch两个值共同表示整个投影坐标系。在实际使用中可以通过setYaw(),getYaw(),setPitch(),getPitch()等方法将视角移动到指定的坐标处,也可以获取当前视角对应的坐标位置。接下来需要注意的是Pannellum提供了setPitchBounds(number[])方法和setYawBounds(number[])方法,这两个方法的作用是限制视角的移动范围,例如如果想将视角限制在水平yaw值0~140的范围内,设置如下:
同理在竖直方向上只需要setPitchBounds就可以了。
Pannellum除了可以限制视角的移动范围,还可以限制全景图的覆盖范围,通过参数haov、vaov、vOffset来设置,haov(horizontal angle of view)表示水平展示的图片的角度大小,vaov(vertical angle of view)表示竖直方向的角度大小,vOffset表示竖直方向的偏移度,上图以助理解:
可以看到跟setXXBounds方式不同,该方法直接设置了全景图片整个所占的面积和角度,vOffset设置为30,整个图像向上偏移了30度。需要注意的是只能在构造方法中设置这三个参数,这三个参数只对“equirectangular”类型的图片有效,且设置后无法改变。这样的投影方式就是partial投影。可见圆柱体投影就是partial投影设置haov=360,vaov=180,vOffset=0的结果。
3、cubic 立方体投影
立方体投影是针对拆分全景图片的投影方式,即将整个投影空间看作一个立方体,具有前后左右上下6个面,分别将各个拆分全景图片渲染在对应的各个面上,在感官上也能够达到柱面投影的效果。在使用cubic投影方式处理全景图片的时候需要配置json文件,在json中配置图片路径、标题、作者、标注点等信息,首先根据上文的拆分后的全景图配置json文件:
然后在创建全景图的时候将配置文件设置为cube.json:
嵌入页面:
<iframe width="480" height="390" allowfullscreen style="border-style:none;" src="../src/standalone/pannellum.htm?config=../../examples/cube.json"></iframe>
独立页面:
注意:使用的各个面的图片必须为正方形且大小相等!且需要按照特定的顺序传入图片。
Pannellum传入图片的顺序是:前、右、后、左、上、下。如果不按照顺序传入相对应面的图片就会出现错位的情况。设置好后的效果如下:
关于CubeMap的更多资料读者感兴趣的话可以查看维基百科。
从上图可以看到使用cubic和使用equirectangular的方式效果差不多,cubic的投影坐标系跟equirectangular坐标系是一致的,也可以通过设置视角坐标来操作,但是cubic要求图片的顺序、大小保证一致以及对各个图片之间的重合度要求更高,使用起来更加复杂,那么既然效果差不多为什么还要使用这种方式呢?
首先,该方式有利于粗加工或未加工的图片展示为全景图片,因为cubic方式可以直接采用源图片来进行投影拼接成全景图,所以只要能够在用相机拍摄图片的时候固定好各个方向镜头的角度,拍摄得到的图片只需要经过粗加工(例如裁切成正方形)就可以直接用来展示,免去了再将所有图片合成为一张大的全景图的过程。
其次,cubic方式比equirectangular方式更加灵活,如果全景图的某一个区域出现了“坏点”,“黑洞”,或者图像撕裂等问题,equirectangular的全景图就需要重新合成一张新的全景图,或者对照着圆柱体投影来修图,过程很麻烦,而对于cubic方式来说就只需要替换掉对应面上的图片即可。
cubic的另一个作用就是能够提供多清晰度全景图片,这就是Pannellum的第四种方式:multi-resolution。
4、multi-resolution
顾名思义,就是可以提供不同清晰度的全景图片,Pannellum能够根据缩放的程度(改变Hfov)来显示不同清晰度的照片,示例图如下:
示例图中可以看出根据缩放的层级来分别加载不同清晰度的图片,在使用中可以通过鼠标滚轮、点击“+”按钮、手机双指缩放等操作来改变缩放层级,在Pannellum里表现为改变Hfov(Horizontal field of view)参数,取值为50~120,默认值为100。
构建multi-resolution的全景图片方式和cubic方式相同,不同的是type为multires,并且需要改变json配置文件:
在“multires”节点中,将每一个最小的图片看做瓦片(tile),立方体的每一个面都是由若干个瓦片组成,接下来分别说明multires节点的参数。
basePath设置一个公用路径,后面的path只需要写相对于basePath的相对路径即可,这里需要注意的是path的值,path的值是一个格式化的字符串,其中 %l 代表缩放等级,%s 代表立方体的面 ,%x 和 %y 代表了该瓦片在这一个面中的位置,其文件结构如图:
当缩放等级为1时,就会在“1”文件夹中将各个面对应的图片投影到对应的立方体面上(对应%s),然后根据每一个瓦片的坐标来确定瓦片在每一个面中的位置,这里由于坐标是(0,0),且每一面只有一个瓦片,所以是铺满整面,多个瓦片的效果可以看上面的实例。
fallbackPath的作用就是当某些浏览器不支持multires功能的时候能够回退到fallbackPath指定的文件夹下加载默认的全景图片。
extension指定瓦片的图片格式,不需要加前面的 “.” 符号。
tileResolution指定瓦片的像素,单位为px。
maxLevel指定最多支持几个缩放等级。
cubeResolution指定立方体面的总像素,单位为px。
如此就能够根据不同的缩放等级来显示不同的清晰度的图像,这样的好处是如果要加载一张4k的全景图,不需要一次性就将整个全景图都加载进来,可以先加载一个缩放等级低的全景,然后当使用者进行缩放查看细节的时候再加载清晰度更高的图像,这样就可以明显提高加载速度,避免因为图片过大使得加载时间过长和不必要的流量浪费。不足之处就是需要为一张全景图额外准备不同清晰度的图片,增加了图片处理的工作量,也增加了图片存储的空间占用。
全景标注与漫游
Pannellum不仅是作为全景图片查看器,也可以与使用者产生一定的交互,使用者可以在全景图片上添加标注(HotSpot)和在多个全景场景中漫游(Tour)。
标注
使用标注功能需要在json文件中配置HotSpot,也可以在viewer的构造函数中添加。
标注信息的属性很简单,yaw和pitch分别表示标注点的坐标,type只有两种类型:info和scene,info类型的是直接在全景图上展示的标注,scene类型标明这个标注点指向另一个全景图,也可以说是另一个“场景”,后面要介绍的全景漫游就是使用的scene类型的标注。text里是该标注的提示文字,如果该标注是个可以点击的链接的话,还需要在后面添加上URL,指向链接的地址。
有趣的是虽然Pannellum官方示例只给出了文字标注和超链接标注两种,但是查看pannellum.js源码发现Hotspot还可以支持图片和video类型的标注,所以接下来就添加上图片类型和视频类型的标注和演示:
添加上额外的两种标注类型:
视频演示,使用视频为网易云音乐下载的《止战之殇》MV
图片类型,如果图片过大则会超出屏幕:
官方支持的两种类型:
由上面的演示可以看出结合了H5的视频播放和图片显示,可以实现很酷炫的效果,并且演示的这些功能都是可以自己定制的,可以根据需要使用不同的内容。并且Pannellum的所有方框的样式都定义在../src/css/pannellum.css 文件里,想要修改标注的图标和提示信息的样式都可以直接修改CSS文件即可。如果想要让Pannellum支持更多的标注类型,比如格式化的文档,就需要修改pannellum.js的源代码,增加标注类型的判断,并手动设置标注内容的div。
HotSpot除了可以在初始化页面的时候作为json参数初始化全景页面,也可以调用Pannellum提供的API,在需要添加标注的时候动态添加,对应方法为addHotSpot()和removeHotSpot()值得一提的是如果需要实时地了解当前鼠标点击位置的坐标是多少,可以设置hotSpotDebug:true,该项设置会在实际拖动、点击全景图的时候在浏览器开发者工具的console栏里显示当前的yaw和pitch值,以及视角面对的yaw和pitch值:
漫游
标注点可以用作不同场景之间的转换,谷歌地图和百度地图全景都能够从一个场景跳转到另一个场景,以此来达到在全景场景中虚拟旅行的目的。
在Pannellum中要实现场景的转换同样只需要修改json配置文件:
{"default":{
"author":"Matthew Petroff",
"firstScene":"firstScene",
"sceneFadeDuration":2000
},
"scenes":{
"firstScene":{
"title":"第一个场景",
"type":"cubemap",
"cubeMap":[
"./example_front.jpg","./example_right.jpg",
"./example_behind.jpg","./example_left.jpg",
"./example_up.jpg", "./example_down.jpg"],
"hotSpots":[{
"pitch":-12, "yaw":170,"type":"scene",
"sceneId":"secondScene",
"text":"点击前往第二个场景."}]
},
"secondScene":{
"title":"第二个场景",
"panorama":"./examplepano.jpg",
"hotSpots":[{"pitch":0,"yaw":100,
"type":"scene",
"text":"前往第一个场景",
"sceneId":"firstScene"}]
}
}
}
在该json中管理所有的场景,每一个场景对应一张全景图,这个全景图可以是四种图片展示方式的任意一种,每一个场景也有自己的sceneId,在default中配置所有场景通用的属性,例如作者、初始场景、淡入淡出时间,在scenes中配置每一个场景的具体参数。实际演示效果如下:
通过在不同场景中移动来达到虚漫游体验,由于标注的形状和图标以及边缘的控制按钮都可以自定义,据此仿造百度街景的形式做出前后移动的效果应该也没问题了。
结语
通过上文对Pannellum的全面解析和实际演示,基本上将Pannellum组件的功能都介绍了一遍,当然还有一些其他没有介绍到的功能,比如 指南针、全景方位、全景视频、动态equirectangular、预览图等,读者可自行了解Pannellum关于这些方面的使用。Pannellum作为一个轻量级的全景图片查看器(Viewer),基本上满足了日常使用全景图的需求,当然如果想要能够具有更多的个性化的功能就需要对Pannellum进行扩展和补充,总的来说Pannellum是一款很优秀的全景组件,感谢其作者Matthew Petroff的无私奉献。