
摘要:在此之前,我们详细分析了ARKit的开发原理。在本文中,我们将讨论ARCore,这是另一个在现场场景中也很实用的工具。
其实我关注ARCore已经有相当长一段时间了,但是一直没有抽出时间写总结。正好应朋友之邀,今天就来好好聊聊ARCore。
ARCore的历史和与苹果ARKit的竞争我就不多说了。你可以在网上找到很多信息。但是网上对ARCore的深入解释并不多。
本文有两个主要目的。一个是给大家介绍一下ARCore的基本概念。理解这些概念对你进一步学习ARCore起着关键作用。二是深入分析ARCore的工作机制,会让大家更容易理解ARCore。
另外,ARCore和ARKit的基本概念非常接近。只要你知道其中的一个,你就基本掌握了另一个。
ARCore的基本概念
ARCore工作时必须做两件事。首先,它跟踪手机的运动,然后它构建对现实世界的理解。
ARCore的运动跟踪技术是通过摄像头识别特征点,并跟踪这些特征点如何随时间移动。ARCore根据这些特征点的运动数据和从手机惯性传感器读取的信息,计算出手机的位置和方向,称之为姿态。
除了识别这些特征点,ARCore还可以检测地板、桌面等平面信息,以及某个地方的光线强度。这些信息使ARCore能够构建他所理解的真实世界。建立了这样的模型之后,就可以在上面放一些虚拟的内容了。
ARCore是怎么做到的?它使用三种关键技术将虚拟内容与现实世界相结合,它们是:
运动跟踪
环境理解
光线评估
运动跟踪
ARCore可以知道手机在运动过程中相对于现实世界的位置和方向(姿态)。
当手机在现实世界中移动时,ARCore使用一种称为并发测距和映射的过程来了解手机与周围世界的相对位置。
ARCore可以检测出摄像机拍摄的图像的不同视觉特征,这些视觉特征称为特征点。它使用这些点来计算它的位置变化。随着时间的推移,ARCore可以通过来自IMU设备的视觉信息和惯性测量来估计相机相对于真实世界的姿态(位置和方向)。
通过将渲染的3D虚拟内容与物理相机的姿态对齐,开发人员可以从正确的角度渲染虚拟内容。然后,通过在从照相机获得的图像上渲染虚拟对象的图像,看起来好像虚拟内容是真实世界的一部分。
环境理解
ARCore允许手机检测水平面的位置和大小。如地板、书桌、书架等。以这种方式,虚拟对象可以被放置在检测到的水平面上。
它是怎么做到的?ARCore通过检测特征点和平面,不断提高对真实世界环境的理解。
ARCore将在常见的水平表面(如桌面)上找到特征点簇。此外,ARCore可以确定每个平面的边界,并向您的应用程序提供上述信息。通过这种方式,开发人员可以使用这些信息,并将虚拟对象放置在平面上。
因为ARCore使用特征点来检测平面,所以它可能无法正确检测没有纹理的平面(如白色桌面)。
光线评估
用户交互
ARCore利用命中测试(hit testing)获得手机屏幕对应的(x,y)坐标(如通过点击屏幕等交互方式),投影到相机的3D坐标系中,返回与命中点光线相交的所有平面和特征点,以及交点在世界坐标系中的姿态。这样,用户就可以在ARCore环境中与对象进行交互。
锚点和跟踪
ARCore可以通过改变对自身位置和环境的认识来调整自己的态度。如果我们要在ARCore环境中放置一个虚拟物体,首先要确定一个锚点,以确保ARCore能够随着时间的推移持续跟踪物体的位置。通常,锚是基于命中测试返回的姿态创建的。
姿势改变是一项关键技术。只有获得了姿态,ARCore才能随着时间不断更新环境物体(如飞机、特征点)的位置。ARCore将平面和点视为可以跟踪的特殊类型的对象。您可以将虚拟对象锚定到这些可跟踪对象,以确保设备移动时虚拟对象和可跟踪对象之间的稳定关系。这就像在桌面上放置一个虚拟花瓶。如果ARCore稍后调整与桌面相关的姿态,花瓶仍将保留在桌面上。
ARCore核心类简介
会议
Com.google.ar.core.Session类,Session管理ar系统的状态,处理Session的生命周期。这个类是ARCore API的主要入口点。该类允许用户创建会话、配置会话、启动/停止会话,最重要的是,接收文章帧以允许访问摄像机图像和设备手势。
配置
该类用于保存会话的设置。
基本框架
Com.google.ar.core.Frame类,通过调用update()方法获取状态信息并更新ar系统。
点击结果
Com.google.ar.core.HitResult类,它定义了命中点光线和估计的真实几何世界的交集。
要点
Com.google.ar.core.Point类,表示ARCore正在追踪的空间点。它是在创建锚点(调用createAnchor方法)或检测到点击(调用hitTest方法)时返回的结果。
点云
Com.google.ar.core.PointCloud类,包含一组观察到的3D点和置信度值。
飞机
Com.google.ar.core.Plane类,描述现实世界中飞机表面的最新信息。
锚
Com.google.ar.core.Anchor类,描述现实世界中固定的位置和方向。为了保持物理空间的固定位置,这个位置的数字描述信息会随着ARCore对空间理解的不断完善而更新。
姿态
手势表示从一个坐标空间到另一个坐标空间的位置不变的变换。在所有ARCore API中,手势总是描述从对象的局部坐标空间到世界坐标空间的变换。
随着ARCore对环境的理解发生变化,它会调整坐标系模式,与现实世界保持一致。此时,摄像机和定位点的位置(坐标)可能会发生明显的变化,从而使它们所代表的对象能够处理适当的位置。
这意味着每一帧图像都应该被认为是在一个完全独立的世界坐标空间中。不应在渲染帧之外使用锚点和相机的坐标。如果有必要考虑某个位置超出了单个渲染帧的范围,则应该创建一个锚点,或者使用相对于附近现有锚点的位置。
图像元数据
Com。Google.ar.core.imagemetadata类,提供对相机图像捕捉结果的元数据的访问。
光照估计
Com。google.ar.core.lightestimate存储了真实场景光照的预估信息。通过getLightEstimate()获取。
个案分析
Google发布的ARCore SDK包含了一些示例程序。有了以上的基础知识,我们就很容易理解他写的演示程序的流程了。
创建会话和配置
这是在Activity的onCreate方法中创建会话和配置的好地方。
m Session=new Session(this);mDefaultConfig=config . createdefaultconfig();如果(!m session . is supported(mDefaultConfig)){ Toast . make text(This,'此设备不支持AR 'Toast。长度_长)。show();finish();返回;}
Session:是ARCore的管理类,非常重要。ARCore的开合,文章帧采集等等都是通过它来管理的。
Config:存储一些配置信息,比如平面搜索模式,光照模式等等,这些都记录在这个类中。目前这种比较简单,里面东西不多。
IsSupported:该方法主要控制SDK的版本和型号。目前政府只支持谷歌和三星的几款机型进行测试。其他型号还不支持ARCore。当然,有些机型可以通过破解的SDK使用ARCore。不使用此方法中的Config参数。
为AR演示创建GLSurfaceView
在谷歌提供的演示中,AR的显示部分使用了GLSurfaceView。做文章开发的同学都知道Android可以用三视图进行文章渲染。它们是:
表面视图
GLSurfaceView
TextureView
其中SurfaceView最为灵活高效,但使用起来比较麻烦。GLSurfaceView比SurfaceView简单多了,只需要实现它的Render接口就可以了。TextureView最好用,很多工作都是Android窗口管理器帮你做的,但是灵活性比较差。
为了高效渲染,Google在Demo中大量使用OpenGL技术。因为OpenGL是一个非常大的图像处理领域,不是一两篇文章就能讲清楚的,也不是我们论文的重点,这里就不详细介绍了,有兴趣的同学可以自己上网学习。
mSurfaceView=(GL surface view)findViewById(r . id . surface view);msurfaceview . setpreserveeglcontextonpause(true);msurfaceview . seteglcontextclientversion(2);msurfaceview . seteglconfigchooser(8,8,8,8,16,0);//Alpha用于平面blending . msurfaceview . set renderer(this);msurfaceview . setrendermode(GLSurfaceView。render mode _ CONTINUOUSLY);
这段代码首先通过资源文件创建一个GLSurfaceView对象,然后将GLSurfaceView与EGL上下文相关联。并将活动作为GLSurfaceView的回调对象(也就是说,活动要实现GLSurfaceView中定义的接口。渲染器,如onSurfaceCreated、onSurfaceChanged、onDrawFrame等。).最后将mSurfaceView的渲染模式设置为GLSurfaceView。Rendermode _ continuously,即连续渲染glsurfaceview。
创建各种线程
要理解这一节,首先要详细了解AR是如何工作的。这里给大家简单解释一下。
背景显示
用过AR的人都知道,AR是把一些虚拟的物体放到真实的场景中。那么这个真实场景是从哪里来的呢?当然是从手机的摄像头获取的。
我们使用从摄像机获得的文章作为AR的背景。AR其实就是把虚拟物体放到文章上,但不是简单的摆放,而是需要大量的计算,找到文章中的平面位置,然后摆放。
Android中的文章采集比较简单,比如文章系统和摄像头。
平台检测
上面我们说过,AR是实时文章虚拟物体。然而,虚拟对象不能简单地放在文章上。而是先检测文章中的每一帧,找到文章中的平面,再放置虚拟物体。这是AR:)
点云
上面我们知道,AR=实时文章平面虚拟物体。此外,它还应该能够跟踪虚拟物体,即可以从不同角度观察同一个物体,得到不同的姿态,所以有了“点云”技术。那么什么是点云呢?顾名思义,形象的说就是一堆点,有点像云。点云中的每一个点都是一个特征点,由相机获取。
放置虚拟对象
找到了平面和追踪手段,就可以把准备好的虚拟物体放到平台上,现在就是真正的Arha了。
好了,知道了这些基本原理之后,我们来看看Google Demo是怎么做的。
创建线程
对于上面的每一点,Demo用下面的代码启动一个线程:
.//创建纹理,并将其传递给阿尔科尔会话,以便在更新期间进行填充()mbackgroundrenderer。createonglthread(this);m会话。setcameratexturename(mbackgroundrenderer。gettextureid());//准备其他渲染对象,请尝试{ mvirtualobject。createonglthread(this,' andy.obj '' andy。png’);mvirtualobject。setmaterialproperties(0.0f,3.5f,1.0f,6.0f);} catch (IOException e) { Log.e(TAG,读取目标文件文件失败');}试试{ mplanerenderer。createonglthread(this,' trig rid。png’);} catch (IOException e) { Log.e(TAG,读取平面纹理失败');} mpointcloud。createonglthread(this);
上面的代码中首先创建了一个背景线程,用来将从照相机中获取的文章渲染到屏幕上当背景。数据是从哪里来的呢?就是通过会话。更新获取照相机数据,再通过纹理交给背景线程。
对纹理没有概念的同学可以把它想像成一块内存空间。
然后启动虚拟物品线程,用于绘制虚拟物品,及发生角度变化时,更新虚拟物别的姿势。紧接着创建平面线程来绘制平面。最后启动点云线程绘制特征点。
到此,各种线程就创建完毕了。下面我们来说一下如何渲染。
命中检测与渲染
命中检测
当我们要向背景绘制虚拟物品时,首先要进行命中检测。代码如下:
运动事件tap=mquedsingletaps。poll();如果(轻点!=空框架。gettrackingstate()==跟踪状态.跟踪){ for(命中结果命中:帧。hittest(点击)){//检查是否击中了任何平面,以及是否击中了平面多边形内部if(hit PlaneHitResult的实例((PlaneHitResult)hit).isHitInPolygon()) { //限制创建的对象数量。这避免了//渲染系统和阿尔科尔过载.如果(m触及。size()=16){ m会话。移除锚点(数组。如列表(m触摸。get(0)).getAnchor()));m touches。删除(0);} //添加锚点告诉阿尔科尔它应该在//空间中跟踪这个位置。该锚点将在飞机附件中用于将三维(three dimension的缩写)模型//放置在相对于世界和平面的正确位置mTouches.add(新的平面附件((PlaneHitResult)命中).getPlane()、m会话。添加锚点(点击。gethitpose()))));//命中按深度排序。只考虑飞机上最近的命中。打破;} }}
在例子中,它查看是否有点击事件,且图像处理于跟踪状态?如果是,就对其进行命中检测,看是否可以找到一个平面,如果找到就创建一个锚点并将其与该平台绑定起来。
渲染背景
//绘制背景。mbackgroundrenderer。绘制(帧);
通过上面的代码就可以将纹理中的内容推给EGL,上面创建的渲染线程从EGL上下文中获取数据,最终将文章渲染到屏幕上。
绘制点云
mpointcloud。更新(框架。getpointcloud());mpointcloud。画(框。getpointcloudpose()、viewmtx、proj MTX);
同理,通过上面的代码,就可以将数据传给点云线程进行点云的绘制。
绘制平面
//可视化平面。mplanerenderer。画平面(m会话。获取所有平面()、frame.getPose()、proj MTX);
通过上面代码将数据传给平面线程进行平面的绘制。
绘制虚拟物品
for(平面附件平面附件:m touches){ if(!平面附件。正在跟踪()){继续;} //获取锚点和平面在世界空间中的当前组合姿态。在调用会话.更新()的过程中,随着阿尔科尔优化//其对世界的估计,锚点//和平面姿态会更新planeAttachment.getPose().toMatrix(mAnchorMatrix,0);//更新并绘制模型及其阴影mvirtualobject。updatemodelmatrix(mAnchorMatrix,比例因子);mvirtualobjectshadow。updatemodelmatrix(mAnchorMatrix,比例因子);}
最后,遍历所有的锚点,在每个锚点上绘制虚拟物品。
至此,我们对阿尔科尔的分析就告一段落了。
小结
ARCore对于初学者来说还是比较难的。因为有很多新概念需要大家消化吸收。
另一方面,ARCore能测试的型号很少,而且这些型号在国内用的人也不多,大部分人不可能做实验,这也增加了学习的难度。
除了以上两点,ARCore使用了很多OpenGL的相关知识。而OpenGL是一门很深的学问,所以学习难度就更陡了。
通过以上三点,可以说目前学习ARCore的门槛比苹果的ARKit要难很多。









