@zyl06
2017-10-22T04:38:17.000000Z
字数 6596
阅读 1773
Android AR
Vuforia 是高通提供的一款 AR SDK。
简要介绍 UserDefinedTargets 用户自定义目标,实现自定义选择场景并投放模型的功能

UserDefinedTargets demo 解析
vuforiaAppSession = new SampleApplicationSession(this);vuforiaAppSession.initAR(this, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
其中 SampleApplicationSession.initAR(Activity activity, int screenOrientation) 方法逻辑如下:
后台线程初始化 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 implementsSampleApplicationControl, SampleAppMenuInterface {...@Overridepublic void onVuforiaUpdate(State state) {...}...}
@Overridepublic void onInitARDone(SampleApplicationException exception) {// 初始化 refFreeFrame,mGlView,mRendererinitApplicationAR();// 最终调用 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.pngmRenderer.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();...}...}
@Overridepublic boolean doStartTrackers() {...Tracker objectTracker = TrackerManager.getInstance().getTracker(ObjectTracker.getClassType());if (objectTracker != null) {result = objectTracker.start();}...}
获取焦点
@Overrideprotected void onResume() {super.onResume();// 1. 针对 android 设备,设置请求屏幕转向为横向...// 2. 内部调用 Vuforia.onResume(),并尝试开启 TrackervuforiaAppSession.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();}
点击,开始构建目标帧对象
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();}}}
绑定目标帧对象至目标跟踪器,并激活
@Overridepublic void Vuforia_onUpdate(State s) {mSessionControl.onVuforiaUpdate(s);}
@Overridepublic 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();}}}
@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 最终调用 Vuforia.onSurfaceCreated(),用来确保在初次使用或者 onResume() 之后初始化渲染vuforiaAppSession.onSurfaceCreated();// 最终调用 void initRendering(),创建 shader 程序对象,加载顶点处理器和片元处理器// 创建纹理引用,坐标引用,投影矩阵引用等,同 EasyAR 简单调研文档 1.3.1 初始化 OpenGLmSampleAppRenderer.onSurfaceCreated();}
@Overridepublic 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 donemSampleAppRenderer.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. 创建顶点、纹理、矩阵等句柄}
public void render() {// 1. 清除颜色和深度缓存区// 2. 针对前置摄像头和后置摄像头,设置面片正面方面// 3. 从 mRenderingPrimitives 取出 viewListViewList viewList = mRenderingPrimitives.getRenderingViews();// 4. 从每个图元中取出当前的视口大小,模型矩阵,用于绘制当前界面}