GMTC2019分享记录|AR在百度小游戏中的探索与实践

本文作者:

shenyi

背景

这篇文章是我对这次GMTC的移动AI专场中分享的“AR在百度小游戏中的探索实践”所做的记录整理,并对其中一小部分内容做了一点微调。

这次分享主要分为三块内容

1. 目前比较典型的AR应用的介绍,对现在应用的AR能力有一些了解

2.浏览器中的 AR以及百度小游戏中AR 的集成方案

3.通过一个 case 介绍怎么在百度小游戏上去开发一个AR的应用

AR应用的介绍

丨1. 六个AR案例

首先第一个非常传统的是基于 marker 追踪的AR 效果。这种 AR 需要使用一张像 barcode 这样具有规定特征的图片作为 marker 生成特征数据,然后在运行的时候对输入的相机画面做匹配,寻找这个特征图片,进行实时的追踪并且生成三维变换矩阵应用到三维模型上达到现虚拟场景和显示场景融合的效果。像浏览器中的 AR.js 就是基于 Marker追踪实现的AR能力。而它底层实际上是用的ARtoolkit的JS版本,这也是一个非常老牌的AR库了。

第二个是基于图片的追踪,跟刚才对Marker的追踪一样,也需要预先对图片生成特征数据,然后在运行时做匹配。不一样的是,基于图片的追踪可以使用任意的自然图片了(当然还是需要有一定的特征,不能使用纯色这样的图片),这样使得AR可以应用到更多的营销场景中,比如图中是追踪了马里奥游戏盒的封面图片,然后在上面展现了更多的游戏信息。

第三个愤怒小鸟的AR版。它使用了基于平面追踪的AR,游戏中会检测相机输入的现实场景中有哪些是平面,然后把游戏场景放到这个平面上。这个技术的代表就是苹果的ARKit和Google的ARCore了。

第四个是前几年很火的AR游戏Pokemon Go ,这个游戏是基于LBS的玩法,玩家需要跑到地图上投放了宠物的位置去寻找和捕获宠物

最后两个案例:

前一个是前段时间权力游戏第八季开播时在Snapchat上投放的AR营销,它会在用户打开相机后去识别画面中的地标建筑(地标建筑也需要预先生成特征数据),然后对画面做天空分割,在分割出来的区域播放一个天空盒的视频,画面中在飞的龙和乌云就是视频播放的。

后一个是典型的人脸AR 应用,也是一个营销的场景。人脸的增强一般就是识别并追踪前置摄像头中的人脸画面,识别出人脸上五官的特征点,然后基于这些特征点实现像表情触发,人脸美妆和贴纸等效果。

丨2. 浏览器中的AR

刚刚介绍了六个AR的应用,这些应用都是会通过不同的手段去识别现实场景中自己需要的内容,然后根据识别到的内容实现相应的游戏或者应用逻辑。

所以对于一个AR 应用来说,首先要做的事情是通过各种各样的技术手段去理解现实场景,比如通过陀螺仪等传感器去感知手机空间位置和朝向的改变。通过对输入的相机画面做一些传统的CV识别,或者现在更流行的卷积神经网络,去识别出画面中的人脸,平面等物体。通过GPS去知道自己在世界地图中的位置。然后在理解现实场景的基础上,再通过一些三维渲染的技术,去加入虚拟形象,虚拟场景,与相机画面做整合,实现增强现实的效果。AR 的效果好不好,主要就看对周围环境的理解是否到位,是否能够正确识别到平面,是否能够识别出遮挡等等。而这其中深度学习起到了非常重要的作用。

在浏览器中,现在已经有一些规范能够去提供刚才所说的AR需要的能力了,比如有 deviceorientationevent 和 devicemotionevent 两个事件去接受传感器的变化,有WebRTC规范去得到相机画面的输入。对于深度学习来说,TensorFlow 和百度的 Paddle 都已经有了可以在浏览器中运行的版本,可以通过这些深度学习库在浏览器上去对输入的相机图像做理解和推理。

但是以目前JavaScript的性能,尤其是在AR最依赖的手机端,去实现刚才演示的那些 AR 的效果还是很吃力。JavaScript 很难去做一些非常底层的硬件优化,也没法使用SIMD,多线程这些常用的优化手段,尽管像TensorFlow 和 Paddle 会使用WebGL 去做一些卷积计算的GPU通用计算,但是整体的性能还是远远不够,很难达到实时。不过深度学习这一块也是有一些正在推进中更低 level 或者更专项的规范去更高效的做这些事,比如 WebGPU 和 WebNN。

除了这些,w3c也有一个 immersive group在制定针对AR / VR场景的规范 - WebXR。WebXR之前其实是WebVR,后来为了引入AR才重新把名字叫做了WebXR,现在WebXR 里也主要还是针对VR的场景,跟AR相关的比较少。

我们在百度小游戏中对于AR的集成就参考了WebXR的规范,也是希望后面在WebXR完善了AR的场景之后能够做到兼容。

百度小游戏中AR的集成

丨1. 基于ARCore 和 ARKit 的能力

百度小游戏作为一个容器,包含了一个JS引擎(安卓下是V8,iOS下是JSCore)用于运行开发者写的JS游戏逻辑代码,同时提供了WebGL 和 Canvas 2D 用于游戏渲染,以及文件系统,网络等能力用于加载游戏资源。接下来会大概介绍一下百度小游戏中对于AR的集成,包括基于ARKit和ARCore提供的平面AR的能力,以及基于百度的DuMix AR提供的人脸AR 扩展。

这个演示的例子是前段时间用THREE.js写的一个百度小游戏的AR case,这个例子演示了一个完整的AR应用的流程。在开始的普通界面就是一个常见的汽车展示的样子,可以旋转,缩放查看。在进入AR模式之后会调起摄像头,检测画面中的平面,检测到合适的平面后可以点击放置汽车模型,这个汽车模型会和真实场景融合在一起,用户可以走动查看车辆的各个细节。

通过这个case大概可以看到一些百度小游戏中基于ARKit和ARCore提供的能力,比如进入AR 模式后AR会话的创建,相机在现实世界中位置的追踪,平面检测等等。接下来会具体介绍其中的六个主要能力。

1.1 World Tracking

世界追踪World Tracking 是百度小游戏AR中一个非常基础的能力,它能够实时的追踪用户在现实世界中的位置,然后返回相机的 view matrix 。这个 view matrix是三维渲染中的视图变换矩阵,能够直接被游戏引擎中的三维相机对象使用,从而实现把用户在现实世界中的位置映射到虚拟世界中的效果。

1.2 Point Cloud

ARKit 和 ARCore每一帧都会对相机画面检测特征点,开发者能够拿到这些特征点点云的三维位置(x, y, z)数据然后绘制到相机画面上,能够给用户一个在实时检测的反馈。

1.3 Plane Tracking

ARKit和ARCore会通过整个AR会话期间检测出来的特征点,去推测出空间中的平面,这个平面可以是水平的地面,桌面,也可以是垂直的墙面。这是非常核心的一个能力,开发者可以获取到检测到的平面中心点的变换矩阵以及平面的大小。

1.4 Hit Test

Hit Test是三维渲染中的一个概念,一般是根据屏幕上的一个坐标得到一条射线,然后使用这个射线跟三维场景求交得到相交的交点坐标和表面法向量。对于AR来说,求交得到的就是平面上的交点或者说是特征点。开发者可以使用这个能力实现诸如点击放置三维模型的功能。

1.5 Anchor

在锚点(Anchor)上,ARKit和ARCore的定义会有点区别,ARKit所有追踪的东西都是锚点,比如人脸,平面等。ARCore 就要简单很多,锚点就是一个现实空间中的固定位置和朝向,但是它可以是绑定到像平面这样可追踪的物体上。Immersive web 也有讨论 WebXR 中该怎么定义这个锚点,现在并没有什么结论。我们是对ARKit和ARCore取了一个交集,锚点就是在现实空间中的一个固定位置和朝向,没有其它的用途。

游戏引擎中的场景节点的可以跟锚点绑定起来,每一帧锚点都会更新它最新的变换矩阵 poseMatrix,像三维模型这样的场景节点在应用了这个锚点之后,可以保证渲染的时候它看起来就是放在一个固定的位置上。就像下图演示的一样。

1.6 Light Estimate

最后一个是光照信息的获取,目前可以获取到环境光的强度和色调RGB值。开发者可以像下图一样根据获取到的环境光强度去调整渲染中的光照强度,保证在不同光照的场景下三维渲染都能跟真实场景更融合。

这是目前我们基于ARKit和ARCore提供的六个主要能力,后面也会逐渐暴露更多ARKit和ARCore的能力提供给开发者。通过这些能力可以去更好的融合三维的虚拟世界以及相机中的现实世界,能够让用户在使用AR游戏或者应用的时候有更沉浸式的体验。

丨2. 基于DuMix AR 提供的人脸增强扩展

除了ARkit 和ARCore,我们也集成了我们自己的AR SDK,去提供一些像人脸增强这样的扩展AR模式。同样的接下来会大概介绍一下这个人脸模式中提供的能力。

2.1  相机数据

对相机加后期滤镜是人脸应用中不可缺少的一个环节,因此我们通过 Video 对象提供给了开发者相机数据访问的能力。这个 Video 对象跟图片一样可以作为WebGL中纹理的数据源,然后在 Shader 中实现一些像下图中演示的故障艺术,DuoTone以及磨皮美白这样的实时滤镜。

2.2 特征点识别

人脸五官特征点的识别是目前大部分人脸应用的基础,我们会把检测到的95个人脸特征点归一后的(x, y)坐标放到一个Float32Array 中,开发者可以利用这些特征点去做像瘦脸,2D 贴纸这样的后期效果

2.3 人脸骨骼识别

在刚才特征点的基础上,算法还会计算出人脸的骨骼的变换矩阵,这个骨骼的变换会驱动相应的人脸三维模型,实现下图这样贴合人脸的模型动画

动图中绿色的点就是骨骼节点了,看起来可能跟特征点很像,但是它是三维空间而且跟白色的人脸模型网格绑定的。如果我们再给这个人脸模型加上纹理,就可以类似像上面右图这样的3D贴纸效果或者美妆效果。除此之外,也可以在骨骼节点上绑定一个像帽子,耳环这样的三维模型去实现虚拟头饰的佩戴。

2.4 表情系数

最后一个同样也是根据特征推算出来的,五官的表情系数。表情系数是一系列 0 到 1 的值,用来描述五官的特征。比如嘴巴完全闭合是0,完全张开是1。那识别出来半张嘴的可能是一个0.5 的值,同样的像眼睛,眉毛都会有这样一个系数。这个表情系数可以用来做一些游戏逻辑的触发,也可以实现 Morph Animation。

大概介绍完了这两大块百度小游戏中提供的AR能力,我们再来简单看下现在小游戏的架构中是怎么集成和暴露这些AR 能力的。

这个是现在小游戏集成AR的模块图,最底层是我们集成的各个 AR 算法,包括 ARKit,ARCore,还有基于DuMix AR 的人脸算法模块。然后上面这层是小游戏的 Runtime,管理整个小游戏应用的 loop,每一帧去更新AR算法,拿到算法计算出来的数据,然后执行开发者写的 JS 逻辑,开发者会通过上层 v8 或者 JSCore Binding到JS运行环境的接口去访问 AR的数据,再把这些 AR 的数据提供给像 THREE.js 这样的游戏引擎,比如相机对象会使用projectionMatrix 和 viewMatrix  ,锚点的 poseMatrix 会更新到场景节点上。开发者的 JS 逻辑执行完后,再去渲染 Canvas 画布,和相机画面做混合然后绘制到屏幕上。

开发一个百度小游戏的AR应用

最后一部分会大概介绍一下怎么利用现在小游戏提供的AR 能力去开发一个像刚才汽车展示那样的AR demo。

首先是在编辑器中实现最基础的三维模型展示

刚才有提到小游戏Runtime提供了JS引擎,提供了WebGL的渲染能力,这些对于像THREE.js这样的游戏引擎来说已经足够用了,还有一些零碎的像注册事件这样的DOM操作可以通过一层JavaScript 中封装的DOM 适配层来解决。在这个基础上,我们就可以用 THREE.js 来愉快的开发小游戏的 3D应用了。汽车的模型是turbosquid 上下的,简单的处理了一下后转成了 glTF 格式,glTF 格式是 khronos  最近在推的一个 web 模型传输规范,特点是体积小,解析方便。Khronos对这个格式的定位是图片中的jpeg,视频中的 MP4 格式。THREE.js 有现成的模块可以直接加载展示 glTF 格式的模型。加载完之后就可以再加一些JS 的逻辑去实现模型的旋转查看,车漆颜色的更换等效果。右图是在开发者工具中的预览效果。

接下来第二步是进入 AR模式,在小游戏中启动AR模式是通过 swan.requestXRSession 这个接口。

整个接口的风格是跟小游戏其它接口风格保持一致的,调用 requestXRSession 后会异步的去创建 AR 的会话实例并且调起相机,创建成功后会进入 success 回调并且传入会话实例,如果失败(比如无相机权限)则会进入 fail 回调。调起成功后每帧可以通过 getFrame 方法获取帧对象,并且通过帧对象访问到相应的AR数据。

这个时候可以看到屏幕中的相机画面了,底下的ARKit 和ARCore也会开始检测画面中的平面,我们可以通过 getTrackablePalnes 方法获取检测到的平面并且判断这个平面是否可放置。

图中代码大概演示了怎么去获取平面并且判断平面是否可以放置,在这过程中我们可以绘制相应的引导去提示用户该怎么做,比如还不能放置的时候让他们再多移动一下手机,或者找一个更明显的地面。如果可以放置了则提示点击放置。因为平面检测的过程往往需要几秒到十几秒,这个过程有一个友好的引导是非常有必要的。

在查找到平面后就是“放置”模型的步骤了,这个“放置”我加了引号是因为实际上我们做的事是根据上面 hitTest 得到的结果去创建一个锚点。然后每一帧使用锚点的提供的矩阵并且应用到模型的场景节点上,实现虚拟物体“固定”在现实世界中中某个位置的效果。在“放置”完后我们就能得到差不多这样的画面了

我们第一眼看到的时候可能还是会感觉,这个就只是把模型画面覆盖在相机画面上吧,无法看出来这个模型是被放置在桌面上的,整个车的光照效果也跟相机画面中的格格不入。接下来我们就会去通过一些渲染的优化措施去解决这两个问题。

首先是光照的优化,刚才我们只是用了一个简单的平行光源,整体光照效果非常单一。对此我们可以引入 HDR 的环境光贴图。环境光贴图它相当于是每个像素都是一个光源了,可以让整体的光照更加丰富,比如车漆表面也有这种反射的效果了,然后再配合基于物理的渲染,可以取实现金属和非金属材质的区分,材质粗糙度的模拟,以及这个例子中特殊的 Clear Coat 的车漆效果。

使用固定的环境光照贴图在很多时候可以欺骗过用户的眼睛了,但是固定的毕竟不能反映真实的光照场景,比如局部明暗信息,或者说从室外换到室内,用的还是同一张环境光贴图,就显得不太合适了,所以有时候还是会显得比较假。更优的方案就是实时的从相机视频流里计算出环境光贴图。ARKit 提供了 AREnvironmentProbeAnchor 去得到环境光贴图,ARCore 最新版本还没有类似的功能,但是刚刚 Google IO 上有介绍了他们新版本会加入(在分享完后整理这篇文章的时候 ARcore 刚好发布了1.10 版本,支持了HDR的环境光贴图,平行光预测,以及球谐光照的系数)

HDR 的环境光贴图作为输入的光源,需要映射到LDR才不会在输出屏幕的时候导致过亮,这中间有一步叫做 Tone Mapping,做的事情就是从 HDR 线性或者非线性映射到LDR颜色空间。我们可以使用刚才提到过的 Light Estimate 的环境光系数来作为 Tone Mapping 的曝光系数,让整体渲染画面的曝光强度跟相机画面的曝光强度更接近。

然后是阴影的优化,阴影和遮挡是体现空间关系两个非常重要的因素,阴影可以用来体现光照,可以用来表现平面。PPT 下面图中加上阴影后可以看到汽车就像是被放在这个桌面上了。当然这个不只是渲染中才有的问题,在现实世界中如果阴影的位置跟人脑想像的不一样也会让人产生视觉错觉。

刚才的阴影是对理想光源的阴影,在现实世界中,更多的光照信息来自于各种其它物体或者大气中的漫反射,也就是间接光照。一些比较角落的区域就会因为接受到的简介光照比较少,就会比较暗。比如图中电脑和桌面接触的部分,同样的渲染的汽车的底盘下面也应该会暗很多。因此我们要在渲染中加入 接触阴影(Contact Shadow) 去模拟这种效果。

对于移动端来说,比较常见的方式是离线去烘焙出AO贴图,这种方式开销很低,而且对于静态场景来说效果不错,缺点就是没法针对使用到动态的场景中。

如果是动态的场景的话,可以使用实时的 SSAO 去模拟这种接触阴影,它是在屏幕空间中对像素周围的像素采样得到自己的遮挡信息,但是因为要实时所以不能有太多的采样,而且屏幕空间中也已经丢失了很多场景的几何信息,这些遮挡信息的确实往往会导致间接阴影的表现并不理想。刚好汽车底盘其实就是一个这样一个比较典型的 bad case。

在这个例子中用了一种更 trick 的方式去表现这种跟地面或者桌面的接触阴影。就是在汽车模型的横截面用黑色渲染了一帧,然后加上几层高斯模糊,作为平面上的接触阴影。这种实现非常廉价,而且效果整体还不错。当然这个只能针对现在这个场景,并不是所有场景都适用的。

在做完这些优化后可以看到整体渲染的效果跟真实场景已经比较接近了,车底盘下面的阴影跟后面其它相机画面中的车也比较一致。

当然还有不少可以优化的地方,比如刚才提到的从相机画面中提取出环境光贴图, 可以让车身的反射跟后面其它车的反射更加的接近。

总结

这次分享大概从AR应用示例的介绍,百度小游戏中AR 的集成和能力介绍以及一个AR应用的开发三部分介绍了一下,我们最后再来总结下这其中的一些重点。

在集成ARKit和ARCore的时候,我们在小游戏Runtime中做了渲染和数据的统一管理,去统一了两者一些不同的概念,保证提供给开发者一个一致的接口,并且在接口设计上能够实现高效访问,更符合前端的开发习惯。

除了ARKit和ARCore,我们也去扩展了像人脸这样的能力,后续也会继续加入肢体骨骼,手势,物体的识别和追踪功能。我们希望能够利用更多深度学习的能力去实现更强大的感知世界的能力从而实现更丰富的AR效果。

最后我们通过一个case去演示了如何在小游戏中开发一个可用的AR demo。这过程中我们去优化了平面检测中的交互,加入了像基于物理的渲染,间接阴影这样渲染技术去保证渲染的场景和现实场景更融合。这些渲染效果其实THREE.js 都有现成的模块可以用,这个demo 也大概只花了一个周末的时间。所以我们希望是能够把现在强大的Web生态和百度小游戏结合起来,能够让开发者非常便捷的去开发高质量的AR 游戏和AR应用。

参考资料

https://immersive-web.github.io/webxr/

---------------------------------

在微信-搜索页面中输入“百度App技术”,即可关注微信官方账号;

收藏 评论(0)
分享到: