68

玩大了! 阿里工程师的年会竟然这样搞?

 5 years ago
source link: http://www.10tiao.com/html/639/201806/2247487667/1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

不用邀请函、不用签字板,“笑容”才是唯一的入场凭证。年会还有这样的操作?


最近在阿里巴巴内部就掀起这样一阵“笑容签到”风潮。在年会开场,大家是这样排队刷脸的:


 

而刷脸成功后,入场人员的花名、头像以及“笑容指数”会实时同步显示在会场大屏幕上,并汇聚成一个“笑脸星球”。


 

这是阿里巴巴信息平台一群90后工程师,用两周时间开发的一套年会开场秀系统:

 

观众在经过人脸识别后,系统会根据人脸表情特征,识别出观众的花名(名字)与微笑指数,同时吐出一句“评语”。当笑容越灿烂,评价就会越高。同时通过技术手段,这些信息还会上屏展示与互动。


工程师们在现场调试

 

不仅是部门年会,在内部一些大型比赛、重要颁奖典礼等活动开场,也逐步用起了这一套科技感满满的开场秀。同时根据活动不同主题,还可以进行个性化定制呈现。

 

阿里内部一些重要大会陆续使用这套系统开场


究竟这套年会开场秀系统如何实现的?今天,阿里妹邀请到该项目团队中的开发小哥哥探源,来聊聊背后的实现原理与技术方案。

 

背景


传统大会通常采用的暖场方式是,在大屏幕上循环播放宣传视频,等观众差不多到齐时,一个321的倒计时宣告开始,既老套又缺乏互动。更是白白错过一次向观众展示公司技术与公司人才的机会。

 

那有没有一种可以将科技感与互动感结合的开场秀呢?恰逢新一财年信息平台部门大会在即,我们想以此为切入点,给大家玩一些不一样的开场。

 

解决方案


任何一个“靠谱”的前端工程师,肯定会下意识想用H5动画来替代视频。我们的方案是:使用酷炫的H5动画,并且结合智慧园区团队的人脸识别技术实现人员扫脸签到+大屏展示的技术方案。既能运用及展示内部的技术,又能起到不错的暖场效果。



根据方案构想,很快就形成了初版需求demo。梳理一下,可以拆分出下面几点功能:


  • 初始状态下,是默认做自转运动的星球,周围有围绕的卫星

  • 当人员进场时,人脸识别成功后,在屏幕上展示

  • 展示完之后,照片要飞回到自转的球面上,跟着球一起做自转运动

  • 会议开始前,人工控制照片做粒子效果,over

 

技术方案


当功能拆解后,便是研究怎么实现方案了。出于对效果考虑,准备选择3维动画来创作,并最终采用了Three.js作为3D引擎库,结合tween.js作为配套的动画库,以及基于webpack的脚手架nowa链接作为技术支持。

 

whyThree.js?


目前市面上比较成熟的3D库有Three.js和Babylon.js,但对比两者后可发现:


  • Babylon.js常用于制作3d游戏引擎,倾向于游戏开发;而Three.js是纯渲染引擎。

  • Babylon.js诞生不久(13年),社区活跃;而Three.js相对久一些(比webgl还久),且比较流行,代码易读,团队成员有相关的开发经验。

  • Babylon.js已经支持了webgl2的多数特性,并且能够平滑降级;而Three.js还是处于提需求阶段,并没有支持。


所以最后选择的是Three.js,想尝试下webgl2.0的小伙伴可以试下Babylon.js。

 

技术实现


介绍完技术引擎后,接下来将结合整体的功能流程,为大家解析下如何通过技术实现。


step1:让球体运动起来



这是动画展示效果的第一步。通过Three.js的基本方法,很容易实现在场景中添加对象的功能。如上图所示,在场景中添加了一个球体,并让它做顺时针的转动,而让球表面的图做逆时针的转动,并向场景中添加了不断向z轴负方向运动的星星,和做一定角度的公转运动的卫星。



三维坐标系中的点坐标x,y,z可以转换成了(上图)中的极坐标r,θφ(半径r和两个角度θ 和φ),同样可以用来表示点的位置(反过来也能推导)。

 

球面上的方片也是由对象构成。人员签到成功之后,方片上会变成照片,这里需要事先计算出方片相对于球面的位置以便生成方片。根据前期配置的到场人数n,从而让球面生成均匀分布的n个点,得到每个点的极坐标系位置,再转换成点坐标位置,这些位置就是方片位置。

 

step2:加入“微笑”展示效果



前端通过轮询定时请求后端接口,来拉取人脸识别数据,展示之后告诉后端已经展示过了。由于现场人脸识别后的“微笑”需要实时展示在主屏上,每场年会活动到场人数不等(约500-1500人),在这一状况下,如何保证在规定时间内完成人员入场与展示。我们的方案是:展示时间可以动态调节,人流量大时识别成功之后大屏就展示快一些,反之则展示慢一些

 

因此,需要在前端维护了一个队列,用于存储识别成功但还未展示人员,轮询拉取的数据会进入到队列中,展示过的数据则会从队列中移除,一个展示动画的时长会根据队列的长度动态调节,取值范围2.5-5s不等。

 

step3:让“微笑”随球体一起运动


“微笑”展示后,还有个照片飞回球面并跟着球体一起运动的效果。因为牵涉到坐标系的相对运动球面的位置是相对于父元素来实现的),这一效果较难实现。


通过step1,可以计算出方片的位置position(position是个三维向量:xyz),因为位置是相对球体的,所以从球体看来方片的位置永远是xyz,而在全局看来,方片的位置是永远在变化的,而这个位置坐标怎么获取是一个问题。


当时,小伙伴们想到了两种方案:


第一种:让照片相对球体运动,这样就不用去考虑方片位置了,因为这个位置是不变的。但这样的弊端是,因为球体在运动,照片也需要一直运动。如果要达到视觉上看“照片不动”的效果,就需要照片永远对着摄像头。


第二种:让照片相对全局运动,在每一帧的时候去获取方片相对于全局的坐标。然后在这一帧内慢慢趋近于这个坐标,最后实现位置的重叠。


经过讨论,决定采用第二种方案。因为核心是要解决坐标系相对转换的问题,但第一种方案并没有解决,只是把问题方式转移了。还好,Three.js提供了现成的方法:getWorldPosition用于返回表示对象在世界空间中的位置向量。

    

这样,就可以得到方片的全局坐标。

 

现在知道了照片的位置和最后需要到达的位置。但如果直接从初始位置向最后位置运动,还会有个问题:照片可能直接穿过球体而达到最后的位置(不符合运动规律),所以这里需要尽可能做曲线运动,而不是让照片穿过球体。


我们还是用到了上面的坐标系转极坐标系的公式,通过初始的极坐标位置(sourceR,sourcePhi,sourceTheta)和目标位置的(targetR,targetPhi,targetTheta)。根据线性差值公式计算出在每一帧中的中间位置(currentR,currentPhi,currentTheta),再转换成点坐标系下的位置,即为每一帧时照片的位置,从轨迹上来看是一个曲线运动,且不会穿过球体。

 

step4:粒子动画开场



终于进入最后的环节了。在活动正式开场前,“笑脸星球“会散开成粒子状态,通过粒子运动拼成本场活动的主题文案。这里运用到粒子动画效果,需要事先知道每个粒子最后运动的位置。我们参考了canvas粒子动画的效果(具体可以自行查一下),简化如下:


  1. newImage加载图片

  2. context.drawImage把图片画到一张canvas画布上

  3. 通过context.getImageData就可以获取画布上指定区域的像素数据

  4. 比较每个点的像素值就可以记录下需要像素点的位置信息,转换成3D的坐标

    这边会涉及坐标系的转换,需要特别注意一下,平面canvas的坐标系和THREE.js的坐标系是不一样的)。

  5. 创造粒子,让粒子做飞散状运动起来,最后到达指定位置即可

  6. 事先准备两张图片,一张白底透明,一张彩色透明,粒子运动完成之后白底渐渐显示

  7. 然后白底渐隐,彩色的渐渐显示


性能优化


客观因素如:大屏分辨率、设备显卡等不考虑,但需要更多从可控条件来解决部分性能问题。一般衡量动画是否卡顿用fps衡量,如果在30-60帧之内肉眼基本无感知,再往下,会感受到很明显的卡顿。第一版开发完成之后,在mac上的帧率只有20+到40。肯定达不到标准,所以从以下几个方面开始优化。


1.尽量重用MaterialGeometry,或者缓存模型;


BufferGeometry 会缓存网格模型,性能要高效点。网格模型生成原理。


  • Geometry 生成的模型是这样的 (代码)-> (CUP 进行数据处理,转化成虚拟3D数据) -> (GPU 进行数据组装,转化成像素点,准备渲染) -> 显示器第二次操作时重复走这些流程。


  • BufferGeometry 生成模型流程 (代码) -> (CUP 进行数据处理,转化成虚拟3D数据) -> (GPU 进行数据组装,转化成像素点,准备渲染) -> (丢入缓存区) -> 显示器第二次修改时,通过API直接修改缓存区数据,流程就变成了这样(代码) -> (CUP 进行数据处理,转化成虚拟3D数据) -> (修改缓存区数据) -> 显示器。


2.减少渲染的对象,或者渲染的时候让对象不可见:渲染过不再需要的对象可以设置visible = false,或者直接从scene中remove,两者的区别可以参考Three.js scene.remove vs. visible=false;


3.谨慎地在render()中操作:一般FPS为60也就意味着一秒会执行60次如果render()中有有实例化或是赋值操作很容易会崩溃;


4.选择合适的对象:粒子我就是用Sprite代替Mesh实现的;


5.考虑光源的影响:会影响场景中对象的渲染;


6.渲染的对象时side属性尽量用FrontSide,DoubleSide会导致更多的渲染,也是减少渲染的方法;


7.可以用着色器来渲染,用更底层的glsl来实现。


优化完之后的状态:在mac上基本上都是60fps。保证了最终效果的实现:

 


未来规划


万万没想到,一套专为部门年会做的方案,正逐步演变成一个成熟产品。并且通过可视化、定制化的配置,结合人脸识别技术已经支持集团多个部门的年会与活动。


随着使用场景的不断丰富,未来我们还将针对活动主题,在活动过程中增加互动。比如根据入场时的人脸识别,支持抽奖等现场互动,实现年会大屏、观众手机、人脸闸机等多屏互动。此外,在面向参会观众,还将生成现场图片等素材,方便收藏。

 

信息平台事业部是阿里巴巴经济体服务的基础平台,为阿里巴巴提供生态化、国际化、数据化、移动化以及安全稳定的企业信息服务。我们希望能有更多同学加入,通过技术创新,挑战自己的不可能,同时为阿里巴巴更多可能性的发生贡献力量。


点击文末“阅读原文”,即可查看招聘岗位具体信息,投递简历。



每天一篇技术文章,

看不过瘾?

关注“阿里巴巴机器智能”,

发现更多AI干货。


 ↑ 翘首以盼等你关注


你可能还喜欢

点击下方图片即可阅读



内核空间镜像攻击揭秘


程序员吃的是青春饭?本质上取决于......



为什么阿里工程师纷纷在内网晒代码?


关注「阿里技术」

把握前沿技术脉搏


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK