这篇文章是我对此次GMTC的移动AI专场中分享的“AR在百度小游戏中的探索实践”所作的记录整理,并对其中一小部份内容作了一点微调。前端
此次分享主要分为三块内容git
首先第一个很是传统的是基于 marker 追踪的AR 效果。这种 AR 须要使用一张像 barcode 这样具备规定特征的图片做为 marker 生成特征数据,而后在运行的时候对输入的相机画面作匹配,寻找这个特征图片,进行实时的追踪而且生成三维变换矩阵应用到三维模型上达到现虚拟场景和显示场景融合的效果。像浏览器中的 AR.js 就是基于 Marker追踪实现的AR能力。而它底层其实是用的ARtoolkit的JS版本,这也是一个很是老牌的AR库了。
第二个是基于图片的追踪,跟刚才对Marker的追踪同样,也须要预先对图片生成特征数据,而后在运行时作匹配。不同的是,基于图片的追踪可使用任意的天然图片了(固然仍是须要有必定的特征,不能使用纯色这样的图片),这样使得AR能够应用到更多的营销场景中,好比图中是追踪了马里奥游戏盒的封面图片,而后在上面展示了更多的游戏信息。
第三个愤怒小鸟的AR版。它使用了基于平面追踪的AR,游戏中会检测相机输入的现实场景中有哪些是平面,而后把游戏场景放到这个平面上。这个技术的表明就是苹果的ARKit和Google的ARCore了。
第四个是前几年很火的AR游戏Pokemon Go ,这个游戏是基于LBS的玩法,玩家须要跑到地图上投放了宠物的位置去寻找和捕获宠物
最后两个案例:github
前一个是前段时间权力游戏第八季开播时在Snapchat上投放的AR营销,它会在用户打开相机后去识别画面中的地标建筑(地标建筑也须要预先生成特征数据),而后对画面作天空分割,在分割出来的区域播放一个天空盒的视频,画面中在飞的龙和乌云就是视频播放的。
后一个是典型的人脸AR 应用,也是一个营销的场景。人脸的加强通常就是识别并追踪前置摄像头中的人脸画面,识别出人脸上五官的特征点,而后基于这些特征点实现像表情触发,人脸美妆和贴纸等效果。web
刚刚介绍了六个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的场景以后可以作到兼容。app
百度小游戏做为一个容器,包含了一个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游戏或者应用的时候有更沉浸式的体验。
除了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 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....
本文做者:
shenyi