Vuforia
是高通提供的一款 AR SDK。
简要介绍 UserDefinedTargets
用户自定义目标,实现自定义选择场景并投放模型的功能
1. UserDefinedTargets
demo 解析
1.1 初始化
vuforiaAppSession = new SampleApplicationSession(this);
vuforiaAppSession.initAR(this, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
其中 SampleApplicationSession.initAR(Activity activity, int screenOrientation)
方法逻辑如下:
监听屏幕转向,设置竖屏
设置 Activity 可见时维持亮屏
-
后台线程初始化 Vuforia
Vuforia.setInitParameters(mActivity, mVuforiaFlags, ${VuforiaKey});
mVuforiaFlags:
GL_20
,表示使用 OpenGL 初始化do { mProgressValue = Vuforia.init(); // Publish the progress value: publishProgress(mProgressValue); } while (!isCancelled() && mProgressValue >= 0 && mProgressValue < 100);
反复调用
Vuforia.init()
直至返回值为 100,表示初始化完成 -
主线程初始化跟踪器
// Initialize the image tracker: TrackerManager trackerManager = TrackerManager.getInstance(); Tracker tracker = trackerManager.initTracker(ObjectTracker .getClassType());
-
加载跟踪器数据(暂时这么描述)
// Get the image tracker: TrackerManager trackerManager = TrackerManager.getInstance(); ObjectTracker objectTracker = (ObjectTracker) trackerManager .getTracker(ObjectTracker.getClassType()); ... // Create the data set: dataSetUserDef = objectTracker.createDataSet(); ... // 激活数据集(没理解) objectTracker.activateDataSet(dataSetUserDef)
-
注册 Vuforia 回调
Vuforia.registerCallback(Vuforia.UpdateCallbackInterface object)
真正实现逻辑如下(后续分析)
public class UserDefinedTargets extends Activity implements SampleApplicationControl, SampleAppMenuInterface { ... @Override public void onVuforiaUpdate(State state) { ... } ... }
1.2 设置相机、场景背景等
@Override
public void onInitARDone(SampleApplicationException exception) {
// 初始化 refFreeFrame,mGlView,mRenderer
initApplicationAR();
// 最终调用 Renderer.getInstance().setVideoBackgroundConfig(config); 初始化场景的视频背景
mRenderer.setActive(true);
// 添加 GlView 至场景中
addContentView(mGlView, new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
...
try {
// 设置 CameraDevice 的相关参数,并开启场景帧的跟踪
vuforiaAppSession.startAR(CameraDevice.CAMERA_DIRECTION.CAMERA_DIRECTION_DEFAULT);
} catch (SampleApplicationException e) {
Log.e(LOGTAG, e.getString());
}
// 设置为连续对焦模式
boolean result = CameraDevice.getInstance().setFocusMode(
CameraDevice.FOCUS_MODE.FOCUS_MODE_CONTINUOUSAUTO);
...
}
-
initApplicationAR 方法
private void initApplicationAR() { refFreeFrame = new RefFreeFrame(this, vuforiaAppSession); // 加载场景中,相机框框的纹理图 refFreeFrame.init(); // 创建 GL 视图,并设置 OpenGL 是否支持透明格式,深度缓存区大小,和模板缓冲区大小 mGlView = new SampleApplicationGLView(this); mGlView.init(translucent, depthSize, stencilSize); // 创建自定义渲染器(封装OpenGL渲染相关的代码) mRenderer = new UserDefinedTargetRenderer(this, vuforiaAppSession); // 添加之前的初始化绑定的纹理贴图 viewfinder_crop_marks_portrait.png 和 viewfinder_crop_marks_landscape.png mRenderer.setTextures(mTextures); // 设置自定义的渲染器 mGlView.setRenderer(mRenderer); ... }
-
vuforiaAppSession.startAR(CameraDevice.CAMERA_DIRECTION.CAMERA_DIRECTION_DEFAULT);
public class SampleApplicationSession implements UpdateCallbackInterface { ... public void startAR(int camera) throws SampleApplicationException { ... mCamera = camera; ... // 初始化 Vuforia 相机设备,参数指定使用正面相机 CameraDevice.getInstance().init(camera); ... // 设置相机的视频模式为默认,其他参数有高清、流程 CameraDevice.getInstance().selectVideoMode( CameraDevice.MODE.MODE_DEFAULT); ... // 开启相机设备 CameraDevice.getInstance().start(); ... // 开启 AR 场景跟踪器 mSessionControl.doStartTrackers(); ... } ... }
@Override public boolean doStartTrackers() { ... Tracker objectTracker = TrackerManager.getInstance().getTracker( ObjectTracker.getClassType()); if (objectTracker != null) { result = objectTracker.start(); } ... }
1.3 处理页面获取和失去焦点
-
获取焦点
@Override protected void onResume() { super.onResume(); // 1. 针对 android 设备,设置请求屏幕转向为横向 ... // 2. 内部调用 Vuforia.onResume(),并尝试开启 Tracker vuforiaAppSession.resumeAR(); ... // 3. 调用 GLSurfaceView onResume 方法 if (mGlView != null) { mGlView.setVisibility(View.VISIBLE); mGlView.onResume(); } }
-
失去焦点
public void pauseAR() throws SampleApplicationException { if (mStarted) { // 1. 停止跟踪器,停止 CameraDevice 运行,并销毁相机对象 stopCamera(); } // Vuforia.onPause(); }
1.4 用户点击拍照按钮,构建目标帧
-
点击,开始构建目标帧对象
public void onCameraClick(View v) { // 1. 通过目标跟踪器获取的帧的质量设置是否为 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_NONE 来判断跟踪器是否在运行 if (isUserDefinedTargetsRunning()) { ... // 2. 开始目标帧 startBuild(); } }
void startBuild() { // 1.得到目标跟踪器 if (objectTracker != null) { // 2. 得到目标构建器 if (targetBuilder != null) { // 3. 若 targetBuilder.getFrameQuality() 为 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_LOW,显示出错 ... // 4. 循环遍历构建目标图像数据 do { ... targetBuilderCounter++; } while (!targetBuilder.build(name, 320.0f)); // 5. 标记当前 refFreeFrame 当前的状态是创建状态。 // 后续 Vuforia_onUpdate() 回调,会根据这个标记从跟踪器中取出目标跟踪图像,结合当前的帧数据,计算模型的显示位置和角度 refFreeFrame.setCreating(); } } }
-
绑定目标帧对象至目标跟踪器,并激活
@Override public void Vuforia_onUpdate(State s) { mSessionControl.onVuforiaUpdate(s); }
@Override public void onVuforiaUpdate(State state) { // 1. 获取跟踪器对象 ObjectTracker objectTracker = ...; // 2. 判断是否有新的目标帧对象 if (refFreeFrame.hasNewTrackableSource()) { ... // 3. 取消激活当前的跟踪数据 objectTracker.deactivateDataSet(objectTracker.getActiveDataSet(0)); // 4. 添加新的目标跟踪对象 Trackable trackable = dataSetUserDef .createTrackable(refFreeFrame.getNewTrackableSource()); // 5. 重新激活跟踪数据集 objectTracker.activateDataSet(dataSetUserDef); if (mExtendedTracking) { trackable.startExtendedTracking(); } } }
1.5 GLSurfaceView.Renderer 回调函数处理
1.5.1 onSurfaceCreated
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 最终调用 Vuforia.onSurfaceCreated(),用来确保在初次使用或者 onResume() 之后初始化渲染
vuforiaAppSession.onSurfaceCreated();
// 最终调用 void initRendering(),创建 shader 程序对象,加载顶点处理器和片元处理器
// 创建纹理引用,坐标引用,投影矩阵引用等,同 EasyAR 简单调研文档 1.3.1 初始化 OpenGL
mSampleAppRenderer.onSurfaceCreated();
}
1.5.2 onSurfaceChanged
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 1.
mActivity.updateRendering();
// Call Vuforia function to handle render surface size changes:
vuforiaAppSession.onSurfaceChanged(width, height);
// RenderingPrimitives to be updated when some rendering change is done
mSampleAppRenderer.onConfigurationChanged(mIsActive);
// Call function to initialize rendering:
initRendering();
}
-
mActivity.updateRendering()
最终会调用
RefFreeFrame.initGL
方法void initGL(int screenWidth, int screenHeight) { // 1. 初始化模型矩阵,初始化顶点着色器、片元作色器、颜色等句柄 frameGL.init(screenWidth, screenHeight); }
调用
Vuforia.onSurfaceChanged(width, height)
-
重新计算设置 Render 的 VideoBackgroundConfig
VideoBackgroundConfig config = new VideoBackgroundConfig(); config.setEnabled(true); config.setPosition(new Vec2I(0, 0)); ... config.setSize(new Vec2I(xSize, ySize)); Renderer.getInstance().setVideoBackgroundConfig(config);
-
获取渲染基元
mRenderingPrimitives = Device.getInstance().getRenderingPrimitives();
-
初始化渲染
private void initRendering() { // 1. 创建茶几对象 // 2. 设置清空颜色 // 3. 绑定需要的纹理对象 // 4. 创建顶点、纹理、矩阵等句柄 }
1.5.3 onDrawFrame
public void render() {
// 1. 清除颜色和深度缓存区
// 2. 针对前置摄像头和后置摄像头,设置面片正面方面
// 3. 从 mRenderingPrimitives 取出 viewList
ViewList viewList = mRenderingPrimitives.getRenderingViews();
// 4. 从每个图元中取出当前的视口大小,模型矩阵,用于绘制当前界面
}
1.6 Vuforia SDK 简单小结
- 提供接口设置背景相机视频
- 提供相机对象,支持设置相机对象的清晰度、对焦模式等
- 提供跟踪器
- 跟踪器支持获取当前的一帧作为目标图像,后续帧参考该帧计算
- 跟踪器支持同时跟踪多个对象
- 提供 RenderingPrimitives 类,提供创建场景时的视口大小和模型矩阵
- 暂未看到 SLAM 相关的功能 demo
- 最新的免费版本(6.2.10)有水印,早期版本 QCAR(2.6.10)无水印。但最新版本 SDK 效果也并未达到预期要求,早期版本可期望性并不高