如何用AR Engine环境Mesh能力实现虚实遮挡

在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 最新技术资讯~

posted @ 2022-10-11 10:00  HarmonyOS_SDK  阅读(408)  评论(0编辑  收藏  举报