Vuforia demo 簡析

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) 方法邏輯如下:

  1. 監(jiān)聽屏幕轉(zhuǎn)向,設置豎屏

  2. 設置 Activity 可見時維持亮屏

  3. 后臺線程初始化 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,表示初始化完成

  4. 主線程初始化跟蹤器

    // Initialize the image tracker:
    TrackerManager trackerManager = TrackerManager.getInstance();
    Tracker tracker = trackerManager.initTracker(ObjectTracker
            .getClassType());
    
  5. 加載跟蹤器數(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)
    
  6. 注冊 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);

    ...
}
  1. 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);
        
        ...
    }
    
  2. 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 處理頁面獲取和失去焦點

  1. 獲取焦點

    @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();
        }
    }
    
  2. 失去焦點

    public void pauseAR() throws SampleApplicationException {
        if (mStarted) {
             // 1. 停止跟蹤器,停止 CameraDevice 運行,并銷毀相機對象
            stopCamera();
        }
    
        // 
        Vuforia.onPause();
    }
    

1.4 用戶點擊拍照按鈕,構(gòu)建目標幀

  1. 點擊,開始構(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();
            }
        }
    }
    
  2. 綁定目標幀對象至目標跟蹤器,并激活

    @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();
}
  1. mActivity.updateRendering()

    最終會調(diào)用 RefFreeFrame.initGL 方法

    void initGL(int screenWidth, int screenHeight) {
        // 1. 初始化模型矩陣,初始化頂點著色器、片元作色器、顏色等句柄
        frameGL.init(screenWidth, screenHeight);
    }
    
  2. 調(diào)用 Vuforia.onSurfaceChanged(width, height)

  3. 重新計算設置 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);
    
  4. 獲取渲染基元

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

    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é)

  1. 提供接口設置背景相機視頻
  2. 提供相機對象,支持設置相機對象的清晰度、對焦模式等
  3. 提供跟蹤器
    • 跟蹤器支持獲取當前的一幀作為目標圖像,后續(xù)幀參考該幀計算
    • 跟蹤器支持同時跟蹤多個對象
  4. 提供 RenderingPrimitives 類,提供創(chuàng)建場景時的視口大小和模型矩陣
  5. 暫未看到 SLAM 相關(guān)的功能 demo
  6. 最新的免費版本(6.2.10)有水印,早期版本 QCAR(2.6.10)無水印。但最新版本 SDK 效果也并未達到預期要求,早期版本可期望性并不高
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容