[ARCore] 01 - Plane Detection

前言


Code from HelloArActivity

文档:探究 HelloAR 示例应用代码

Plane detection 是最大最有用的feature,这里讲解跟plane相关的知识点。

 

 

 

文档学习


一、疑点

Sceneform 概览

通过配置,启用 ARCore

 

 

二、图像特征点匹配

  • 图像数据库

链接:AugmentedImageDatabase

 

  • 新建并加入图片
复制代码
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 中创建一个布局文件 

从标准的 Android 微件创建 ViewRenderable。 它们将在场景中渲染为平坦的卡片。
 
public class ViewRenderable
Renders a 2D Android view in 3D space by attaching it to a Node with setRenderable(Renderable).
By default, the size of the view is 1 meter in the Scene per 250dp in the layout. Use a ViewSizer to control how the size of the view in the Scene is calculated.

 

  • 构建 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() 可以打开阴影投射。

  

posted @   郝壹贰叁  阅读(1391)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示