[ARCore] 01 - Plane Detection
前言
Code from HelloArActivity.
Plane detection 是最大最有用的feature,这里讲解跟plane相关的知识点。
文档学习
一、疑点
Sceneform 概览
通过配置,启用 ARCore
二、图像特征点匹配
- 图像数据库
- 新建并加入图片
Bitmap bitmap;
try (InputStream inputStream = getAssets().open("dog.jpg")) {
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (IOException e) {
Log.e(TAG, "I/O exception loading augmented image bitmap.", e);
}
int index = imageDatabase.addImage("dog", bitmap, imageWidthInMeters);
- 加载已有数据库
InputStream inputStream = context.getAssets().open("example.imgdb");
AugmentedImageDatabase imageDatabase = AugmentedImageDatabase.deserialize(inputStream);
从图像目录创建图像数据库
./arcoreimg build-db --input_images_directory=/path/to/images \
--output_db_path=/path/to/myimages.imgdb
从图像列表文件创建数据库(首选)
./arcoreimg build-db --input_image_list_path=/path/to/image_list_file.txt \
--output_db_path=/path/to/myimages.imgdb
- 开始追踪图像
config.setAugmentedImageDatabase(imageDatabase);
session.configure(config);
- 循环 Detect 每一帧
// Update loop, in onDrawFrame().
Frame frame = mSession.update();
Collection<AugmentedImage> updatedAugmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
for (AugmentedImage img : updatedAugmentedImages) {
// Developers can:
// 1. Check tracking state.
// 2. Render something based on the pose, or attach an anchor.
if (img.getTrackingState() == TrackingState.TRACKING) {
// You can also check which image this is based on getName().
if (img.getIndex() == dogIndex) {
// TODO: Render a 3D version of a dog in front of img.getCenterPose().
} else if (img.getIndex() == catIndex) {
// TODO: Render a 3D version of a cat in front of img.getCenterPose().
}
}
}
三、arcoreimg
是一个命令行工具
仅适用于 Android 和 Android NDK 开发者。
它内置于 Unity SDK 和 ARCore Unreal 插件中。
检查参考图像的质量:
./arcoreimg eval-img dog.png
四、Cloud Anchor
云锚点,它允许多个设备使用云来共享真实世界场景中的对象信息。
这将启用多个 ARCore 设备用户之间的协作,以便他们可以共同在公共空间内绘制或操纵AR对象,从每个人的角度正确显示跟踪的对象位置。
五、Sceneform
- 添加一个
ArFragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.google.ar.sceneform.samples.hellosceneform.HelloSceneformActivity">
<fragment android:name="com.google.ar.sceneform.ux.ArFragment"
android:id="@+id/ux_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
- ArSceneView
Fragment 会自动执行某些规定的检查后,Fragment 会创建一个 ArSceneView。
- 创建一个可渲染对象
Renderable
是一个 3D 模型,包括可由 Sceneform 在界面上渲染的网格、材料和纹理。
3D模型文件格式:obj文件
由Alias|Wavefront公司为3D建模和动画软件"Advanced Visualizer"开发的一种标准,适合用于3D软件模型之间的互导,也可以通过Maya读写。
OBJ文件是一种文本文件,可以直接用写字板打开进行查看和编辑修改。另外,有一种与此相关二进制文件格式(*.MOD),其作为专利未公开,因此这里不作讨论。
(1) 根据一个 3D 资产文件 andy.obj
创建可渲染对象。
apply plugin: 'com.google.ar.sceneform.plugin'
sceneform.asset('sampledata/models/andy.obj',
'default',
'sampledata/models/andy.sfa',
'src/main/res/raw/andy')
(2) 将资源加载为可渲染对象的方法
ModelRenderable.builder()
.setSource(this, R.raw.andy)
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Log.e(TAG, "Unable to load Renderable.", throwable);
return null;
});
- 节点 node
每个节点都包含 Sceneform 对其进行渲染所需的全部信息(包括其位置、屏幕方向和可渲染对象)以及与其进行交互所需的全部信息(包括其碰撞形状和事件侦听器)。
可将节点添加到其他节点,从而形成父级-子级关系。 当节点是其他节点的子级时,将随其父级移动、旋转和缩放——就好比您的臂部会在您的身体移动时随之摆动。
一个节点可有多个子级,但只能有一个父级,从而形成一种树状结构。 这种结构称为场景图。
- Node node = new Node(); node.setParent(arFragment.getArSceneView().getScene()); node.setRenderable(andyRenderable);
六、构建三维场景
-
res > layout 中创建一个布局文件
Node
with setRenderable(Renderable)
.
- 构建 ViewRenderable
ViewRenderable.builder() .setView(this, R.layout.test_view) .build() .thenAccept(renderable -> testViewRenderable = renderable);
七、以动画形式呈现节点
The official one is Unity, this is Java version: https://github.com/fjbatresv/arcore_solar_system
- 通过 ObjectAnimator 以动画形式呈现
聚光灯强度的示例:
final int durationInMilliseconds = 1000; final float minimumIntensity = 1000.0f; final float maximumIntensity = 3000.0f; ValueAnimator intensityAnimator = ObjectAnimator.ofFloat( spotlightNode.getLight(), "intensity", minimumIntensity, maximumIntensity); intensityAnimator.setDuration(durationInMilliseconds); intensityAnimator.setRepeatCount(ValueAnimator.INFINITE); intensityAnimator.setRepeatMode(ValueAnimator.REVERSE); intensityAnimator.start();
重写节点的 onUpdate()
,在帧与帧之间将其以动画形式呈现。
@Override public void onUpdate(FrameTime frameTime) { Vector3 cameraPosition = getScene().getCamera().getWorldPosition(); Vector3 cardPosition = infoCard.getWorldPosition(); Vector3 direction = Vector3.subtract(cameraPosition, cardPosition); Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up()); infoCard.setWorldRotation(lookRotation); }
- 添加灯
Light spotLightYellow = Light.builder(this, Light.Type.FOCUSED_SPOTLIGHT) .setColor(new Color(android.graphics.Color.YELLOW)) .setShadowCastingEnabled(true) .build();
- 平面显示
渲染检测到的平面的默认材料和纹理。
Texture.Sampler sampler = Texture.Sampler.builder() .setMinMagFilter(Texture.Sampler.MagFilter.LINEAR) .setWrapMode(Texture.Sampler.WrapMode.REPEAT) .build(); Texture.builder() .setSource(this, R.drawable.custom_texture) .setSampler(sampler) .build() .thenAccept(texture -> { arSceneView .getPlanerRenderer() .getMaterial() .setTexture(PlaneRenderer.MATERIAL_TEXTURE, customTexture); });
- 阴影
默认情况下,太阳已启用阴影投射,但灯未启用。 调用 setShadowCastingEnabled()
可以打开阴影投射。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律