JChehe / blog

🌈 原创&翻译 🌈
719 stars 111 forks source link

CSS 3D Panorama - 淘宝造物节技术剖析 #2

Open JChehe opened 7 years ago

JChehe commented 7 years ago

本文首发于 凹凸实验室

封面

前言

3D 全景并不是什么新鲜事物了,但以前我们在 Web 上看到的 3D 全景一般是通过 Flash 实现的。若我们能将 CSS3 Transform 的相关知识运用得当,也是能实现类似的效果。

准备

在实现 CSS3 3D 全景之前,我们先理清部分 CSS3 Transform 相关的属性:

下面我们对上述的一些点进行更深入的分析:

实现

理清了 CSS Transform 相关的知识点后,下面就讲讲如何实现 CSS 3D 全景 :

想象一下,当我们站在十字路口中间,身体旋转 360°,这个过程中所看到的画面就是一幅以你为中心的全景图。其实,当焦距不变时,我们就等同于站在一个圆柱体的中心。

但是,虚拟世界与现实世界最大的不同点是:没有东西是连续的,即所有东西都是离散的。例如,你无法在屏幕上显示一个完美的圆。你只能以一个正多边形表示圆:边越多,圆就越“完美”。

同理,在三维空间中,每个 3D 模型都是一个多面体(即 3D 模型由不可弯曲的平面组成)。当我们讨论一个本身就是多面体(如立方体)的模型时并不足以为奇,但对于其它模型,如球体,就需要意识这个原理。 三维环境的球体

淘宝造物节的活动页 是一个基于 CSS 3D 实现的全景页面。它将全景图分割成 20 等份,为一个正 20 棱柱。需要注意的是:我们要确保每个元素的正面是指向棱柱中心。所以要计算好每等份的旋转角度值后,再将元素向外(即 Z 轴方向)平移 r px。对于立方体的 r 就是 边长/2,而对于其他正棱柱呢?

举例:对于正九棱柱,每个元素的宽为 210px,对应的圆心角为 40°,即如下图:
图片来自:https://desandro.github.io/3dtransforms/docs/carousel.html
正九棱柱的俯视图
正九棱柱的俯视图

计算过程
计算过程

由此可得到一个通用函数,只需传入含有元素的宽度元素数量的对象,即可得到 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: 420px)
    #cube(transform-style: preserve-3d)
        .face // 组成立方体的面

正棱柱构建完成后,就需要将我们的“眼睛”放置在正棱柱内。由于浏览器不会渲染在“眼睛”后的元素(与 .face 元素 是否设置 backface-visibility: hidden; 无关),且保证 .face 元素正面均指向正棱柱中心,这样就形成 360° 被环绕的效果了。

根据上述知识,笔者粗略地模仿了“造物节”的效果:https://css3dpanorama-1251477229.cos.ap-guangzhou.myqcloud.com/index.html

另外,只需 6 幅图即可实现一个常见的无死角全景图效果:https://css3dpanorama-1251477229.cos.ap-guangzhou.myqcloud.com/street.html

可由下图看出,将水平的 4 张图片合成后就是一张全景图:
此处输入图片的描述

以上就是我们通过 CSS3 Transform 相关属性实现的可交互全景效果了。当然,交互效果可以是拖拽,也可以是重力感应等。

全景图素材的制作

将全景图制作分为设计类与实景类:

设计类

要制作类似 《淘宝造物节》 的全景页面,设计稿有以下要求。

注:下面提及的具体数据均基于《造物节》,可根据自身要求进行调整(若发现欠缺,欢迎作出补充)。

整体背景设计图如下(2580*1170px,被分成 20 等份):
淘宝造物节整体效果图

基本要求:

  1. 水平方向上需要首尾相连;
  2. 因为效果图最终需要切成 N 等份,所以设计图的宽度要能被 N 整除
  3. 不要遗漏上下两面。

为了增强立体感,可添加能形成视差效果的小物体(与背景图不同的运动速度、延迟时间),如:
物体小元素1
物体小元素2
小物体元素(虚线用于参考,造物节中共有 21 个小物体)

如上图虚线所示,每个小物体也会被等分成 M 份,且每份宽度应与背景元素宽度相等。

实景类

如果想制作实景的全景效果,可以看看 Google 街景:

Google 街景 推荐的设备如下: Google 街景推荐的设备

如上图,最实惠的方式就是最后一个选项——Google 街景 APP,该应用提供了全景相机功能。但正如图片介绍所说,这是需要练习的,因此对操作要求比较高。

补充: 上周六(2016.8.20)参加了 TGDC 的分享会,嘉宾分享了他们处理全景的方式:

  1. 利用 RICOH THETA S 等专业设备拍出全景图
  2. 导出静态图像
  3. 利用设备专门提供的 APP 或 krpamo tools、pano2vr、Glsky box 等工具将静态图像切分为 6 张图
  4. 利用 Web 技术制作可交互的全景图

其中 Web 技术有以下 3 种可选方式:

现场快速制作的 会议现场全景

可见,优秀硬件设备的出现,大大减少了后期处理的时间,而 Web 则提供了一个优秀的展现平台。


最后

随着终端设备的软硬件不断完善与提高,Web 在 3D 领域也不甘落后,如果你玩腻了 2D 的 H5 或者想为用户提供更加新颖真实的体验,全景也许是一种选择。

最后,如有不清晰或不明白的地方,可以留言,我会尽可能解决的。谢谢谢~

zjp123 commented 4 years ago

你好 有源码可以参考下吗

JChehe commented 4 years ago

你好 有源码可以参考下吗

@zjp123 没有哦,弄丢了。网上好像有插件实现。

xiao252 commented 4 years ago

全景图载入的时候有种路径动画的效果那部分是怎么实现的呢?

JChehe commented 4 years ago

全景图载入的时候有种路径动画的效果那部分是怎么实现的呢?

@xiao252 是指加载进度条完成后,组成棱柱的每片方块从小到大的效果吗?

  1. 棱柱作为一个整体进行旋转
  2. 同时,组成棱柱的每片方块按序错开一定间隔时间,执行从 scale(0) -> scale(1) 的过渡
xiao252 commented 4 years ago

全景图载入的时候有种路径动画的效果那部分是怎么实现的呢?

@xiao252 是指加载进度条完成后,组成棱柱的每片方块从小到大的效果吗?

  1. 棱柱作为一个整体进行旋转
  2. 同时,组成棱柱的每片方块按序错开一定间隔时间,执行从 scale(0) -> scale(1) 的过渡

哦 ,明白了 :)