接触过opengl的同窗应该很容易知道,opengl最大的特色就是模拟真实视角以及渲染场景模型,java
美颜相机
,包括
抖音
的一些变脸特效, 他们的作法是==(以Android平台为例)==经过Camera获取图像,并对经过识别算法捕捉到特定部位, 用特殊设计的矩阵算法进行变换,好比拉伸、挤压等, 而后把==处理事后的图像== 以贴图的方式呈如今屏幕上。 固然图像并非简简单单得直接像平时开发同样
imageview.setImage(...)
复制代码
由于要考虑到物体自己坐标、世界坐标、视图坐标 等,因此要进行转换才能最终对应到屏幕中的坐标,由于摄像头的姿式一直在变。摄像头每一次变动,图像跟着转换,就好像真的是经过摄像头在观察真实世界。android
因此,google是聪明的,它利用 opengl的生态来发展本身的生态,==几乎全部能在opengl es上应用的库、模型,均可以直接拿来使用==, 只不过要换成ARCore本身的视图矩阵转换。git
再者,绝不夸张得说, 若是有人说 ==ARCore(android)是opengl es的一个库==,Android原生开发者应该无言以对吧。====github
ARCore经过特征点识别,可以鉴别出纹理平面、位置、光线等, 这里暂时只考虑平面识别。 获得平面信息(无论是哪一个朝向,上平面OR下平面),平面是有姿态和边界的,平面是一个可跟踪对象, 能够在平面上建立Anchor,这是咱们用来标定具体对象的位置信息,能够把平面想象成桌子,能够在桌子上听任何像放的东西, 好比放一个苹果
,苹果的位置必须由平面提供接口建立, 由于它和桌子保持相对性,这里的Anchor
至关于苹果的抽象,由于Anchor
只是包含世界坐标的信息和姿态并不表明具体物体, 咱们能够把Anchor的坐标姿态信息应用到具体物体上(如 苹果
), 那么苹果就会出如今桌子上。 ==opengl es==就是利用Anchor
信息来在真实世界中放置本身的模型,模型叠加在真实世界视图中,这就是加强现实。算法
光有Anchor还不够, 上面的Anchor只是物体自己位置信息, 并无考虑到 摄像头、投影等因素, 其实这和opengl里是同样的, 物体自己的坐标要通过 视图矩阵==ViewMatrix==和投影矩阵==ProjectionMatrix==的转换才能最终转换成==屏幕坐标==, 这些信息ARCore也会提供,除此以外还会提供 ==光照信息==、==摄像头姿态==等api
这些信息之前其实都是由opengl 本身产生指定, 如今变动为由ARCore提供而已。session
前面说过 运动跟踪
是他的特色之一, 意思就是你在摄像头的当前位置方式一些物体 镜头位置转移,再回来的时候物体还在, 这就是他对环境的理解对物体的跟踪。app
接触过Android中指纹Api的人应该知道, 6.0以前虽然各厂商都有指纹支持,可是并无统一Api,若是硬是要作,只能判断具体机型,调用对应Api。ide
所以不少大厂致力于这些事情,好比联想的Fido指纹库, 原理是和每个手机厂商合做,厂商会提供特定的api给联想去调用, 因此合做的厂商在手机出厂时会有预置的 APK, Android app开发者利用联想提供的jar来实现和内置apk以及手机底层通讯,开发者就能够把关注点从繁琐的适配中转移到Fido的使用上。post
google也是这个策略, 可是也有不一样的地方, 不一样在于,他并无预置应用在厂商手机上, 而是在特定时候才会去下载该特殊apk
(后面会详细说明),至于为何要采起这个作法,后面能够探讨 [^preLoad], 因此一个设备不光须要这歌特殊的apk
一样也须要厂商的接口支持。
apk
今天4月初的时候,ARCore release了1.1版本, 相对于以前版本改动点不是特别多,可是提供了 特殊apk
,开发者能够在支持ARCore的手机上安装它(考虑到墙的问题,某些开发者没法从google商店获取),或者安装在 ==3.1 Studio==的模拟器上。
目前google正和国内华为、小米、 魅族等各大厂商进行合做, 4月初的时候,小米上架了特殊apk
==ARCore== 被我逮到了,不过还处在试验期,不支持下载,还无聊得举报了一下。
implementation 'com.google.ar:core:1.0.0'
复制代码
google把ARcore应用分为两类,==AR Required== 或者 ==AR Optional==,what?
==AR Required==
意味着您的应用在没有AR的状况下不可用。Play商店仅在支持ARCore的设备上提供您的应用。
当用户安装AR需求应用时,Play商店将自动安装ARCore。可是,若是用户卸载了ARCore ,您的应用仍然必须执行其余运行时检查。
复制代码
<uses-sdk android:minSdkVersion = “ {24或更高版本}“ />
...
<uses-feature android:name = ”android.hardware.camera.ar“ android:required = ”true“ />
<application> ...
<meta-data android:name = ”com.google .ar.core“ android:value = ”required“ />
复制代码
==AR Optional==
您的应用程序包含一个或多个AR功能,若是用户的设备支持ARCore,则会激活该功能。可是该应用程序能够在不支持ARCore的设备上安装和运行。
当用户安装AR可选应用程序时,Play商店不会自动安装ARCore。
要将您的应用做为AR可选,须要修改menifest以包含如下条目:
<uses-sdk android:minSdkVersion = “ {14或更高版本}“ />
...
<application>
...
<meta-data android:name = ”com.google.ar.core“ android:value = ”optional“ />
...
复制代码
宿主Activity实现GLSurfaceView.Renderer接口
public class MainActivity extends AppCompatActivity implements GLSurfaceView.Renderer{
//初始化opengl的一些参数,例如初始化着色器
void onSurfaceCreated(GL10 gl, EGLConfig config){}
//接收视口的变化,在传统opengl应用中若是涉及到Camera,能够设置
//projection matrix
void onSurfaceChanged(GL10 gl, int width, int height){}
//具体渲染的地方,在ARCore中会按必定频率被调用,
//这个方法中咱们能够获取摄像头信息、投影/视图矩阵信息、光照信息等
void onDrawFrame(GL10 gl){}
}
复制代码
初始化画布而且设置上面的Render接口
// Set up renderer.
surfaceView.setPreserveEGLContextOnPause(true);
surfaceView.setEGLContextClientVersion(2);
surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
surfaceView.setRenderer(this);
surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
复制代码
在展现咱们ARCore相关UI元素以前,咱们须要检查当前设备是否支持,不然Session会建立失败。
void maybeEnableArButton() {
// Likely called from Activity.onCreate() of an activity with AR buttons.
ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
if (availability.isTransient()) {
// re-query at 5Hz while we check compatibility.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
maybeEnableArButton();
}
}, 200);
}
if (availability.isSupported()) {
mArButton.setVisibility(View.VISIBLE);
mArButton.setEnabled(true);
// indicator on the button.
} else { // unsupported or unknown
mArButton.setVisibility(View.INVISIBLE);
mArButton.setEnabled(false);
}
}
复制代码
因为该检查方式会启用远程服务查询,因此无论设备是否支持都会当即返回UNKNOWN_CHECKING, 因此要循环查询,但不会重复请求查询服务,只是获取查询结果, 上段代码中:
if (availability.isTransient())
复制代码
该方法返回true表示当前状态知识临时状态,也就是说查询服务尚未返回,你应该继续去捞结果, 直到 返回 ==SUPPORTED== 或者 ==UNSUPPORTED==,大体流程以下图:
上面咱们说过,一个设备可否使用ARCore,有两个条件,==设备自己支持== 和 ==安装了特殊apk(ARCore)== 所以,咱们还须要检查==是否安装了ARCore==
// Set to true ensures requestInstall() triggers installation if necessary.
private boolean mUserRequestedInstall = true;
// in onResume:
try {
if (mSession == null) {
switch (ArCoreApk.getInstance().requestInstall(this, mUserRequestedInstall)) {
case INSTALLED:
mSession = new Session(this);
// Success.
break;
case INSTALL_REQUESTED:
// Ensures next invocation of requestInstall() will either return
// INSTALLED or throw an exception.
mUserRequestedInstall = false;
return;
}
}
} catch (UnavailableUserDeclinedInstallationException e) {
// Display an appropriate message to the user and return gracefully.
return;
} catch (...) { // current catch statements
...
return; // mSession is still null
}
复制代码
也许有人困惑第2
行的变量有什么用,我也困惑了一顿饭的时间,先不急,咱们先看看上面代码对应的流程图:
INSTALL_REQUESTED
何时返回
exception
, 这就取决于代码中第
2
行的变量啦, 若是为
false
时,系统则认为你已经提示过用户安装了,所以会跑出一个异常,这时候你能够简单得
Toast
提示, 为
true
时会引导用户去各市场下载==ARCore==, 固然目前只有google市场,其余厂商的市场还在商谈中。
前面说过,渲染请求都是在public void onDrawFrame(GL10 gl)
发起的,在这个方法里咱们能够获取 sdk提供给咱们的信息传递给==opengl es==进行渲染
//session是在上文建立的ARCore回话,是贯穿于整个宿主Activity生命周期的
session.setCameraTextureName(backgroundRenderer.getTextureId());
//获取到当前帧的信息
Frame frame = session.update();
//获取Camera对象,Camera对象有咱们所须要的绝大部分渲染信息
Camera camera = frame.getCamera();
//这个就是投影矩阵
float[] projmtx = new float[16];
camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);
//这个就是视图矩阵
float[] viewmtx = new float[16];
camera.getViewMatrix(viewmtx, 0);
//光照信息
final float lightIntensity = frame.getLightEstimate().getPixelIntensity();
//pikaqiuRender是我定义的opengl的渲染类,把这三个要素丢给opengl es其实就没有ARCore啥事了,
//其他工做就交给opengl es了
pikaqiuRender.draw(viewmtx, projmtx, lightIntensity);
复制代码
因为ARCore检测以及opengl es渲染实在是太耗资源了, 个人mac开启ARCore应用,小风扇就直接转起来了,实在太恐怖, 因此在没必要要的时候尽可能避免渲染,这里要特别提醒的是,注意 ==session== 和 ==surfaceView== 的次序。
@Override
protected void onPause() {
super.onPause();
if (session != null) {
// Note that the order matters - GLSurfaceView is paused first so that it does not try
// to query the session. If Session is paused before GLSurfaceView, GLSurfaceView may
// still call session.update() and get a SessionPausedException.
displayRotationHelper.onPause();
surfaceView.onPause();
session.pause();
}
}
复制代码
@Override
protected void onResume() {
super.onResume();
if(session == null){
checkAndInitSession();
}
showLoadingMessage();
try{
session.resume();
}catch (CameraNotAvailableException e){
Log.d(TAG, "CameraNotAvailableException");
e.printStackTrace();
}
surfaceView.onResume();
displayRotationHelper.onResume();
}
复制代码
模型没有添加灯光参数, 添加灯光后会更加真实一点
普及篇就写到这里了,你们若是感兴趣的话后面能够针对官方demo以及api作一些解读
[^IMU]: IMU, 惯性测量单元 (Inertial measurement unit , 能够经过这个视频直观得感觉下
[^preload]: 不采用预置方法,可能有两个缘由: 1. 特殊apk
能够被卸载,一旦卸载手机则没法支持ARCore,2. 采用特殊时机下载的方式,能够防止这种状况,而且支持升级。