上个月底,在朋友圈看到一个号称“这可能是地球上最美的h5”的分享,点进入后发现这个h5还很别致,思考了一会,决定要不高仿一个?
到今天为止,高仿基本完成,
除了手机端的media控制没有去兼容,其他的基本都给仿了。 那为了让你觉得是高仿,最好使用chrome的手机调试模式进行访问。微信打开将听不见声音看不到视频... (后面再有时间看是不是仿的再进一步)
之所以要仿它,因为觉得这个h5还挺酷,想看看自己需要花多长时间找到并实现它的技术路径。
需求分析
这个h5的主要玩法很简单:地球自转的时候会播放背景音乐(比如海浪声),为了找到这个声音是从哪个地球上哪个地方传来的,需要长按下方的按钮,这时地球会自动转动到目标地点,然后镜头拉近,穿过云层,最后你会看到和这段声音相关的视频内容;松开手之后,上面的过程会倒退回去,地球又开始自转,播放着下段神秘的背景音乐。
个人觉得这个设计还是很新颖的,不是说用了3D的效果,而是将一个看起来很复杂的动画(从宇宙拉近到地表的过程),使用最基础的3D效果和其他一些常规的动画手法去实现,并且能流畅的运行在手机浏览器上。另外还有声音和视频的完美搭配,用户体验不错。
反复观察,理清页面功能:
- 加载:加载进度百分比,饶椭圆轨道运行的小行星作为loading动画(这个动画我没有做)
- 地球:3D球体,旋转入场动画,自转,漂移的云层,城市的坐标点,镜头的旋转与拉近,穿越云层动画
- 星空背景:静态星空背景图,动态(闪烁的)星星,划过的流星
- 隐藏的音频和视频:按内容(地理位置)划分的音频和视频内容
- 其他:操作指引示意动画,地球上方会显示当前城市的经纬度,“了解更多”的结语页面等
寻找技术路径
打开chrome inspect一下。
首先是这个地球,得看看它是真3D还是假3D(因为很多3D效果是拿雪碧图做的,比如这里的旋转的3D飞机),结果找到了:
<div class="ns-webgl-page">
<canvas width="750" height="1200" style="width: 375px; height: 600px;"></canvas>
</div>
并且在网站source文件中搜到了THREE,那就是threejs没跑了。
然后是那个穿越云层的效果,猜测可能是GIF,可能是SpriteSheet Animation,也有可能是一段视频。但是考虑到这个穿越的动画可以正反双方播放,那么就很可能是是SpriteSheet Animation了,否则GIF或者视频文件需要两个动画方向各准备一份。这个从chrome debug工具的network下找到了证据—— 页面下载了一系列名为kf_cloud_0000X.jpg
的图片文件。顺手就把它们down下来,备用。
再就是背景音乐和隐藏视频的问题,同样在network下,找到了两个文件,一个mp3一个mp4,每个文件都包含了所有片段,就像是media的雪碧图,只在需要的时候控制播放对应片段而已。
其他的内容都没什么问题,CSS动画或者CANVAS都好做。那么到此,技术路径都清楚了,准备开始写代码。
难点突破
对于我而言,用threejs绘制地球可能会是难点,threejs没有用过,而且印象中对3D的东西,一直比较敬畏。如果3D的地球弄不出来,这个项目其他的都做完了,在浩瀚的宇宙中是怎么也找不到“声音来自何方”了。
OK,来看threejs怎么能弄出个地球来。(这个阶段并没有开始项目代码,而是尽量的在一个临时文件中进行涂鸦,快速随意的达到绘制出地球的目的就行了)
官网
对于新的技术,首先得看官网。这里并不是来全面学习threejs的,而是抱着很强的目的性去实现特定功能,因此直接去示例中找,是否有类似实现可以借鉴。在官网首页中,通过缩略图,找到了下面三个关于地球的例子。
可惜,貌似这里的例子都是一些产品应用,代码都是压缩过的。于是开始去寻找官方示例,最后在examples里找到了canvas_geometry_earth,最棒的是在github上有源码。
示例代码
clone下threejs的项目代码,找到上面的示例文件。示例代码不到200行,阅读之后发现其实threejs和之前接触过的一些2D的游戏引擎(createjs,pixijs)等比较类似,都需要有场景(scene),要有渲染循环(render loop),在scene上添加对象(Mesh)或者是group;而Mesh由形状(Geometry)和材质(Material)组成,Material则又是由图片创建的纹理(Texture)而来。不同的是,这里有相机(Camera),有光线(Light),还有一些一直都不明白的距离单位问题。
稍微改动一下示例代码,就能创建出来了earth。但是从使用的资源来看,只有一个地表纹理贴图(earth4.jpg),而xplan中还有3个关于earth的图片文件:
不确定bump和spec是什么,我的思路是先在官方文档中找这些关键词,如果找不到,就加上threejs一起去做google。官网上找到了bump相关的东西,但帮助最大的是google出来的一篇详细的如何使用threejs创建earth的教程。(如果这个教程早点冒出来,也省了前面改示例代码的时间了。主要也源于对threejs不熟悉,没有想到哪些示例可能已经有很多教程了)
换上了earth4.jpg贴图之后:
教程中的步骤不再这里重复,下面仅仅对一些关键东西作简单的解释。
earth_bump
了解到bumpmap:
Bump mapping is a technique to simulate bumps and wrinkles on the surface of an object. The result is an apparently bumpy surface rather than a smooth surface although the surface of the underlying object is not actually changed. I'm sorry, you can't tilt the camera to see 3D mountains with this technique. You can adjust the bump effect (how much the map affects lighting) with the bumpScaleparameter
threejs中bumpmap是调节对光线的感知,来使人能明显感觉到不光滑的表面,而并没有在mesh中添加起伏,即没有真的改变形状。
官方bumpmap示例效果图如下:
其实这里的earth_bump.jpg就是一个DEM,在threejs中称作bumpmap,在其他一些地方也有被叫做heightmap。即用灰度图表达高程,越黑表示高程越低,越亮表示高程越高。GIS专业中常用,unity3D中创建地形也会用到这个。
添加了earth_bump之后:
earth_spec
了解到了earth_spec.jpg是specular map,用来调节镜面反射的,这里主要是调节海洋对光线的反射,增加真实性。
添加了earth_spec之后:
漂移的云层
云层的添加, 前面的教程里已经很详细了,其实就是一个同心,半径大一点的球体而已。
添加了云层之后:
浮动的标签
xplan中地球表面有城市标签,会随着地球的自转而移动,同时又保持了水平的方向。google关键词:threejs floating label。于是找到:
- http://threejs.org/examples/#webgl_sprites
- http://stemkoski.github.io/Three.js/Labeled-Geometry.html
找到方向就好办,稍微参考一下官方API文档和找到的示例代码,能够很容易的在earth上添加上浮动标签。
小结
到这里,3D地球的绘制基本差不多了。虽然threejs是新东西,但是绝大部分功能都容易找到方向,并且改动一下示例代码都够快速的实现我们想要的效果,所这个过程并不难。重点是如何在一个未知的领域内找到想要的东西,并且快速的为自己所用。
但过程中我碰到一个性能问题,耽误了很久。xplan的页面在chrome的PC和手机模式都有近60的FPS,但是我创建的earth在PC有60,但是在手机模式却不到30!最后逐一调试代码,修改参数,花了好久才找到原因:
renderer.setPixelRatio(window.devicePixelRatio)
threejs的示例代码中都有这么一行,就是这一行导致了我的代码比xplan的代码在手机上绘制的像素点翻倍,从而导致了性能成倍的下降。
另外,前面也提到,我对于3D框架中的距离单位和坐标问题,很模糊。于是这里,关于earth的大小,camera朝向,每个城市标签的三维坐标和其他关与三维坐标的问题,我都硬抄了xplan的参数(幸好他们的代码没有压缩...)。还有一个要承认的,就是地球后面的淡蓝色光晕效果,貌似用了一些高级的渲染技术,我也就硬搬了xplan这部分代码。
下一篇将介绍如何制作多步骤、可进可退的动画,在我看来这个才是技术难点。