本文转自凹凸实验室:https://aotu.io/notes/2016/08... css
3D 全景并非什么新鲜事物了,但之前咱们在 Web 上看到的 3D 全景通常是经过 Flash 实现的。若咱们能将 CSS3 Transform
的相关知识运用得当,也是能实现相似的效果。换句话说,3D 全景其实就是 CSS3 3D 的应用场景之一。html
在实现 CSS3 3D 全景以前,咱们先理清部分 CSS3 Transform 相关的属性:git
下面咱们对上述的一些点进行更深刻的分析:github
perspective
,该属性指定了“眼睛”与元素的 perspective-origin
(默认值是 50% 50% 0
)点的距离。那么问题来了:“当咱们以 px
做为衡量单位时,它的实际距离该如何量化呢?” perspective
数值的值为 1920px
时,应用了 CSS3 3D Transform 的子元素的立体效果就至关于咱们在距离一个屏幕宽度(1920px)的屏幕前观看该元素时的真实效果。尽管如此,目前笔者也不知道如何准确地为元素设置一个合适的 perspective
值,只能猜想大概值后进行调整,以达到满意的呈现效果。
根据 类似三角形 的性质可计算出被前移的元素最终在屏幕上显示的实际大小 浏览器
另外,关于 perspective
还有另一个重要的点是:由于 perspective-origin
属性的默认值是 50% 50% 0
,因此对哪一个元素应用 perspective
属性,就决定了“眼睛”的位置(即咱们的“眼睛”是在哪一个角度看物体)。通常来讲,当咱们须要正视物体时,就会将该属性设置在与该元素中心重合的某一祖先元素上。app
再另外,若是说:“如何让一个元素(的背面)不可见?”,你可能会回答 backface-visibility:hidden;
。其实,对于在“眼睛”背后的元素(以元素的 transform-origin
为参考点),即元素的 Z
轴坐标值大于 perspective
的值时,浏览器是不会将其渲染出来的。函数
transform-style
,该属性指定了其子元素是处于 3D 场景仍是 2D 场景。对于 2D 场景,元素的先后位置是按照平时的渲染方式(即若在普通文档流中,同层级元素是按照代码中元素的前后编写顺序,后面的元素会遮住在其前面的元素);对于 3D 场景,元素的先后位置则按照真实世界的规则排序(即靠近“眼睛”的元素,会遮住离“眼睛”远的元素)。另外,因为 transform-style
属性是非继承的,对于中间节点须要显式设定。工具
transform
属性:下图整理了 rotate3d、translate3d 的变换方向: 须要注意的是:transform 中的变换属性的顺序是有关系的,如 translateX(10px) rotate(30deg) 与 rotate(30deg) translateX(10px) 是不等价的。字体
另外,须要注意的是 scale 中若是有负值,则该方向会产生 180 度的翻转;动画
再另外,部分 transform 效果会致使元素(字体)模糊,如 translate 的数值存在小数、经过 translateZ 或 scale 放大元素等等。每一个浏览器都有其不一样的表现。
上面理清了一些 CSS Transform 相关的知识点,下面就讲讲如何实现 CSS 3D 全景 :
想象一下,当咱们站在十字路口中间,身体旋转 360°,这个过程当中所看到的画面就是一幅以你为中心的全景图了。其实,当焦距不变时,咱们就等同于站在一个圆柱体的中心。
可是,虚拟世界与现实世界的最大不一样是:没有东西是连续的,即全部东西都是离散的。例如,你没法在屏幕上显示一个完美的圆。你只能以一个正多边形表示圆:边越多,圆就越“完美”。
同理,在三维空间中,每一个 3D 模型都是一个多面体(即 3D 模型由不可弯曲的平面组成)。当咱们讨论一个自己就是多面体(如立方体)的模型时并不足觉得奇,但咱们想展现其它模型时,如球体,就须要记住这个原理了。
淘宝造物节的活动页 就是 CSS 3D 全景的一个很赞的页面,它将全景图分割成 20 等份,相邻的元素构成的夹角 18°(360/20,相邻两侧面相对于棱柱中心所构成的夹角)。须要注意的是:咱们要确保每一个元素的正面是指向棱柱中心的。因此要计算好每等份的旋转角度值后,再将元素向外(即 Z 轴方向)平移 r
px。对于立方体的 r
就是 边长/2
,而对于其它更复杂的正多面体呢?
举例:对于正九棱柱,每一个元素的宽为 210px
,对应的角度为 40°
,即以下图:
图片来自:https://desandro.github.io/3d...
正九棱柱的俯视图
计算过程
由此可获得一个公用函数,只需传入含有元素的宽度和元素数量的对象,便可获得 r
值:
function calTranslateZ(opts) { return Math.round(opts.width / (2 * Math.tan(Math.PI / opts.number))) } calTranlateZ({ width: 210, number: 9 }); // 288
俯视时所看到的元素外移动画
另外,为了让下文易于理解,咱们约定 HTML 的结构:
#view(perspective:1000px) #stage(transform-style:preserve-3d) #cube(transform-style:preserve-3d) .div(width:600px;height:600px;) /*组成立方体的元素*/
正棱柱构建完成后,就须要将咱们的“眼睛”放置在正棱柱内。因为在“眼睛”后的元素是不会被浏览器渲染的(与 .div元素
是否设置 backface-visibility:hidden;
无关),并且咱们保证 .div元素
的正面都是指向正棱柱中心,这样就造成 360° 被环绕的效果了。
那“眼睛”具体被放置在哪一个位置呢?
答:经过设置 #stage
元素的 translateZ
值,让不能被看到的 .div元素
在 Z
轴上的最终坐标值(即其自身 Z
坐标和祖先元素 Z
坐标相加)大于 #view
元素的 perspective
值便可。如:立方体的正面的 translateZ
是 -300px
(为了保证立方体的正面是指向立方体中心,正面元素须要以自身水平方向上的中线为轴,旋转 180度
,即 rotateY(-180deg) translateZ(-300px)
,即正面元素向“眼球”方向平移了 300px),而 #view
的 perspective
值为 1000px
,那么 #stage
的 translateZ
值应该大于 700px
且小于 1300px
便可,具体数值则取决于你想要的呈现效果。
根据上述知识,笔者粗略地模仿了“造物节”的效果:http://jdc.jd.com/lab/zaowu/i...
另外,只需 6 幅图就能够实现一张常见的无死角全景图。
笔者本身又试验了下:http://jdc.jd.com/lab/zaowu/i...
可由下图看出,将水平的 4 张图片合成后就是一张全景图:
所以,理解上述知识后,经过 CSS3 Transform 相关属性就能够实现可交互的全景效果了。固然,交互的效果能够是拖拽,也能够是重力感应等。
正如在上文提到的:“没有东西是连续的,即全部东西都是离散的...”。经过两个案例的对比能够发现:图片数量越多,对图片的要求也越低。你以为呢?
造物节全景图
将全景图制做分为设计类与实景类:
要制做相似 《淘宝造物节》 的全景页面,设计稿须要有如下这些要求。
注:下面说起的具体数据均基于《造物节》,可根据自身要求进行调整(若发现欠缺,欢迎做出补充)。
总体背景设计图以下(2580*1170px,被分红 20 等份):
基本要求:
固然,上图只是做为背景,咱们还能够添加一些小物体素材(与背景图的运动速度不一样时,可造成视差效果,加强立体感),如:
小物体元素(虚线用于参考,造物节中共有 21 个小物体)
如上图所示,每一个图片也被等分红 M 等份,并且 M 的宽度应该与 N(背景元素)的宽度相等(具体缘由,请看文章评论)。
对于顶部和底图图片,则无特殊要求。
若是想制做实景的全景效果,能够看看 Google 街景:
Google 街景 推荐的设备以下:
如上图,最实惠的方式就是最后一个选项——Google 街景 APP,该应用提供了全景相机功能,但正如图片介绍所说,这是须要练习的,所以对操做要求比较高。
补充:
上周六(2016.8.20)参加了 TGDC 的分享会,嘉宾分享了他们处理全景的方式:
其中 Web 技术有如下 3 种可选方式(固然,还有其它):
当时,嘉宾现场快速制做的 会议现场全景。
可见,优秀硬件设备的出现,大大减小了后期处理的时间,而 Web 则提供了一个很好的展示平台。
随着终端设备的软硬件不断完善和提升,Web 在 3D 领域也不甘落后,若是你玩腻了 2D 的 H5 或者想为用户提供更加新颖优秀的体验,全景也许是一种选择。
最后,若有不清晰或不明白的地方,能够留言,我会尽量解决的。谢谢谢~