如何用AR Engine環境Mesh能力實現虛實遮擋

2022-10-11 15:08:21

在AR應用中,使用者最不希望看到不真實的穿模現象發生,如虛擬形象部分身體陷入牆壁之中,或者未碰到牆壁卻已無法移動,這種不真實的互動十分影響使用者體驗。那如何才能讓避免虛擬物體的穿模問題呢?使用AR Engine的環境Mesh能力就能幫助開發者解決這個問題。

效果展示

實現方法

AR Engine提供實時計算並輸出畫面環境Mesh資料的能力。通過環境Mesh能力虛擬角色可以準確識別當前所處三維空間的情況,讓虛擬物體不僅僅能放置在水平面和垂直面上,還可以放置在任意可重建的曲面上。開發者可利用重建的環境Mesh實現虛實遮擋和碰撞檢測,可以讓虛擬物體藏在真實物品後,避免現實物體和虛擬物體融合現象的發生,從而實現沉浸式AR體驗。

整合步驟

開發環境要求:

JDK 1.8.211及以上。

安裝Android Studio 3.0及以上:

minSdkVersion 26及以上

targetSdkVersion 29(推薦)

compileSdkVersion 29(推薦)

Gradle 6.1.1及以上(推薦)

在華為終端裝置上的應用市場下載AR Engine伺服器端APK(需在華為應用市場,搜尋「華為AR Engine」)並安裝到終端裝置。

測試應用的裝置:參見AREngine特性軟硬體依賴表中環境Mesh支援裝置列表。如果同時使用多個HMS Core的服務,則需要使用各個Kit對應的最大值。

開發準備

  1. 在開發應用前需要在華為開發者聯盟網站上註冊成為開發者並完成實名認證,具體方法請參見帳號註冊認證

  2. 華為提供了Maven倉整合方式的AR Engine SDK包,在開始開發前,需要將AR Engine SDK整合到您的開發環境中。

  3. Android Studio的程式碼庫設定在Gradle外掛7.0以下版本、7.0版本和7.1及以上版本有所不同。請根據您當前的Gradle外掛版本,選擇對應的設定過程。

  4. 以7.0為例:

開啟Android Studio專案級「build.gradle」檔案,新增Maven程式碼庫。

在「buildscript > repositories」中設定HMS Core SDK的Maven倉地址。

buildscript {
    	repositories {
        	google()
        	jcenter()
        	maven {url "https://developer.huawei.com/repo/" }
    	}
}

開啟專案級「settings.gradle」檔案,設定HMS Core SDK的Maven倉地址

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    		repositories {
       			 repositories {
           			 	google()
            			jcenter()
            			maven {url "https://developer.huawei.com/repo/" }
       			 }
   			 }
}
  1. 新增依賴 在「dependencies」中新增如下編譯依賴:
dependencies {
    implementation 'com.huawei.hms:arenginesdk:{version}
}

開發步驟

  1. 建立HitResultDisplay類,這個類根據指定的引數來繪製虛擬物件
Public class HitResultDisplay implements SceneMeshComponenDisplay{
	//初始化VirtualObjectData
	VirtualObjectData mVirtualObject = new VirtualObjectData();
	//在init方法中給mVirtualObject傳入上下文
	Public void init(Context context){
		mVirtualObject.init(context);
		//傳入材質屬性
		mVirtualObject.setMaterialProperties();
	}
	//在onDrawFrame方法中傳入ARFrame,用來獲取光照估計
	Public void onDrawFrame(ARFrame arframe){
		//獲取光照估計
		ARLightEstimate le = arframe.getLightEstimate();
		//獲取當前相機視野的畫素強度
		lightIntensity = le.getPixelIntensity();
		//獲取好之後,需要給mVirtualObject中一些方法傳入資料
		mVirtualObject.draw(…,…,lightIntensity,…);
		//建立handleTap方法傳入ARFrame物件來獲取座標資訊
		handleTap(arframe);
	}
     //實現handleTap方法
     Private void handleTap(ARFrame frame){
        //用ARFrame物件呼叫hitTest
        List<ARHitResult> hitTestResults = frame.hitTest(tap);
        //檢測平面是否被擊中,是否在平面多邊形中被擊中
        For(int i = 0;i<hitTestResults.size();i++){
            ARHitResult hitResultTemp = hitTestResults.get(i);
            Trackable = hitResultTemp.getTrackable();
            If(trackable instanceof ARPoint && ((ARPoint) trackable).getOrientationMode() == ARPoint.OrientationMode.ESTIMATED_SURFACE_NORMAL){
                isHasHitFlag = true;
                hitResult = hitResultTemp;
            }
        }
     }
}
  1. 建立SceneMeshDisplay類,用來渲染場景網路
Public class SceneMeshDiaplay implements SceneMeshComponenDisplay{
	//需要在init中實現openGL的一些操作
	Public void init(Context context){}
	//在onDrawFrame方法中獲取當前對應的環境Mesh
	Public void onDrawFrame(ARFrame arframe){
		ARSceneMesh arSceneMesh = arframe.acquireSceneMesh();
		//建立一個用來更新資料的方法把arSceneMesh傳入進去
		updateSceneMeshData(arSceneMesh);
         //arSceneMesh使用完之後需要釋放
         arSceneMesh.release();
	}
     //實現這個方法用來更新資料
     Public void updateSceneMeshData(ARSceneMesh sceneMesh){
         //返回當前視角下環境Mesh頂點座標陣列
         FloatBuffer meshVertices = sceneMesh.getVertices();
         //返回當前視角下環境Mesh三角面片頂點索引的陣列
         IntBuffer meshTriangleIndices = sceneMesh.getTriangleIndices();
     }
}
  1. 建立SceneMeshRenderManager類,這個類來提供與外部場景相關的渲染管理器,

包括虛擬物件渲染管理

public class SceneMeshRenderManager implements GLSurfaceView.Render{
	//初始化更新網路資料和執行渲染的類
	private SceneMeshDisplay mSceneMesh = new SceneMeshDisplay();
	//初始化繪製虛擬物件的類
	Private HitResultDisplay mHitResultDisplay = new HitResultDisplay();
	
	//實現onSurfaceCreated()方法
	public  void  onSurfaceCreated(){
		//需要給mSceneMesh 類和mHitResultDisplay類傳入 context
		mSceneMesh.init(mContext);
		mHitResultDisplay.init(mContext);
}	
	
	//實現onDrawFrame()方法;
	public void onDrawFrame(){
		//用ARSession物件來設定camera。
		mArSession.setCameraTexTureName();
		ARFrame arFrame = mArSession.update();
		ARCamera arCamera = arframe.getCamera();
		//把SceneMeshDisplay類需要的資料傳過去
		mSceneMesh.onDrawFrame(arframe,viewmtxs,projmtxs);
}
}
  1. 建立SceneMeshActivity用來展示功能
public class SceneMeshActivity extends BaseActivity{
	//提供與外部場景相關的渲染管理器,包括虛擬物件渲染管理類。
	private ScemeMeshRenderManager mSceneMeshRenderManager;
	//用來管理AR Engine的整個執行狀態,
	private ARSession mArSession;
//需要初始化一些類和物件
	protected void onCreate(Bundle savedInstanceState){
	mSceneMeshRenderManager = new SceneMeshRenderManager();
}
//在onResume方法中初始化ARSession
protected void onResume(){
	//初始化ARSession
	mArSession = new ARSession(this.getApplicationContext());
	//基於session引數建立ARWorldTrackingConfig物件
	ARConfigBase config = new ARWorldTrackingConfig(mArSession);
	//需要把ARSession傳給SceneMeshRenderManager
	mSceneMeshRenderManager.setArSession(mArSession);
//需要開啟mesh,用config呼叫setEnableItem方法
config.setEnableItem(ARConfigBase.ENABLE_MESH | ARConfigBase.ENABLE_DEPTH);
}
}

具體實現可參考範例程式碼

瞭解更多詳情>>

存取華為開發者聯盟官網
獲取開發指導檔案
華為移動服務開源倉庫地址:GitHubGitee

關注我們,第一時間瞭解 HMS Core 最新技術資訊~