[关闭]
@zyl06 2017-10-22T12:38:17.000000Z 字数 6596 阅读 1538

Vuforia demo 简析

Android AR


Vuforia 是高通提供的一款 AR SDK。

简要介绍 UserDefinedTargets 用户自定义目标,实现自定义选择场景并投放模型的功能

gif

1. UserDefinedTargets demo 解析

1.1 初始化

  1. vuforiaAppSession = new SampleApplicationSession(this);
  2. vuforiaAppSession.initAR(this, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

其中 SampleApplicationSession.initAR(Activity activity, int screenOrientation) 方法逻辑如下:

  1. 监听屏幕转向,设置竖屏
  2. 设置 Activity 可见时维持亮屏
  3. 后台线程初始化 Vuforia

    1. Vuforia.setInitParameters(mActivity, mVuforiaFlags, ${VuforiaKey});

    mVuforiaFlags: GL_20,表示使用 OpenGL 初始化

    1. do {
    2. mProgressValue = Vuforia.init();
    3. // Publish the progress value:
    4. publishProgress(mProgressValue);
    5. } while (!isCancelled() && mProgressValue >= 0 && mProgressValue < 100);

    反复调用 Vuforia.init() 直至返回值为 100,表示初始化完成

  4. 主线程初始化跟踪器

    1. // Initialize the image tracker:
    2. TrackerManager trackerManager = TrackerManager.getInstance();
    3. Tracker tracker = trackerManager.initTracker(ObjectTracker
    4. .getClassType());
  5. 加载跟踪器数据(暂时这么描述)

    1. // Get the image tracker:
    2. TrackerManager trackerManager = TrackerManager.getInstance();
    3. ObjectTracker objectTracker = (ObjectTracker) trackerManager
    4. .getTracker(ObjectTracker.getClassType());
    5. ...
    6. // Create the data set:
    7. dataSetUserDef = objectTracker.createDataSet();
    8. ...
    9. // 激活数据集(没理解)
    10. objectTracker.activateDataSet(dataSetUserDef)
  6. 注册 Vuforia 回调

    1. Vuforia.registerCallback(Vuforia.UpdateCallbackInterface object)

    真正实现逻辑如下(后续分析)

    1. public class UserDefinedTargets extends Activity implements
    2. SampleApplicationControl, SampleAppMenuInterface {
    3. ...
    4. @Override
    5. public void onVuforiaUpdate(State state) {
    6. ...
    7. }
    8. ...
    9. }

1.2 设置相机、场景背景等

  1. @Override
  2. public void onInitARDone(SampleApplicationException exception) {
  3. // 初始化 refFreeFrame,mGlView,mRenderer
  4. initApplicationAR();
  5. // 最终调用 Renderer.getInstance().setVideoBackgroundConfig(config); 初始化场景的视频背景
  6. mRenderer.setActive(true);
  7. // 添加 GlView 至场景中
  8. addContentView(mGlView, new LayoutParams(LayoutParams.MATCH_PARENT,
  9. LayoutParams.MATCH_PARENT));
  10. ...
  11. try {
  12. // 设置 CameraDevice 的相关参数,并开启场景帧的跟踪
  13. vuforiaAppSession.startAR(CameraDevice.CAMERA_DIRECTION.CAMERA_DIRECTION_DEFAULT);
  14. } catch (SampleApplicationException e) {
  15. Log.e(LOGTAG, e.getString());
  16. }
  17. // 设置为连续对焦模式
  18. boolean result = CameraDevice.getInstance().setFocusMode(
  19. CameraDevice.FOCUS_MODE.FOCUS_MODE_CONTINUOUSAUTO);
  20. ...
  21. }
  1. initApplicationAR 方法

    1. private void initApplicationAR() {
    2. refFreeFrame = new RefFreeFrame(this, vuforiaAppSession);
    3. // 加载场景中,相机框框的纹理图
    4. refFreeFrame.init();
    5. // 创建 GL 视图,并设置 OpenGL 是否支持透明格式,深度缓存区大小,和模板缓冲区大小
    6. mGlView = new SampleApplicationGLView(this);
    7. mGlView.init(translucent, depthSize, stencilSize);
    8. // 创建自定义渲染器(封装OpenGL渲染相关的代码)
    9. mRenderer = new UserDefinedTargetRenderer(this, vuforiaAppSession);
    10. // 添加之前的初始化绑定的纹理贴图 viewfinder_crop_marks_portrait.png 和 viewfinder_crop_marks_landscape.png
    11. mRenderer.setTextures(mTextures);
    12. // 设置自定义的渲染器
    13. mGlView.setRenderer(mRenderer);
    14. ...
    15. }
  2. vuforiaAppSession.startAR(CameraDevice.CAMERA_DIRECTION.CAMERA_DIRECTION_DEFAULT);

    1. public class SampleApplicationSession implements UpdateCallbackInterface {
    2. ...
    3. public void startAR(int camera) throws SampleApplicationException {
    4. ...
    5. mCamera = camera;
    6. ...
    7. // 初始化 Vuforia 相机设备,参数指定使用正面相机
    8. CameraDevice.getInstance().init(camera);
    9. ...
    10. // 设置相机的视频模式为默认,其他参数有高清、流程
    11. CameraDevice.getInstance().selectVideoMode(
    12. CameraDevice.MODE.MODE_DEFAULT);
    13. ...
    14. // 开启相机设备
    15. CameraDevice.getInstance().start();
    16. ...
    17. // 开启 AR 场景跟踪器
    18. mSessionControl.doStartTrackers();
    19. ...
    20. }
    21. ...
    22. }
    1. @Override
    2. public boolean doStartTrackers() {
    3. ...
    4. Tracker objectTracker = TrackerManager.getInstance().getTracker(
    5. ObjectTracker.getClassType());
    6. if (objectTracker != null) {
    7. result = objectTracker.start();
    8. }
    9. ...
    10. }

1.3 处理页面获取和失去焦点

  1. 获取焦点

    1. @Override
    2. protected void onResume() {
    3. super.onResume();
    4. // 1. 针对 android 设备,设置请求屏幕转向为横向
    5. ...
    6. // 2. 内部调用 Vuforia.onResume(),并尝试开启 Tracker
    7. vuforiaAppSession.resumeAR();
    8. ...
    9. // 3. 调用 GLSurfaceView onResume 方法
    10. if (mGlView != null) {
    11. mGlView.setVisibility(View.VISIBLE);
    12. mGlView.onResume();
    13. }
    14. }
  2. 失去焦点

    1. public void pauseAR() throws SampleApplicationException {
    2. if (mStarted) {
    3. // 1. 停止跟踪器,停止 CameraDevice 运行,并销毁相机对象
    4. stopCamera();
    5. }
    6. //
    7. Vuforia.onPause();
    8. }

1.4 用户点击拍照按钮,构建目标帧

  1. 点击,开始构建目标帧对象

    1. public void onCameraClick(View v) {
    2. // 1. 通过目标跟踪器获取的帧的质量设置是否为 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_NONE 来判断跟踪器是否在运行
    3. if (isUserDefinedTargetsRunning()) {
    4. ...
    5. // 2. 开始目标帧
    6. startBuild();
    7. }
    8. }
    1. void startBuild() {
    2. // 1.得到目标跟踪器
    3. if (objectTracker != null) {
    4. // 2. 得到目标构建器
    5. if (targetBuilder != null) {
    6. // 3. 若 targetBuilder.getFrameQuality() 为 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_LOW,显示出错
    7. ...
    8. // 4. 循环遍历构建目标图像数据
    9. do {
    10. ...
    11. targetBuilderCounter++;
    12. } while (!targetBuilder.build(name, 320.0f));
    13. // 5. 标记当前 refFreeFrame 当前的状态是创建状态。
    14. // 后续 Vuforia_onUpdate() 回调,会根据这个标记从跟踪器中取出目标跟踪图像,结合当前的帧数据,计算模型的显示位置和角度
    15. refFreeFrame.setCreating();
    16. }
    17. }
    18. }
  2. 绑定目标帧对象至目标跟踪器,并激活

    1. @Override
    2. public void Vuforia_onUpdate(State s) {
    3. mSessionControl.onVuforiaUpdate(s);
    4. }
    1. @Override
    2. public void onVuforiaUpdate(State state) {
    3. // 1. 获取跟踪器对象
    4. ObjectTracker objectTracker = ...;
    5. // 2. 判断是否有新的目标帧对象
    6. if (refFreeFrame.hasNewTrackableSource()) {
    7. ...
    8. // 3. 取消激活当前的跟踪数据
    9. objectTracker.deactivateDataSet(objectTracker.getActiveDataSet(0));
    10. // 4. 添加新的目标跟踪对象
    11. Trackable trackable = dataSetUserDef
    12. .createTrackable(refFreeFrame.getNewTrackableSource());
    13. // 5. 重新激活跟踪数据集
    14. objectTracker.activateDataSet(dataSetUserDef);
    15. if (mExtendedTracking) {
    16. trackable.startExtendedTracking();
    17. }
    18. }
    19. }

1.5 GLSurfaceView.Renderer 回调函数处理

1.5.1 onSurfaceCreated

  1. @Override
  2. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  3. // 最终调用 Vuforia.onSurfaceCreated(),用来确保在初次使用或者 onResume() 之后初始化渲染
  4. vuforiaAppSession.onSurfaceCreated();
  5. // 最终调用 void initRendering(),创建 shader 程序对象,加载顶点处理器和片元处理器
  6. // 创建纹理引用,坐标引用,投影矩阵引用等,同 EasyAR 简单调研文档 1.3.1 初始化 OpenGL
  7. mSampleAppRenderer.onSurfaceCreated();
  8. }

1.5.2 onSurfaceChanged

  1. @Override
  2. public void onSurfaceChanged(GL10 gl, int width, int height) {
  3. // 1.
  4. mActivity.updateRendering();
  5. // Call Vuforia function to handle render surface size changes:
  6. vuforiaAppSession.onSurfaceChanged(width, height);
  7. // RenderingPrimitives to be updated when some rendering change is done
  8. mSampleAppRenderer.onConfigurationChanged(mIsActive);
  9. // Call function to initialize rendering:
  10. initRendering();
  11. }
  1. mActivity.updateRendering()

    最终会调用 RefFreeFrame.initGL 方法

    1. void initGL(int screenWidth, int screenHeight) {
    2. // 1. 初始化模型矩阵,初始化顶点着色器、片元作色器、颜色等句柄
    3. frameGL.init(screenWidth, screenHeight);
    4. }
  2. 调用 Vuforia.onSurfaceChanged(width, height)

  3. 重新计算设置 Render 的 VideoBackgroundConfig

    1. VideoBackgroundConfig config = new VideoBackgroundConfig();
    2. config.setEnabled(true);
    3. config.setPosition(new Vec2I(0, 0));
    4. ...
    5. config.setSize(new Vec2I(xSize, ySize));
    6. Renderer.getInstance().setVideoBackgroundConfig(config);
  4. 获取渲染基元

    1. mRenderingPrimitives = Device.getInstance().getRenderingPrimitives();
  5. 初始化渲染

    1. private void initRendering() {
    2. // 1. 创建茶几对象
    3. // 2. 设置清空颜色
    4. // 3. 绑定需要的纹理对象
    5. // 4. 创建顶点、纹理、矩阵等句柄
    6. }

1.5.3 onDrawFrame

  1. public void render() {
  2. // 1. 清除颜色和深度缓存区
  3. // 2. 针对前置摄像头和后置摄像头,设置面片正面方面
  4. // 3. 从 mRenderingPrimitives 取出 viewList
  5. ViewList viewList = mRenderingPrimitives.getRenderingViews();
  6. // 4. 从每个图元中取出当前的视口大小,模型矩阵,用于绘制当前界面
  7. }

1.6 Vuforia SDK 简单小结

  1. 提供接口设置背景相机视频
  2. 提供相机对象,支持设置相机对象的清晰度、对焦模式等
  3. 提供跟踪器
    • 跟踪器支持获取当前的一帧作为目标图像,后续帧参考该帧计算
    • 跟踪器支持同时跟踪多个对象
  4. 提供 RenderingPrimitives 类,提供创建场景时的视口大小和模型矩阵
  5. 暂未看到 SLAM 相关的功能 demo
  6. 最新的免费版本(6.2.10)有水印,早期版本 QCAR(2.6.10)无水印。但最新版本 SDK 效果也并未达到预期要求,早期版本可期望性并不高
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注