文章:

  1. AR尺子--简介
  2. AR尺子--预览

效果:预览并渲染数据

目录:

1. 前序

本篇文章较长,目的是可以在手机中预览数据。希望读者能够认真读下去。不管你是刚接触ARCore以及OpenGL的 程序员。还是马上要毕业,把该项目拿来用作毕设的学生。我相信只要你能坚持下去,一定会对你有所帮助。 该文章代码较多。部分解释都集中在代码的注释中。在最后还有项目的GitHub地址。希望大家耐着性子看下去。我会尽量写的详细,希望能帮到大家。当然也算是自己对知识的一种积累。

2. 集成ARCore

1. 向 manifest 添加 AR 选项。并声明Camera权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.jtl.arcoredemo">//声明Camera权限<uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity>//添加AR选项,在启动应用时会判断是否安装了ARCore<meta-data android:name="com.google.ar.core" android:value="required" /></application></manifest>复制代码
2. 添加依赖库
android {...//要求JDK 1.8compileOptions {sourceCompatibility 1.8targetCompatibility 1.8}
}
//在APP Gradle中添加ARCore的依赖库(截至2019.5.4,最新版本为1.8.0)
dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support:appcompat-v7:28.0.0'implementation 'com.android.support.constraint:constraint-layout:1.1.3'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test:runner:1.0.2'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'implementation "com.google.ar.sceneform:core:1.8.0"
}
复制代码
3. 请求摄像机权限

这里引入一个PermissionHelper类

/*** 权限帮助类*/
public final class PermissionHelper {private static final int CAMERA_PERMISSION_CODE = 0;private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;/*** 是否有相机权限* @param activity* @return*/public static boolean hasCameraPermission(Activity activity) {return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)== PackageManager.PERMISSION_GRANTED;}/*** 请求相机权限* @param activity*/public static void requestCameraPermission(Activity activity) {ActivityCompat.requestPermissions(activity, new String[]{CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);}/*** 展示申请权限的相应解释* @param activity* @return*/public static boolean shouldShowRequestPermissionRationale(Activity activity) {return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);}/*** 打开设置界面** @param activity*/public static void launchPermissionSettings(Activity activity) {Intent intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);intent.setData(Uri.fromParts("package", activity.getPackageName(), null));activity.startActivity(intent);}}
复制代码

在Activity中做相应的权限申请操作

    @Overrideprotected void onResume() {super.onResume();// ARCore 申请相机权限操作if (!PermissionHelper.hasCameraPermission(this)) {PermissionHelper.requestCameraPermission(this);return;}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {if (!PermissionHelper.hasCameraPermission(this)) {Toast.makeText(this, "该应用需要相机权限", Toast.LENGTH_LONG).show();//弹出相应解释if (!PermissionHelper.shouldShowRequestPermissionRationale(this)) {// 直接跳至设置 修改权限PermissionHelper.launchPermissionSettings(this);}finish();}}
复制代码

3. 初识Session

1. 什么是Session:

Session也称为会话,是ARCore最核心的一个类。他可以获取相机数据。并算出相应的锚点信息以及视矩阵投影矩阵等。这里的部分内容会在后面进行具体叙述。

2. 初始化Session

首先判断设备是否支持ARCore

@Overrideprotected void onResume() {super.onResume();// ARCore 申请相机权限操作...Exception exception =null;String msg =null;//初始化Sessionif (mSession==null){try {//判断是否安装ARCoreswitch (ArCoreApk.getInstance().requestInstall(this,!isInstallRequested)){case INSTALL_REQUESTED:isInstallRequested=true;break;case INSTALLED:Log.i(TAG,"已安装ARCore");break;}mSession=new Session(this);} catch (UnavailableArcoreNotInstalledException| UnavailableUserDeclinedInstallationException e) {msg = "Please install ARCore";exception = e;} catch (UnavailableApkTooOldException e) {msg = "Please update ARCore";exception = e;} catch (UnavailableSdkTooOldException e) {msg = "Please update this app";exception = e;} catch (UnavailableDeviceNotCompatibleException e) {msg = "This device does not support AR";exception = e;} catch (Exception e) {msg = "Failed to create AR session";exception = e;}//有异常说明不支持或者没安装ARCoreif (msg != null) {Log.e(TAG, "Exception creating session", exception);return;}}//该设备支持并且已安装ARCoretry {//Session 恢复resume状态mSession.resume();} catch (CameraNotAvailableException e) {Log.e(TAG, "Camera not available. Please restart the app.");mSession = null;return;}}
复制代码
3. 开始或恢复Session(会话)
@Overrideprotected void onResume() {super.onResume();// ARCore 申请相机权限操作...Exception exception =null;String msg =null;//初始化Sessionif (mSession==null){//判断是否支持ARCore...}//该设备支持并且已安装ARCoretry {//Session 恢复resume状态mSession.resume();} catch (CameraNotAvailableException e) {Log.e(TAG, "Camera not available. Please restart the app.");mSession = null;return;}}
复制代码
4. 暂停关闭Session(会话)
    @Overrideprotected void onPause() {super.onPause();if (mSession!=null){mSession.pause();}}@Overrideprotected void onDestroy() {super.onDestroy();if (mSession!=null){mSession.close();}}
复制代码

4.OpenGL渲染

1. 简单介绍:

首先这里只是简单介绍一下OpenGL,具体的会在后面进行具体叙述。 OpenGL是一个渲染协议。很多渲染引擎底层就是用OpenGL实现的。现在的移动手机都是用的OpenGL ES2.0,几乎涵盖了所有的苹果和Android手机。Android上有个叫做GLSurfaceView的控件。就是Google已经封装好的一个渲染控件。它的底层API都是Google 封装好的native方法,也就是俗称的JNI方法。他需要实现一个Render接口。这个接口有三个回调方法。每一个GLSurfaceView都会有一个相对应的GL线程,专门用来绘制。每个GL线程都有相应的resume和pause方法。用来resume绘制和pause绘制。

2. GLSurfaceView

xml布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><android.opengl.GLSurfaceViewandroid:id="@+id/gl_main_show"android:layout_width="0dp"android:layout_height="0dp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"/></android.support.constraint.ConstraintLayout>
复制代码

初始化

public class MainActivity extends AppCompatActivity implements GLSurfaceView.Renderer {//用来使Session能够根据手机横竖屏,输出相应分辨率的数据private DisplayRotationHelper mDisplayRotationHelper;private GLSurfaceView mShowGLSurface;//初始化相应数据private void initData(){mShowGLSurface=findViewById(R.id.gl_main_show);mDisplayRotationHelper=new DisplayRotationHelper(this);// Set up renderer.mShowGLSurface.setPreserveEGLContextOnPause(true);mShowGLSurface.setEGLContextClientVersion(2);//OpenGL版本为2.0mShowGLSurface.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.mShowGLSurface.setRenderer(this);//实现Render接口mShowGLSurface.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//RENDERMODE_CONTINUOUSLY渲染模式为实时渲染。}
}
复制代码

实现 Render接口的三个回调方法

    /*** GLSurfaceView创建时被回调,可以做一些初始化操作* @param gl* @param config*/@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {//设置每一帧清屏颜色 传入参输为RGBAGLES20.glClearColor(0.1f,0.1f,0.1f,1.0f);}/*** GLSurfaceView 大小改变时调用* @param gl* @param width GLSurfaceView宽* @param height GLSurfaceView高*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//改变视口 方便 OpenGLES做 视口变换GLES20.glViewport(0,0,width,height);}/*** GLSurfaceView绘制每一帧调用,此处不在主线程中,而是在GL线程中。* 部分跨线程数据,需要做线程同步。不能直接更新UI(不在主线程)* @param gl*/@Overridepublic void onDrawFrame(GL10 gl) {//清空彩色缓冲和深度缓冲  清空后的颜色为GLES20.glClearColor()时设置的颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);}
复制代码

GLSurfaceView的 resume和pause

@Overrideprotected void onResume() {super.onResume();//ARCore的相应初始化操作...//GLSurfaceView onResumemShowGLSurface.onResume();mDisplayRotationHelper.onResume();}@Overrideprotected void onPause() {super.onPause();if (mSession!=null){//由于GLSurfaceView需要Session的数据。所以如果Session先pause会导致无法获取Session中的数据mShowGLSurface.onPause();//GLSurfaceView onPausemDisplayRotationHelper.onPause();mSession.pause();}}复制代码
3. 渲染数据

这里引入了一个BackgroundRenderer。它才是抽离出来的真正的用来渲染的类。具体写法以及用途将在下一章介绍。

  private BackgroundRenderer mBackgroundRenderer;/*** GLSurfaceView创建时被回调,可以做一些初始化操作* @param gl* @param config*/@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {//设置每一帧清屏颜色 传入参输为RGBAGLES20.glClearColor(0.1f,0.1f,0.1f,1.0f);mBackgroundRenderer=new BackgroundRenderer();mBackgroundRenderer.createOnGlThread(this);}/*** GLSurfaceView 大小改变时调用* @param gl* @param width GLSurfaceView宽* @param height GLSurfaceView高*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//方便 OpenGLES做 视口变换GLES20.glViewport(0,0,width,height);mDisplayRotationHelper.onSurfaceChanged(width,height);}/*** GLSurfaceView绘制每一帧调用,此处不在主线程中,而是在GL线程中。* 部分跨线程数据,需要做线程同步。不能直接更新UI(不在主线程)* @param gl*/@Overridepublic void onDrawFrame(GL10 gl) {//清空彩色缓冲和深度缓冲  清空后的颜色为GLES20.glClearColor()时设置的颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);if (mSession==null){return;}//设置纹理IDmSession.setCameraTextureName(mBackgroundRenderer.getTextureId());//根据设备渲染Rotation,width,height。session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight);mDisplayRotationHelper.updateSessionIfNeeded(mSession);try {Frame frame=mSession.update();//获取Frame数据mBackgroundRenderer.draw(frame);//渲染frame数据} catch (CameraNotAvailableException e) {e.printStackTrace();}}
复制代码

5. GitHub地址

  1. ARRuler 本教程版本
  2. ARRuler 已完成版
  3. 简书地址
  4. 掘金地址

6. 后续:

这里的ARCore调用逻辑,来源Google官方的ARCore示例。 渲染部分的代码,有的没说清的,后续都会补上。OpenGL的知识会很难。估计我要写一阵了。如果有大神看到这篇文章中的错误,烦请及时指出。希望大家能共同进步,各位感兴趣的加油吧!

转载于:https://juejin.im/post/5ccdb8d3f265da03a1583c1c

手把手带你写AR应用--AR尺子预览相关推荐

  1. 手把手带你写AR应用--AR尺子简介

    文章: AR尺子--简介 AR尺子--预览 概要: 苹果推出ARKit之后.Google相继也推出了ARCore.但相对应的苹果在iPhone中都预装了AR尺子.但是Android手机中,用到ARCo ...

  2. 手把手带你写一个JavaScript类型判断小工具

    业务写了很多,依然不是前端大神,我相信这是很多'入坑'前端开发同学的迷茫之处,个人觉得前端职业发展是有路径可寻的,前期写业务是一个积累过程,后期提炼总结,比如编程思想,父子类的原型继承,还是对象之间的 ...

  3. 【NLP】Pyhon+讯飞开放平台:​手把手带你写一个智能语音播报系统

    手把手带你写一个智能语音播报系统. 微信扫码登陆讯飞开放平台:https://www.xfyun.cn/ 完成个人认证. 在控制台创建应用,注意应用名称全库查重,很容易跟别人重复. 可查看到pytho ...

  4. 手把手带你写米课官网

    手把手带你写米课官网 人生没有白走的路,每一步都算数,大家好,我是小王,今天,手把手教你写一个米课官网原创不易,希望大家多多支持! 需要源代码或者素材的评论区留言.大家记得关注我哦!我会不定期的跟大家 ...

  5. Python老司机手把手带你写爬虫,整站下载妹子图,一次爽个够!

    其实很多编程语言都可以做爬虫,例如java.c#.php等等甚至excel都可以抓网页的图表,那么为什么我们要用Python呢?它简单.便捷,而且有好多库可以选择,可以说python是写爬虫的首选了! ...

  6. 手把手带你写一个 Vue3 的自定义指令

    背景 众所周知,Vue.js 的核心思想是数据驱动 + 组件化,通常我们开发页面的过程就是在编写一些组件,并且通过修改数据的方式来驱动组件的重新渲染.在这个过程中,我们不需要去手动操作 DOM. 然而 ...

  7. Android CameraX的PreviewView Ar背景实景实时预览

    经常在AR开发过程中有这种需求:需要实时预览实景视频,如下图所示. 代码实现思路使用Android CameraX的PreviewView来实现,下面试代码,仅包含视频预览部分: 一.activity ...

  8. 厉害了,手把手教你搭建一个代码在线编辑预览工具

    点击下方"前端开发博客",选择"设为星标" 回复"2"加入前端群 简介 大家好,我是一个闲着没事热衷于重复造轮子的不知名前端,今天给大家带来 ...

  9. 使用FreeMarker生成word文档(带图片),word转pdf,预览pdf,pdf下载工具类

    一.下载或配置: 下载jar包 :freemaker的jar包下载 下载jar包 :aspose-words的jar包下载 或者配置maven依赖: pom.xml添加aspose的依赖包(maven ...

最新文章

  1. 一键清理 Nexus 中无用的 Docker 镜像
  2. Curl中的参数知多少
  3. linux 5 防火墙,CentOS 5 Linux iptables防火墙的配置
  4. 我的csdnmark
  5. 玩转数据结构从入门到进阶五
  6. 【控制】如何入门现代控制理论
  7. Python中的split,rsplit,splitlines
  8. 写cookies注意事项
  9. 关于异常的合理处理方式
  10. php $表达式,PHP表达式概念及实例详解
  11. 【肌电信号】基于matlab GUI脉搏信号处理系统【含Matlab源码 1062期】
  12. Android MTK Metadata Configuration
  13. Mysql 纵表转换为横表
  14. Ramp Number
  15. 如何根据vin码查询_车架号查询-VIN查询-车辆识别码查询-宜配网
  16. 第一课 大数据技术之Fink1.13的实战学习-部署使用和基础概念
  17. NS3 仿真系列资料大全
  18. python3调用新浪微博API 报HTTP Error 403: Forbid、400 Bad Request错误
  19. 王文京一把抓住ASP
  20. JSD-2204-WebServer(项目)-Day14

热门文章

  1. 云快充协议 - 共享充电桩平台APP
  2. python二级证书含金量排名_计算机二级证书含金量有多高?这些用处很多人都不知道!...
  3. 音视频下载Chrome插件 官方主页
  4. 【Unity优化篇】 | Unity脚本代码优化策略,快速获取 游戏对象 和 组件 的方法【文末送书】
  5. Linux驱动入门(四)非阻塞方式实现按键驱动
  6. ARM9串行通信里面的 nRTS 和nCTS是什么意思?
  7. 装饰者模式(通俗易懂)
  8. Eclipse Android项目 为控件添加了Id,但是在Java代码中提示xxx cannot be resolved or is not a field
  9. Python 用户输入和while循环
  10. 热身:go语言windows gui界面开发之walk 改错