新型3D Panorama技术解剖全息视频

CSS3 3D技术

前言

3D 全景并不是什么新鲜事物了,但以前我们在 Web 上看到的 3D 全景一般是通过 Flash 实现的。若我们能将 CSS3 Transform 的相关知识运用得当,也是能实现类似的效果。换句话说,3D 全景其实就是 CSS3 3D 的应用场景之一。
准备
在实现 CSS3 3D 全景之前,我们先理清部分 CSS3 Transform 属性:
transform-origin:元素变形的原点(默认值为 50% 50% 0,该数值和后续提及的百分比均默认基于元素自身的宽高算出具体数值);
perspective: 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。(默认值:none,值只能是绝对长度,即负数是非法值);
transform-style:用于指定其为子元素提供 2D 还是 3D 的场景。另外,该属性是非继承的;
transform:该属性能让你修改 CSS 可视化模型的坐标空间,其中包括 平移(translate)、旋转(rotate)、缩放(scale) 和 扭曲(skew)。
下面对上述的一些点进行更深入的分析:
对于 perspective,该属性指定了“眼睛”与元素的 perspective-origin (默认值是 50% 50%)点的距离。那么问题来了:“当我们应用 px 作为衡量单位时,那它的实际距离该如何量化呢(即如何得到我们熟悉且易于表达的距离)?”
答:当我们的屏幕的分辨率是 1080P(1920*1080px),且该元素或祖先元素的 perspective 值是 1920px 时,该应用了 CSS3 3D Transform 的元素的立体效果就相当于我们在距离一个屏幕宽度(1920px)的屏幕前观看该元素的真实效果。尽管如此,目前我也不清楚如何准确地为元素设置一个合适的 perspective 值,只能猜测个大概值,然后再动态修改值,以达到满意的呈现效果。

根据 相似三角形 的性质可计算出被前移的元素最终在屏幕上显示的实际大小

  • 另外,关于 perspective 还有另外一个重要的点。因为,perspective-origin 的默认值是 50% 50%,因此,对哪个元素应用 perspective 属性,就决定了“眼睛”的位置(即我们的“眼睛”是在哪个角度看物体)。一般来说,当我们需要正视物体时,就会将该属性设置在与该元素中心重合的某一祖先元素上。

    再另外,如果说:“如何让一个元素(的背面)不可见?”,你可能会说 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,而对于其它更复杂的正多面体呢?


    俯视时所看到的元素外移动画

    可由下图看出,将水平的 4 张图片合成后就是一张全景图:

    理解上述知识后,就可以通过为元素设置合适的 CSS3 Transform 属性值,即可实现一张可交互的全景图了。当然,交互的效果可以是拖拽,也可以是重力感应等。
    正如在上文提到的:“没有东西是连续的,即所有东西都是离散的…”。将《造物节》与后续全景图的水平方向上的图片分别合成一张图后,可以发现:图片数量越多,图片的要求也越低。你觉得呢?

    基本要求:

    1. 水平方向上需要首尾相连;
    2. 因为效果图最终需要切成 N 等份,所以尽可能让 设计图的宽度能被 N 整除;
    3. 图片尺寸不仅要考虑正视图的大小,还要考虑元素在旋转时依然能覆盖视野(可选)。