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

  • 2022 年 10 月 11 日
  • 筆記

在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 "//developer.huawei.com/repo/" }
    	}
}

打開項目級「settings.gradle」文件,配置HMS Core SDK的Maven倉地址

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    		repositories {
       			 repositories {
           			 	google()
            			jcenter()
            			maven {url "//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 最新技術資訊~