【AR开发示例】实现AR管线巡检

写在前面的话

这是一篇旧文档,代码仓库见 https://gitee.com/tanyunxiu/AR-pipe

本文档是基于超图移动端SDK的AR模块开发的示例,仅供参考,SDK在持续迭代中,相关描述可能有变化。

示例介绍

这是一个使用AR查看墙内管线的基础示例程序。

涉及的关键词:SuperMap iMobile for Android、深度遮挡、ARCore、AREngine

数据准备

数据格式

本示例所使用到的管线模型格式为:gltf2.0 、gltf2.0介绍

示例数据

示例数据位于ar_occlusion\sampledata\PipeData.zip中

数据制作

  1. 使用blender制作模型(或在blender中导入模型)

为了防止在模型批量导出的过程中出现错误,请参考下图的场景集合的层级结构。

由于示例程序中采用OBB有向包围盒( 它是包含该对象且相对于坐标轴方向任意的最小的长方体 )的方式用于射线检测。为了在示例程序中能够准确点击模型,请通过将模型拆分成单个实体对象的方式,确保模型的冗余空间尽可能地小。

模型导入

  1. 批量导出模型

在菜单栏->"Scripting"中新建脚本,内容如下:

# exports each selected object into its own file
import bpy
import os# export to blend file location
basedir = r"E:\3d\top_pipe\\"if not basedir:raise Exception("Blend file is not saved")view_layer = bpy.context.view_layerobj_active = view_layer.objects.active
selection = bpy.context.selected_objectsbpy.ops.object.select_all(action='DESELECT')for obj in selection:obj.select_set(True)# some exporters only use the active objectview_layer.objects.active = objname = bpy.path.clean_name(obj.name)fn = os.path.join(basedir, name)#bpy.ops.export_scene.fbx(filepath=fn + ".fbx", use_selection=True)bpy.ops.export_scene.gltf(filepath=fn, export_format="GLB", export_lights=False, use_selection=True)obj.select_set(False)print("written:", fn)view_layer.objects.active = obj_activefor obj in selection:obj.select_set(True)print("All save completed!")
  1. 选中场景集合中所有模型,执行脚本,导出模型。

批量导出脚本

  1. 查看模型文件夹。

模型组

  1. 至此,数据准备阶段已完成。

在后续构建的AR场景中,通过点击交互就可以查询出模型的名称。(Mesh2、Mesh3、Line…)。

若是需要通过点击交互,查询模型的其他属性信息(诸如规格、连接类型这些信息)。可通过创建一张属性表,建立模型名称与属性字段的一一对应的关系。通过查询模型名称,进而去查询对应的属性值。

属性查询

运行流程

开发环境

  • IDE:Android Studio 2021
  • Android Gradle Plugin Version:4.1.2
  • Gradle Version:6.5

注意事项:

Gradle 7.0版本后,请参考Android官方对于Gradle版本与Gradle插件的配套关系,把Gradle插件版本也升级到7.0及以上。

iMobile SDK

使用SuperMap移动GIS的iMobile for Android 的SDK 下载链接

示例程序涉及SDK中的以下so 和 jar

  • libimb2d_1100.so
  • com.supermap.data_v1100.jar
  • com.supermap.ar_v1100.jar
  • scenefrom-sm-11.0.1.aar

在工程中导入iMboile的AR模块

产品包

模块的build.gradle配置如下

plugins {id 'com.android.application'
}android {compileSdk 28defaultConfig {applicationId "com.supermap.samplecode.occlusiondemo"minSdk 24targetSdk 28versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"ndk{//注意使用的产品包是32位还是64位abiFilters 'armeabi-v7a'}}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}sourceSets {main {jniLibs.srcDirs = ['libs']}}
}dependencies {implementation 'androidx.appcompat:appcompat:1.3.0'implementation 'com.google.android.material:material:1.4.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.4'//SuperMap Data模块implementation files('libs/com.supermap.data_v1100.jar')//SuperMap AR模块implementation files('libs/com.supermap.ar_v1100.jar')//渲染框架implementation files('libs/sceneform-sm-11.0.1.aar')//第三方工具类implementation files('libs/eqtool-1.3.0.jar')
}

运行示例

  1. 许可设置

    此示例程序使用的是离线使用许可。

    在src/main/assets/目录下,默认存放一个试用许可"SuperMapiMobileTrial.slm"。在程序初次启动时,会拷贝至手机对应文件夹(…/PipeData/license)下。

    若许可过期或不可用,请先申请许可,然后拷贝至手机对应文件夹(…/PipeData/license)下,或在assets目录进行替换。

    注意:

    许可过期或不可用,会出现如下报错信息:

错误信息

若许可可用,仍出现上述异常信息,请从以下方面进行自查。

  • 使用的so与jar不是同一个产品包的产物
  • 申请的许可与对应产品包的版本不一致
  • 手机未开启存储读写权限
  1. 导入工程

方式一
打开工程

导入工程

指定对应文件夹

导入工程

方式二
在现有工程的settings.gradle中添加配置,实现模块导入

include ':ar_occlusion'
project(':ar_occlusion').projectDir=new File('D:\\OcclusionDemo')
  1. 导入模型数据

将模型数据拷贝至手机目录/SuperMap/PipeData。

具体路径配置,参考PathConfig.java

public static final String SD_CARD = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();/**
* 数据文件夹根路径
* MI 9 Transparent Edition\内部存储设备\SuperMap\PipeData
*/
public static final String PIPE_DATA_PATH = SD_CARD + "/SuperMap/PipeData";/**
* 屋顶通风管道模型组文件夹路径
*/
public static String TOP_PIPE_DATA = PIPE_DATA_PATH + "/Model/top_pipe";/**
* 地下管线模型组
*/
public static String UNDERGROUND_PIPE_DATA = PIPE_DATA_PATH + "/Model/underground_pipe";/**
* 垂直墙面内的管线数据
*/
public static String VERTICAL_PIPE_DATA = PIPE_DATA_PATH + "/Model/pipe_v";
  1. 运行示例

运行示例程序

run

程序运行成功后,会在手机SuperMap/PipeData生成以下内容

  • ImgData
  • license
  • Log
  • app.cfg

run

app.cfg(default.cfg)、ImgData(包含一张名为“mark.png”的图片)可在工程的assets目录下找到

run

  1. 示例程序使用流程
  • 打印“mark.png”,将其布置在场景中

  • 启动程序,进入主界面

使用流程

  • 点击 “定位”,扫描“mark.png”,加载场景

使用流程

  • 点击 “视口模式”,行走浏览

    可通过手势调节开挖参数,具体操作见程序演示

  • 点击"卷帘模式",行走浏览

    可通过手势调节显示范围,具体操作见程序演示

代码定位

场景加载

实现通过扫码的方式加载场景。

见MarkerConfig,涉及Marker的初始位置、图片资源路径的相关信息。

见ScanLayout,涉及布局设置和图片识别相关的接口(ImageScanner)调用。

/**
* 开启图片扫描功能
* @param arEffectView AR视图
* @param callback 扫描结果回调
*/
public void startImageScan(AREffectView arEffectView,ScanCallback callback){//...
}/**
* 结束图片扫描
* @param arEffectView AR视图
*/
private void stopScan(AREffectView arEffectView) {//...
}

见DataManager,涉及数据的加载.

/**
* 添加管线场景
* @param parent 父节点
* @param dataPath 数据路径
* @param enabled 启用点击交互
* @param type 数据类型
*/
public void addPipeScene(AREffectElement parent,String dataPath,boolean enabled,Type type){//...
}/**
* 添加管线场景
* @param parent 父节点
* @param dataPath 数据路径
* @param enabled 启用点击交互
*/
public void addPipeScene(AREffectElement parent,String dataPath,boolean enabled) {//...
}

视口模式

实现在视口模式下,对墙内管线模型进行开挖显示。

见ViewportFuncLayout,涉及布局设置。

见ExcavatorManager,涉及开挖参数的计算、坑洞对象渲染和屏幕显示范围构成的点集的更新。

private EffectView.OnUpdateListener onUpdateListener = new OnUpdateListener() {@Overridepublic void onUpdate() {//开挖参数计算->坑洞对象渲染->更新屏幕显示范围构成的点集}

卷帘模式

实现类似卷帘的效果。

实现原理上,比视口模式更简单。直接根据分割线计算出屏幕显示范围构成的点集即可。

见RollingFuncLayout,涉及布局设置。

屏幕范围裁剪

见ScreenPointManager,统一管理屏幕显示范围构成的点集,当点集更新时,触发update回调。在回调事件里执行屏幕范围裁剪。

//在PipeActivity中
ScreenPointManager.getInstance().setOnUpdatePointListener(new ScreenPointManager.OnUpdatePointListener() {@Overridepublic void update(List<ArrayList<int[]>> screenPoint,List<ArrayList<int[]>> bottomScreenPoint) {//...裁剪屏幕显示范围}
});

开挖参数调节

在视口模式中,涉及通过手势去修改开挖参数。

在最初的版本中,是通过SeekBar的方式去修改开挖参数。

参数修改

参数修改

当前版本修改为通过手势去修改开挖参数。

参数修改

见CustomGesture,涉及单指、双指手势的定义。
见DigGestureManager,涉及开挖参数修改的手势管理。

见DynamicView,在布局上位于最顶部,用于接收MotionEvent,分发onTouch事件。

@Override
public boolean onTouch(View v, MotionEvent event) {//...
}

程序演示

注: 以下内容非最终成果,仅是迭代过程中的录屏。且对应模型数据需要结合对应场景,才可正确地显示。

v1.0

示例程序的录屏

补充说明

实现方式

对每一帧显示的AR内容进行裁剪的方式来实现只显示坑洞范围内的AR内容。

在EffectView#OnUpdateListener的onUpdate事件中,重复执行以下步骤。

  • 构建开挖参数ExcavationParameter
  • Excavator#generateHitPoint 生成碰撞点
  • Excavator#calculate 根据开挖参数进行计算
  • PitObject#updateMesh 更新坑洞对象的网格
  • OcclusionHelper#setUniquePointList 设置屏幕裁剪的范围
  • OcclusionHelper#refresh 刷新

简单示例

//遮挡设置
occlusionHelper = arView.getOcclusionHelper();
occlusionHelper.init(0.36f).setRenderMode(OcclusionHelper.RenderMode.NORMAL);List  roomBounds = Arrays.asList(new Point3D(-1, -1, -2),new Point3D(-1, 6, -2),new Point3D(6, 6, -2),new Point3D(6, -1, -2),new Point3D(-1, -1, -2)
);//采用ARGeoPrism,构建“检测墙”
ARGeoPrism geoVerticalRegion = new ARGeoPrism();
geoVerticalRegion.setParentNode(arView);
//仅用作射线检测,渲染状态设置为false
geoVerticalRegion.setRenderable(false);
geoVerticalRegion.addPart(roomBounds,6.0f);//创建开挖工具,在这之前,需确认AREffectView开启了遮挡设置
//Excavator所有子类使用方法一致
excavatorWall = new WallExcavator(geoVerticalRegion);
//坑洞纹理
Bitmap bitmap=null;
Bitmap bitmap2=null;
try {InputStream is = getApplicationContext().getAssets().open("brown_mud_dry2.png");bitmap= BitmapFactory.decodeStream(is);InputStream is2 = getApplicationContext().getAssets().open("wall_texture.png");bitmap2= BitmapFactory.decodeStream(is2);is.close();is2.close();
} catch (IOException e) {
}//创建坑洞渲染对象
pitWall = new PitObject(excavatorWall).setTexture(bitmap,bitmap2);//在每一帧刷新时调用(通常使用EffectView.addOnUpdateListener(EffectView.OnUpdateListener)添加帧监听事件)
arView.addOnUpdateListener(()->{//开挖计算墙面碰撞点 arView为AREffectView、screenPointX/Y为对应的屏幕坐标//以屏幕中心计算碰撞点Point3D hitPoint = excavatorWall.generateHitPoint(arView, screenPointX, screenPointY);if (hitPoint!=null){//desc-执行开挖的顶点计算(开挖参数)excavatorWall.calculate(ExcavationParameter.builder().setRadius(radius).setOffset(offset).setInnerMargin(0).setCenterPoint(hitPoint).build());}//渲染坑洞结果pitWall.updateMesh();if (occlusionHelper.isEnabled()){//desc-执行画面裁剪ArrayList  screenPoint = null;if (excavatorWall !=null){//计算屏幕坐标screenPoint = excavatorWall.getScreenPoint(null);if (screenPoint!=null){//根据屏幕坐标刷新裁剪范围occlusionHelper.setUniquePointList(screenPoint).refresh();}}}
})

AR开发专栏

原生开发?就用这做AR

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/1419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud 运维篇1——Jenkins CI/CD 持续集成部署

Jenkins 1、Jenkins是什么&#xff1f; Jenkins 是一款开源 CI/CD 软件&#xff0c;用于自动化各种任务&#xff0c;包括构建、测试和部署软件。 Jenkins 支持各种运行方式&#xff0c;可通过系统包、Docker 或者一个独立的 Java 程序。 Jenkins Docker Compose持续集成流…

k8s安装,linux-ubuntu上面kubernetes详细安装过程

官方文档&#xff1a;https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/ 环境配置 该部分每个主机都要执行 如果你确定不需要某个特定设置&#xff0c;则可以跳过它。 设置root登录 sudo passwd root sudo vim /etc/ssh/sshd_config Perm…

HarmonyOS NEXT 使用XComponent + Vsync 实现自定义动画

介绍 XComponent 提供了应用在 native 侧调用 OpenGLES 图形接口的能力&#xff0c;本文主要介绍如何配合 Vsync 事件&#xff0c;完成自定义动画。在这种实现方式下&#xff0c;自定义动画的绘制不在 UI 主线程中完成&#xff0c;即使主线程卡顿&#xff0c;动画效果也不会受…

晶圆制造之MPW(多项目晶圆)简介

01、MPW是什么&#xff1f; 在半导体行业中&#xff0c;MPW 是 "Multi Project Wafer" 的缩写&#xff0c;中文意思是多项目晶圆。MPW 的主要思想是将使用相同工艺的多个集成电路设计放在同一晶圆片上进行流片&#xff08;即制造&#xff09;。这种方法允许多个设计共…

java学习笔记6

11. 类的封装 ​ 在Java中,**封装(Encapsulation)**是面向对象编程中的重要概念,它指的是将类的数据(属性)和行为(方法)绑定在一起,并对外部隐藏数据的具体实现细节,只通过公共方法来访问和操作数据。这有助于提高代码的安全性、可维护性和灵活性。 11.1 为什要封装 …

Python exe 文件反编译为 Python 脚本

文章目录 前言版本反编译Python 可执行文件&#xff08;.exe&#xff09;反编译打包一个简单的 .exe 可执行文件提取 pyc 文件使用脚本提取使用工具提取 将 .pyc 文件转换为 Python 脚本入口运行类非入口运行类转换补全后的 pyc 文件uncompyle6 反编译在线工具 可能遇到的问题P…

如何在在wordpress安装百度统计

前言 看过我的往期文章的都知道&#xff0c;我又建了一个网站&#xff0c;这次是来真的了。于是&#xff0c;最近在查阅资料时发现&#xff0c;有一款免费的软件可以帮我吗分析网站数据。&#xff08;虽然我的破烂网站压根没人访问&#xff0c;但是能装上的都得上&#xff0c;…

探索边缘计算:技术的新疆界

探索边缘计算&#xff1a;技术的新疆界 在当今迅速发展的数字化时代&#xff0c;云计算作为数据处理的主力军已广泛应用。但是&#xff0c;随着物联网&#xff08;IoT&#xff09;设备的急剧增加和数据生成速率的加快&#xff0c;云计算面临着种种挑战。边缘计算因此诞生&…

STL-list的使用及其模拟实现

在C标准库中&#xff0c;list 是一个双向链表容器&#xff0c;用于存储一系列元素。与 vector 和 deque 等容器不同&#xff0c;list 使用带头双向循环链表的数据结构来组织元素&#xff0c;因此list插入删除的效率非常高。 list的使用 list的构造函数 list迭代器 list的成员函…

深度神经网络(DNN)

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个深度神经网络&#xff08;DNN&#xff09;模型程序,最后打印5个条件分别的影响力。 示例 在深度神经网络&#xf…

Matlab新手快速上手2(粒子群算法)

本文根据一个较为简单的粒子群算法框架详细分析粒子群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 粒子群算法简介 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;是一种群体智能优化算法&#xff0c;灵感来源于…

目标检测YOLO数据集的三种格式及转换

目标检测YOLO数据集的三种格式 在目标检测领域&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;算法是一个流行的选择。为了训练和测试YOLO模型&#xff0c;需要将数据集格式化为YOLO可以识别的格式。以下是三种常见的YOLO数据集格式及其特点和转换方法。 1. YOL…

计算机系统结构(二) (万字长文建议收藏)

计算机系统结构 (二) 本文首发于个人博客网站&#xff1a;http://www.blog.lekshome.top/由于CSDN并不是本人主要的内容输出平台&#xff0c;所以大多数博客直接由md文档导入且缺少审查和维护&#xff0c;如果存在图片或其他格式错误可以前往上述网站进行查看CSDN留言不一定能够…

大话设计模式-里氏代换原则

里氏代换原则&#xff08;Liskov Substitution Principle&#xff0c;LSP&#xff09; 概念 里氏代换原则是面向对象设计的基本原则之一&#xff0c;由美国计算机科学家芭芭拉利斯科夫&#xff08;Barbara Liskov&#xff09;提出。这个原则定义了子类型之间的关系&#xff0…

【人工智能基础】经典逻辑与归结原理

本章节的大部分内容与离散数学的命题、谓词两章重合。 假言推理的合式公式形式 R,R→P⇒PR,R∨P⇒P 链式推理 R→P,P→Q⇒R→QR∨P,P∨Q⇒R∨Q 互补文字&#xff1a;P和P 亲本子句&#xff1a;含有互补文字的子句 R∨P,P∨Q为亲本子句 注意&#xff1a; 必须化成析取范式…

命理八字之电子木鱼的代码实现

#uniapp# #电子木鱼# 不讲废话&#xff0c;上截图 目录结构如下图 功能描述&#xff1a; 点击一下&#xff0c;敲一下&#xff0c;伴随敲击声&#xff0c;可自动点击。自动点击需看视频广告&#xff0c;或者升级VIP会员。 疑点解答&#xff1a; 即animation动画的时候&…

Window中Jenkins部署asp/net core web主要配置

代码如下 D: cd D:\tempjenkins\src\ --git工作目录 dotnet restore -s "https://nuget.cdn.azure.cn/v3/index.json" --nuget dotnet build dotnet publish -c release -o %publishPath% --发布路径

Day08React——第八天

useEffect 概念&#xff1a;useEffect 是一个 React Hook 函数&#xff0c;用于在React组件中创建不是由事件引起而是由渲染本身引起的操作&#xff0c;比如发送AJAx请求&#xff0c;更改daom等等 需求&#xff1a;在组件渲染完毕后&#xff0c;立刻从服务器获取频道列表数据…

Java:二叉树(1)

从现在开始&#xff0c;我们进入二叉树的学习&#xff0c;二叉树是数据结构的重点部分&#xff0c;在了解这个结构之前&#xff0c;我们先来了解一下什么是树型结构吧&#xff01; 一、树型结构 1、树型结构简介 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>…

Matlab无基础快速上手1(遗传算法框架)

本文用经典遗传算法框架模板&#xff0c;对matlab新手友好&#xff0c;快速上手看懂matlab代码&#xff0c;快速应用实践&#xff0c;源代码在文末给出。 基本原理&#xff1a; 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种受生物学启发的优化算法…