Vuforia
是高通提供的一款 AR SDK。
簡要介紹 UserDefinedTargets
用戶自定義目標,實現(xiàn)自定義選擇場景并投放模型的功能
gif
1. UserDefinedTargets
demo 解析
1.1 初始化
vuforiaAppSession = new SampleApplicationSession(this);
vuforiaAppSession.initAR(this, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
其中 SampleApplicationSession.initAR(Activity activity, int screenOrientation)
方法邏輯如下:
監(jiān)聽屏幕轉(zhuǎn)向,設置豎屏
設置 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);
反復調(diào)用
Vuforia.init()
直至返回值為 100,表示初始化完成 -
主線程初始化跟蹤器
// Initialize the image tracker: TrackerManager trackerManager = TrackerManager.getInstance(); Tracker tracker = trackerManager.initTracker(ObjectTracker .getClassType());
-
加載跟蹤器數(shù)據(jù)(暫時這么描述)
// Get the image tracker: TrackerManager trackerManager = TrackerManager.getInstance(); ObjectTracker objectTracker = (ObjectTracker) trackerManager .getTracker(ObjectTracker.getClassType()); ... // Create the data set: dataSetUserDef = objectTracker.createDataSet(); ... // 激活數(shù)據(jù)集(沒理解) objectTracker.activateDataSet(dataSetUserDef)
-
注冊 Vuforia 回調(diào)
Vuforia.registerCallback(Vuforia.UpdateCallbackInterface object)
真正實現(xiàn)邏輯如下(后續(xù)分析)
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();
// 最終調(diào)用 Renderer.getInstance().setVideoBackgroundConfig(config); 初始化場景的視頻背景
mRenderer.setActive(true);
// 添加 GlView 至場景中
addContentView(mGlView, new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
...
try {
// 設置 CameraDevice 的相關(guān)參數(shù),并開啟場景幀的跟蹤
vuforiaAppSession.startAR(CameraDevice.CAMERA_DIRECTION.CAMERA_DIRECTION_DEFAULT);
} catch (SampleApplicationException e) {
Log.e(LOGTAG, e.getString());
}
// 設置為連續(xù)對焦模式
boolean result = CameraDevice.getInstance().setFocusMode(
CameraDevice.FOCUS_MODE.FOCUS_MODE_CONTINUOUSAUTO);
...
}
-
initApplicationAR 方法
private void initApplicationAR() { refFreeFrame = new RefFreeFrame(this, vuforiaAppSession); // 加載場景中,相機框框的紋理圖 refFreeFrame.init(); // 創(chuàng)建 GL 視圖,并設置 OpenGL 是否支持透明格式,深度緩存區(qū)大小,和模板緩沖區(qū)大小 mGlView = new SampleApplicationGLView(this); mGlView.init(translucent, depthSize, stencilSize); // 創(chuàng)建自定義渲染器(封裝OpenGL渲染相關(guān)的代碼) 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 相機設備,參數(shù)指定使用正面相機 CameraDevice.getInstance().init(camera); ... // 設置相機的視頻模式為默認,其他參數(shù)有高清、流程 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 設備,設置請求屏幕轉(zhuǎn)向為橫向 ... // 2. 內(nèi)部調(diào)用 Vuforia.onResume(),并嘗試開啟 Tracker vuforiaAppSession.resumeAR(); ... // 3. 調(diào)用 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 用戶點擊拍照按鈕,構(gòu)建目標幀
-
點擊,開始構(gòu)建目標幀對象
public void onCameraClick(View v) { // 1. 通過目標跟蹤器獲取的幀的質(zhì)量設置是否為 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_NONE 來判斷跟蹤器是否在運行 if (isUserDefinedTargetsRunning()) { ... // 2. 開始目標幀 startBuild(); } }
void startBuild() { // 1.得到目標跟蹤器 if (objectTracker != null) { // 2. 得到目標構(gòu)建器 if (targetBuilder != null) { // 3. 若 targetBuilder.getFrameQuality() 為 ImageTargetBuilder.FRAME_QUALITY.FRAME_QUALITY_LOW,顯示出錯 ... // 4. 循環(huán)遍歷構(gòu)建目標圖像數(shù)據(jù) do { ... targetBuilderCounter++; } while (!targetBuilder.build(name, 320.0f)); // 5. 標記當前 refFreeFrame 當前的狀態(tài)是創(chuàng)建狀態(tài)。 // 后續(xù) Vuforia_onUpdate() 回調(diào),會根據(jù)這個標記從跟蹤器中取出目標跟蹤圖像,結(jié)合當前的幀數(shù)據(jù),計算模型的顯示位置和角度 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. 取消激活當前的跟蹤數(shù)據(jù) objectTracker.deactivateDataSet(objectTracker.getActiveDataSet(0)); // 4. 添加新的目標跟蹤對象 Trackable trackable = dataSetUserDef .createTrackable(refFreeFrame.getNewTrackableSource()); // 5. 重新激活跟蹤數(shù)據(jù)集 objectTracker.activateDataSet(dataSetUserDef); if (mExtendedTracking) { trackable.startExtendedTracking(); } } }
1.5 GLSurfaceView.Renderer 回調(diào)函數(shù)處理
1.5.1 onSurfaceCreated
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 最終調(diào)用 Vuforia.onSurfaceCreated(),用來確保在初次使用或者 onResume() 之后初始化渲染
vuforiaAppSession.onSurfaceCreated();
// 最終調(diào)用 void initRendering(),創(chuàng)建 shader 程序?qū)ο螅虞d頂點處理器和片元處理器
// 創(chuàng)建紋理引用,坐標引用,投影矩陣引用等,同 EasyAR 簡單調(diào)研文檔 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()
最終會調(diào)用
RefFreeFrame.initGL
方法void initGL(int screenWidth, int screenHeight) { // 1. 初始化模型矩陣,初始化頂點著色器、片元作色器、顏色等句柄 frameGL.init(screenWidth, screenHeight); }
調(diào)用
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. 創(chuàng)建茶幾對象 // 2. 設置清空顏色 // 3. 綁定需要的紋理對象 // 4. 創(chuàng)建頂點、紋理、矩陣等句柄 }
1.5.3 onDrawFrame
public void render() {
// 1. 清除顏色和深度緩存區(qū)
// 2. 針對前置攝像頭和后置攝像頭,設置面片正面方面
// 3. 從 mRenderingPrimitives 取出 viewList
ViewList viewList = mRenderingPrimitives.getRenderingViews();
// 4. 從每個圖元中取出當前的視口大小,模型矩陣,用于繪制當前界面
}
1.6 Vuforia SDK 簡單小結(jié)
- 提供接口設置背景相機視頻
- 提供相機對象,支持設置相機對象的清晰度、對焦模式等
- 提供跟蹤器
- 跟蹤器支持獲取當前的一幀作為目標圖像,后續(xù)幀參考該幀計算
- 跟蹤器支持同時跟蹤多個對象
- 提供 RenderingPrimitives 類,提供創(chuàng)建場景時的視口大小和模型矩陣
- 暫未看到 SLAM 相關(guān)的功能 demo
- 最新的免費版本(6.2.10)有水印,早期版本 QCAR(2.6.10)無水印。但最新版本 SDK 效果也并未達到預期要求,早期版本可期望性并不高