全景组件Pannellum解析与实践

简介

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工具,该工具需要安装PythonHugin,因为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文件:

pannellum.htm

该页面作为显示全景图的页面,可以嵌入到其他的页面的<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&amp;title=全景图" ></iframe>

其中panorama参数是需要显示的全景图片路径,这里还设置了title为“全景图”,显示效果就是上面的全景图效果,独立页面显示全景图就在页面后添加viewer:

pannellum.htm

由于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:

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)来显示不同清晰度的照片,示例图如下:

multires Test

示例图中可以看出根据缩放的层级来分别加载不同清晰度的图片,在使用中可以通过鼠标滚轮、点击“+”按钮、手机双指缩放等操作来改变缩放层级,在Pannellum里表现为改变Hfov(Horizontal field of view)参数,取值为50~120,默认值为100。

构建multi-resolution的全景图片方式和cubic方式相同,不同的是type为multires,并且需要改变json配置文件:


myltires.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的构造函数中添加。

添加HotSpots

标注信息的属性很简单,yaw和pitch分别表示标注点的坐标,type只有两种类型:info和scene,info类型的是直接在全景图上展示的标注,scene类型标明这个标注点指向另一个全景图,也可以说是另一个“场景”,后面要介绍的全景漫游就是使用的scene类型的标注。text里是该标注的提示文字,如果该标注是个可以点击的链接的话,还需要在后面添加上URL,指向链接的地址。

有趣的是虽然Pannellum官方示例只给出了文字标注和超链接标注两种,但是查看pannellum.js源码发现Hotspot还可以支持图片和video类型的标注,所以接下来就添加上图片类型和视频类型的标注和演示:

添加上额外的两种标注类型:


额外类型

视频演示,使用视频为网易云音乐下载的《止战之殇》MV

video类型

图片类型,如果图片过大则会超出屏幕:


图片类型

官方支持的两种类型:


超链接和文字标注

由上面的演示可以看出结合了H5的视频播放和图片显示,可以实现很酷炫的效果,并且演示的这些功能都是可以自己定制的,可以根据需要使用不同的内容。并且Pannellum的所有方框的样式都定义在../src/css/pannellum.css 文件里,想要修改标注的图标和提示信息的样式都可以直接修改CSS文件即可。如果想要让Pannellum支持更多的标注类型,比如格式化的文档,就需要修改pannellum.js的源代码,增加标注类型的判断,并手动设置标注内容的div。

HotSpot除了可以在初始化页面的时候作为json参数初始化全景页面,也可以调用Pannellum提供的API,在需要添加标注的时候动态添加,对应方法为addHotSpot()和removeHotSpot()值得一提的是如果需要实时地了解当前鼠标点击位置的坐标是多少,可以设置hotSpotDebug:true,该项设置会在实际拖动、点击全景图的时候在浏览器开发者工具的console栏里显示当前的yaw和pitch值,以及视角面对的yaw和pitch值:

设置hotSpotDebug


演示图

漫游

标注点可以用作不同场景之间的转换,谷歌地图和百度地图全景都能够从一个场景跳转到另一个场景,以此来达到在全景场景中虚拟旅行的目的。

在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的无私奉献。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容