Google近几年在VR/AR领域动作频频,先是推出Cardboard作为VR体验的敲门砖,随后发布Project Tango作为AR体验的基石,紧接着移动端的VR平台Daydream应运而生,今年在Google I/O大会上推出了升级版Daydream2.0,近期发布了基于Android平台的AR SDK — ARCore,这摆明了就是要怼早一步公布的iOS平台的AR SDK — ARKit,让无数Android开发者兴奋不已,两家公司的竞争态势也蔓延到组内移动端两股开发势力,前几个月隔壁iOS组的同事可都是鼻子朝天走路的。
秉着对VR/AR的好奇,自己对VR and AR at Google (Google I/O ‘17)进行相关学习,也对ARCore进行实践操作和分析,结合各种专业人士的真知灼见,本文难免有所纰漏,欢迎大家指导交流。
比较正式的解释:
而对于小白用户来说,最直观最接地气的解释是
这次更新也提供了投射功能,将你所能看见的展现给在场的其他朋友一起观看
后者是最近推出的针对移动设备上的单目+IMU(Inertial measurement unit惯性测量单元)的增强现实方案,试图打造用户量最大的AR平台,目前还处在preview阶段,主要对标苹果推出的ARKit。
ARCore 在移动设备上运行主要有三大关键技术:
1. Motion tracking(运动追踪) 可以让手机了解并追踪其在现实世界中的位置。使用手机的摄像头观察房间里的特征点和IMU传感器数据,判断设备所在的位置和方向,对虚拟物体进行精准放置,同时使用vps(visual positioning service室内导航)定位周围的物体位置。
2 . Environmental understanding(环境感知) 可以让手机检测到类似地板或桌面平面大小和位置。虚拟物体一般是放在平面上,ARCore可以利用动作追踪中使用的数据点判断水平表面,保证物体可以正常放置,增加现实感。
3 . Light estimation(光线感知) 可以让手机感知真实世界环境中的光照条件,让开发者照亮虚拟物体的方式与周围环境匹配,虚拟阴影在光照条件下会自动调整,以便让虚拟物体看起来更真实。
ARCore被设计用来支持数量广大的Android设备,但是目前对设备要求比较严格,要求系统不低于Android 7.0 Nougat(API 24),支持下列设备:
但是实际上可运行的设备并不限于以上手机类型,个人臆测其实Google应该是提前研发了ARCore,为了增加使用范围,所以在适配其他手机类型上花费了较多的时间,没想到苹果利用iPhone适配款式少、系统唯一等优势提前发布了ARKit,并直接宣称是世界上最大的AR平台,别说Google,就我们这些Android开发者也是不服的。出于各种因素,Google应该是提前发布了ARCore,并限定了可运行的手机设备,这些设备是满足各项严格测试的,还有其他部分设备只支持部分功能,存在未知隐患,所以还没有公布。但是可以通过修改代码的方式来去除设备限制,这个会在后文描述。
根据目前的Google AR文档描述,支持的开发环境有Android Studio、Unity、Unreal、Web四种。下面以Android Studio为例进行开发。
首先搭建开发环境:
ARCore 不支持 Android Emulator 等虚拟设备,满足要求的设备除了要开启大家所熟知的开发者模式之外,还需要提前安装arcore-preview.apk,提供基础的ARCore Service,安装成功之后会在系统应用里面显示出Tango Core的提示,表示安装成功。
同时利用Android Studio可以反编译查看arcore-preview.apk的结构
根据对so包文件名称猜测,这个apk才是ARCore的核心,供应用中的jni接口调用。在 Android Studio 中,找到 /samples/java_arcore_hello_ar,并打开 HelloAR 示例项目,主要依赖文件有arcore_client.aar和obj-0.2.1.jar
编译项目并在设备上运行,打开相机权限,移动拍摄位置,会出现很多星点,经过计算之后会识别出平面位置,点击平面会放置绿色的安卓logo,效果图如下。
在普通手机上运行该项目,会直接弹出“This device does not support AR”的提示,然后就闪退了,连app里面什么样子都看不见,支持ARCore的官方推荐手机都是5000元以上的高端机,像我这种手持低端机的开发者也想看看app运行的样子,感谢github上大神提出的arcore-for-all这种简单易用的方法修改依赖文件,虽然不能从根本上解决问题,但还是可以绕过手机类型判断这一步。
java -jar /xxxxxx/cfr.jar SupportedDevices.class > SupportedDevices.java
public static boolean isSupported(Context context) {
try {
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 128);
int n = applicationInfo.metaData.getInt("com.google.ar.version.major");
int n2 = applicationInfo.metaData.getInt("com.google.ar.version.minor");
int n3 = 0;
int n4 = 0;
if (n > n3) {
Log.e((String)TAG, (String)"Major version of AR Core is too low.");
return false;
}
if (n == n3 && n2 > n4) {
Log.e((String)TAG, (String)"Minor version of AR Core is too low.");
return false;
}
}
catch (PackageManager.NameNotFoundException nameNotFoundException) {
Log.e((String)TAG, (String)"Unexpected error: Packagename of app doing isSupported check should exist.");
}
if (!SupportedDevices.deviceCalibrationAvailable()) {
Log.e((String)TAG, (String)"Device calibration unavailable. ");
return false;
}
return true;
}
private static boolean deviceCalibrationAvailable() {
return Build.FINGERPRINT.contains("sailfish:7") || Build.FINGERPRINT.contains("sailfish:O") || Build.FINGERPRINT.contains("sailfish:8") || Build.FINGERPRINT.contains("marlin:7") || Build.FINGERPRINT.contains("marlin:O") || Build.FINGERPRINT.contains("marlin:8") || Build.FINGERPRINT.contains("walleye:O") || Build.FINGERPRINT.contains("walleye:8") || Build.FINGERPRINT.contains("taimen:O") || Build.FINGERPRINT.contains("taimen:8") || Build.FINGERPRINT.contains("SC-02J/SC-02J:7") || Build.FINGERPRINT.contains("SCV36_jp_kdi/SCV36:7") || Build.FINGERPRINT.contains("dreamqlteue/dreamqlteue:7") || Build.FINGERPRINT.contains("dreamqltesq/dreamqltesq:7") || Build.FINGERPRINT.contains("dreamqlteldusq/dreamqltesq:7") || Build.FINGERPRINT.contains("dreamqltezm/dreamqltecmcc:7") || Build.FINGERPRINT.contains("dreamqltevl/dreamqltecan:7") || SupportedDevices.isSupportedExynosDevice();
}
public static boolean isSupportedExynosDevice() {
return Build.FINGERPRINT.contains("dreamlteldu/dreamlte:7") || Build.FINGERPRINT.contains("dreamlteks/dreamlteks:7") || Build.FINGERPRINT.contains("dreamltexx/dreamlte:7");
}
4 ,编译文件:利用Android SDK中的android.jar文件对java文件进行编译,在当前的SupportedDevices.java文件目录下执行javac -cp /xxxxx/android.jar -source 1.8 -target 1.8 SupportedDevices.java,这里1.8是对应我本地的java 8 版本,因人而异。
5 .打包文件:将得到的SupportedDevices.class文件重新压缩进jar文件中,在classes.jar所在目录下执行jar cvf classes.jar -C classes .,接着在arcore_client.aar所在目录下执行jar cvf arcore_client.aar -C aar_client.
6.生成apk:在Android Studio中build->clean project(新改的依赖包可能会不生效),然后运行安装在其他设备上,经过部分手机的测试,Nexus 6p也可以出现上文展示的效果,logcat中也会展示出09-10 19:59:50.478 866-866/? E/SupportedDevices: Device calibration unavailable.,进入了刚才修改的判断分支中,不过相比较于Pixel和S8,识别速度等会慢一些。而大部分手机虽然可以进入应用,但是只是在底部提示“Searching for surfaces…”,主要的显示区域也是黑屏,并不能使用ARCore的主要功能。上述的github项目中也展示了支持ARCore的手机测试清单,除了官方推荐,其余支持的手机目前只有Nexus 6p和OnePlus 5。
上文中ARCore的三个核心技术在Tango中都有涉及,而且ARCore SDK和so包里面的文件命名都出现了Tango的字眼,由此不难猜测出ARCore其实是在Tango的研发基础上进行的功能改造,Tango一定要达到特定的软硬件标准才能够实现,比如下图是一台Tango手机需要的部分组件
Tango有专用的红外深度感应摄像头,可以创建丰富的3D纹理,直接测量距离。ARCore可以简单理解为检测平坦的表面,然后在上面放置虚拟物体,它并只是对相机反馈数据进行估计。但是苛刻的设备要求、大量OEM产商不合作和用户需求不够强烈等因素使得Tango一直不温不火,于是将Tango的关键部分分离出来,移除了深度相机部分功能,让它适用于普通手机,ARCore就是为了解决这些痛点而存在,不需要严格的特殊硬件,主要从软件方面解决问题。但是毕竟现在还是预览版,能否真正实现Tango未实现的目标还不得而知。
首先了解下ARKit的基础知识。ARKit是一种为iOS构建增强现实的框架,意在实现将虚拟内容精确且真实地浸入真实世界场景上。ARKit框架提供了两种AR技术,一种是基于3D场景(SceneKit)实现的增强现实,一种是基于2D场景(SpriktKit)实现的增强现实。 ARKit的核心是为一些基本的关键功能提供支持,包括运动跟踪,水平面检测,以及环境光预测。
下图是针对两种框架下的官方demo实例对比,左侧是是iPhone 7,右侧是三星S8,分别识别出平面并添加物体,旋转一周,特征点发生明显的变化之后,再次重新定位
比较看来,ARCore和ARKit核心功能点类似,demo中ARCore 在已经支持的设备上追踪性能与ARKit的识别能力十分接近,ARCore在建图和重定位方面具有一些优势,ARKit在集成和跟踪方面具有一定的技术优势,各自都有市场地位,在选择方面主要看开发者的个人偏好。
Google和苹果两大巨头终于在AR领域部署基于系统层面的解决方案,推出了实际的可落实到移动设备上的框架产品,两者强势的竞争势头是众多AR领域开发者的福音,而对于第三方独立AR公司来说可能就是沉重一击,毕竟这两大巨头配套OEM产商垄断了移动端的硬件设备和软件系统,在夹缝中生存的压力可想而知。ARCore和ARKit相爱相杀,不仅提高了AR应用的体验效果,又降低了开发门槛,是不是AR的春天真的来了,让我们拭目以待……
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。