title: 使用EQ-Renderer实现手势交互
date: 2024-01-31
description: EQ-Renderer是基于sceneform(filament)扩展的一个用于安卓端的三维AR渲染器。 本文档记录如何创建一个简单的手势交互示例。
EQ-Renderer是EQ基于sceneform(filament)扩展的一个用于安卓端的三维AR渲染器。
它包含sceneform_v1.16.0中九成接口(剔除了如sfb资源加载等已弃用的内容),扩展了视频背景视图、解决了sceneform模型加载的内存泄漏问题、集成了AREngine和ORB-SLAM3、添加了场景坐标与地理坐标系(CGCS-2000)的转换方法。
注:由于精力有限,文档和示例都不完善。sceneform相关请直接参考谷歌官方文档,扩展部分接口说明请移步git联系。
若使用离线依赖的方式,则跳过本节内容。
EQ-Renderer的maven仓库地址为:http://repo.eqgis.cn
根据AndroidSudio的版本,配置相应的AGP,这里我使用的gradle版本如下:
在工程目录下修改settings.gradle文件,示例如下:
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven {
allowInsecureProtocol = true
url "http://repo.eqgis.cn"
}
maven {url "https://developer.huawei.com/repo" }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
allowInsecureProtocol = true
url "http://repo.eqgis.cn"
}
maven {url "https://developer.huawei.com/repo" }
}
}
rootProject.name = "EQ-Renderer Sample"
include ':app'
注意:后面若要引入AREngine,则这里需要配置华为的maven仓库。
不同版本的Gradle配置在配置Maven仓库时,有一定差异。
Gradle 7.0版本后,需参考Android官方对于Gradle版本与Gradle插件的配套关系,把Gradle插件版本也升级到7.0及以上。
其它版本的gradle配置,请参考之前写的文档:视频地图开发文档#不同版本的Gradle
eq-renderer:三维渲染器,基于filament
eq-slam:slam算法库,当前版本(v1.0.2)使用的ORB-SLAM3,暂时仅支持arm-v8a。
opencv:图像处理
arcore:谷歌的AR服务
arengine:华为的AR服务
在模块的build.gradle文件中添加在线依赖,示例如下:
dependencies {
//...
//使用在线依赖
implementation 'com.eqgis:eq-renderer:1.0.2'
implementation 'com.eqgis:eq-slam:1.0.2'
//引入opencv
implementation 'org.opencv:opencv-v8a:4.5.5'
//使用ARCore 和 AREngine (按需添加)
implementation 'com.google.ar:core:1.39.0'
//使用AREngine则额外添加下面依赖
//华为仓库 maven {url "https://developer.huawei.com/repo/" }
implementation 'com.huawei.hms:arenginesdk:3.7.0.3'
}
若已使用在线依赖的方式,则跳过本节内容。
EQ渲染器:
eq-renderer
SLAM算法库:
eq-slam
OpenCV(arm-v8a版本):
opencv-v8a
将相关库下载到本地,放入模块的/libs目录下,如图:
然后再在build.gradle文件中引入
dependencies {
//...
//使用离线依赖
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
}
PS:若没有用到ARCore,可不添加这个依赖
ARCore仍采用在线依赖的方式
//使用ARCore 和 AREngine (按需添加)
implementation 'com.google.ar:core:1.39.0'
PS:若没有用到AREngine,可不添加这个依赖
AREngine仍采用在线依赖的方式,注意:使用AREngine,需要配置华为的maven仓库。参考上面的Maven配置。
//使用AREngine则额外添加下面依赖
//华为仓库settings.gradle中添加“ maven {url "https://developer.huawei.com/repo/" } ”
implementation 'com.huawei.hms:arenginesdk:3.7.0.3'
这里以“点击模型,并在点击位置加载标记””为例。
本文介绍的功能是sceneform已支持的,因此请直接参考谷歌sceneform API。
谷歌文档链接:https://developers.google.cn/sceneform/reference
Renderable
ModelRenderable
ViewRenderable
RenderableDefinition
Node
Node.OnTapListener
Node.OnTouchListener
配置开发环境以及创建场景并加载模型请参考文档:使用EQ-Renderer创建AR加载模型
手势交互参考示例源文件"InteractiveScene.java",它实现了在点击位置添加标记。
关键代码如下:
modelNode.setOnTapListener(new Node.OnTapListener() {
@Override
public void onTap(HitTestResult hitTestResult, MotionEvent motionEvent) {
//点击位置的节点对象
Node node = hitTestResult.getNode();
//获取点击对象的Node在世界坐标系下的空间位置、姿态
Vector3 worldPosition = node.getWorldPosition();
Quaternion worldRotation = node.getWorldRotation();
Log.i(InteractiveScene.class.getSimpleName(), "对象节点: "+ worldRotation.toString() + " " + worldPosition.toString());
//点击位置与相机当前位置的距离
float distance = hitTestResult.getDistance();
//获取世界坐标系下的点击位置(射线检测:与点击对象包围盒的碰撞点位置)
Vector3 point = hitTestResult.getPoint();
Log.i(InteractiveScene.class.getSimpleName(), "点击位置与相机的距离是:" + distance + " 米" + point.toString());
Toast.makeText(context, "碰撞点:"+ point, Toast.LENGTH_SHORT).show();
//添加标记
addObj(point,/*采用与父节点相同的姿态*/worldRotation);
}
});
public void addObj(Vector3 position,Quaternion rotation){
//添加TextView,渲染文字
TextView textView = new TextView(context);
//Scenefrom默认情况下,250dp对应世界坐标系下的1m,
textView.setTextSize(16);
textView.setText("T");
ViewRenderable.builder()
.setView(context,textView)
/*底部居中显示*/
.setVerticalAlignment(ViewRenderable.VerticalAlignment.BOTTOM)
.setHorizontalAlignment(ViewRenderable.HorizontalAlignment.CENTER)
.build()
.thenAccept(new Consumer<ViewRenderable>() {
@Override
public void accept(ViewRenderable viewRenderable) {
Node node = new Node();
node.setRenderable(viewRenderable);
node.setWorldScale(Vector3.one().scaled(0.25f));//比例
node.setWorldPosition(position);
node.setLocalRotation(rotation);
node.setParent(rootNode);
}
});
}
在AR模式下,运行效果如下: