您的位置 首页 java

安卓增强现实开发入门「ARCore」

在本文中,我们将深入研究 Android AR 的世界,即 增强现实 ,特别是 ARCore 谷歌 用于构建 AR 体验的平台。我们将看到 ARCore 如何通过抽象出复杂的矩阵和矢量数学并为我们提供用于 AR 开发的漂亮 API 来改变 AR 应用程序开发。

首先,让我们看看增强现实是什么,以及为什么我们作为开发人员应该对这项新技术感到非常兴奋!

1、什么是增强现实?

根据 定义,增强现实是“一种将计算机生成的图像叠加在用户对现实世界的看法上,从而提供复合视图的技术”。

从本质上讲,AR 是一种技术,它使我们能够将计算机生成的 3D 对象模型渲染到现实世界中,并让它与周围环境进行交互,就好像它实际存在于同一位置一样。

该技术在以下领域有广泛的应用:

  • 教育:想象一下在你的办公桌上有一个人脑的 3D 模型。
  • 旅游:将流行古迹的 3D 模型放置在物理世界中。
  • 家具零售:购买前检查椅子在客厅中的外观指南。
  • 电子商务:在你面前以 3D 形式查看新服装。
  • 医学和医疗保健:在化学实验室内拥有药物中存在的各种蛋白质的 3D 模型。
  • 还有很多…

几年前,开发 AR 应用程序意味着学习 OpenGL 和复杂的矢量数学。2018 年, Google 发布了 ARCore 以及 Sceneform SDK(适用于 android),以使每个人都可以更轻松地进行 AR 开发。那么,让我们来看看 ARCore 提供了什么。

2、什么是 ARCore?

根据 Google提供的定义,ARCore 是一个用于构建 Android AR 体验的平台。它使你的手机能够感知其环境、了解世界并与信息交互。

ARCore 遵循 3 个原则:

  • 运动跟踪:它允许手机了解其相对于现实世界的当前位置。
  • 了解环境:它允许手机检测所有类型表面的大小和位置:垂直、水平和倾斜。
  • 光照估计:它可以让手机感知环境的光照条件。

当用户在现实世界中移动他/她的手机时,ARCore 能够了解其周围环境并以数字方式模拟现实世界,它可以在其中放置物体。运动跟踪帮助 ARCore 识别特征,使其能够跟踪其与真实环境相关的位置。

截至目前,ARCore 可用于:

  • java (安卓)
  • 统一(iOS 和 Android)
  • 虚幻引擎
  • iOS

此列表涵盖了大多数用于 AR 应用程序开发的设备和开发平台:

3、场景形式

ARCore 本身不是 SDK,而是帮助 SDK 渲染对象的引擎。因此,为了利用这一功能,Google 发布了 Sceneform SDK,让开发者无需学习 OpenGL 即可构建 Android AR 应用。

Sceneform 具有许多漂亮的功能,例如:

  • 对支持 ARCore 的手机进行自动兼容性检查。
  • 检查相机权限。
  • 用于抽象所有复杂性的场景图 API。
  • 用于操作 3D 资产的插件。

我们现在将深入研究使用 Sceneform 构建示例 Android AR 应用程序,构建一个简单的 Android AR 应用程序并将一些 3D 对象渲染到现实世界中,这将帮助你更深入地了解 Sceneform 和 ARCore。

完成的应用程序如下所示:

4、 开发环境 设置

让我们开始吧,首先创建一个带有空活动的新项目。

5、添加 Sceneform 插件

你需要将 Sceneform 插件安装到 android studio 。Sceneform 插件将帮助你完成诸如将模型导入 Android 项目等任务。

为了安装插件,请按照以下步骤操作:

  • 对于 Windows 用户:转到:文件-> 设置-> 插件
  • 对于 macOS 用户:转到:Android Studio-> 首选项-> 插件
  • 现在在搜索栏中输入“场景形式”。它将位于名为 Google Sceneform Tools 的顶部。
  • 安装插件并重启android studio。

  • 添加依赖项

将以下依赖项添加到你的应用级 build. gradle 文件中:

 implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.9.0'  

重要提示:Sceneform SDK 要求 minSdkVersion 大于或等于 24。因此,请确保设置 minSdkVersion>= 24。此外,请确保已将 Maven 存储库包含在项目级别的 build.gradle 中。

  • 更新清单

在你的 AndroidMan if est.xml 文件中添加以下行:

 <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:name="android.hardware.camera.ar" android:required="true"/>  

使用 ARCore 需要摄像头权限和支持摄像头的手机(显然)。

此外,将元数据添加到你的应用程序标签:

 <meta-data
   android:name="com.google.ar.core"
   android:value="required" />  

如果你的应用严格要求设备启用 ARCore,则设置 required = true 或者如果 AR 不是主要功能或者你已经处理了非兼容设备的兼容性,则可以设置 required = false。

  • 添加 ArFragment

完成所有初始设置后,现在可以开始将 ArFragment(在 Sceneform SDK 中提供)添加到我们的应用程序中。ArFragment 自动处理你的会话和应用程序工作所需的运行时检查。

如果用户的设备上没有安装 ARCore,ArFragment 会敦促用户安装 ARCore。此外,如果未授予摄像头权限,它也会请求摄像头权限。因此,ArFragment 是开始构建您的第一个 Android ARCore 应用程序的最佳方式。

但是,如果你的应用仍然需要一些扩展功能,你始终可以继承 ArFragment 并创建自己的 Fragment 来支持自定义功能。

这是布局 xml 文件的内容:

 <FrameLayout xmlns:android="#34;
   xmlns:tools="#34;
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".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>  
  • 在运行时检查兼容性

我们将检查设备是否:

  1. 正在运行 Android API 版本 >= 24。
  2. 可以支持OpenGL 3.0版本。

上述条件是设备支持使用 ARCore 和 Sceneform SDK 的 AR 应用的必备条件。

如果不满足这些条件,我们打算完成活动。但是,你仍然可以继续支持其他功能。

  • 将 3D 模型添加到我们的应用程序

现在是时候下载并导入要渲染到我们的应用程序中的 3D 模型了。在我们的例子中,我们将在房间的一角渲染一把 3D 椅子并移动它。

你可以从任何地方下载 3D 模型,但 Google 提供了一个出色的存储库 POLY 来为您的应用程序下载 3D 模型。你可以下载 .obj 或 .gltf 格式的模型。我们将下载 .obj 文件。

在你的 android studio 项目中打开项目视图并展开 app 文件夹。你会注意到一个名为“sampledata”的文件夹。如果没有,请继续创建一个。

模型下载完成后,你需要将下载的 zip 文件解压缩到此示例数据文件夹中。

你将找到模型的 .mtl 文件、.obj 文件和 png 图像。我们将使用 sceneform 插件在我们的应用程序中导入 .obj 文件。

  • 使用 Sceneform 插件导入模型

右键单击 .obj 文件,你将找到一个选项“导入 Sceneform 资源”。单击它并将设置保留为默认值。完成导入后,gradle 将同步项目以将资产包含在您的应用程序中。

这样,你就完成了将 3D 资产导入应用程序的过程。现在是时候编写一些代码将模型包含到 AR 场景中了。

6、构建模型

在您的 java 文件中添加以下代码:

 protected  void  onCreate(Bundle savedInstance State ) {
   super.onCreate(savedInstanceState);

   if (!checkIsSupportedDeviceOrFinish(this)) {
       return;
   }

   setContentView(R.layout.activity_ux);
   arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);

   arFragment.setOnTapArPlaneListener(
           (HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {

               Anchor anchor = hitResult.createAnchor();
               placeObject(arFragment, anchor, Uri.parse("model.sfb"));

           });
}  

让我们看看这里发生了什么。

  1. 首先,我们在 supportFragmentManager 和片段 id 的帮助下获得了我们在布局文件中添加的片段。
  2. 然后我们需要将模型加载到场景中。为此,我们使用 Sceneform SDK 提供的 ModelRenderable 类。借助 ModelRenderable 的 setSource() 方法,我们可以通过传入生成的 .sfb 文件的名称来加载我们的模型。
  3. 模型是在后台线程上构建的,因此在加载模型后,它会呈现给主线程,然后将其渲染到场景中。
  4. 我们在 thenAccept 方法中接收模型。如果在构建模型时出现任何错误,则会引发异常。

我们的模型已加载,现在让我们将其放入场景中。

7、将模型添加到 AR 场景

我们的 AR 片段是场景的容器,因此需要在片段被点击时添加一个模型。因此,我们将在片段中添加一个 onTapListener。

  private  void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) {
   ModelRenderable.builder()
           .setSource(arFragment.getContext(), uri)
           .build()
           .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable))
           .exceptionally(throwable -> {
                       Toast.makeText(arFragment.getContext(), "Error:" + throwable.getMessage(), Toast.LENGTH_LONG).show();
                       return null;
                   }

           );

}

private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) {
   AnchorNode anchorNode = new AnchorNode(anchor);
   TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
   node.setRenderable(renderable);
   node.setParent(anchorNode);
   arFragment.getArSceneView().getScene().addChild(anchorNode);
   node.select();
}


public  static  boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
   if (Build.VERSION.SDK_INT < VERSION_CODES.N) {
       Log.e(TAG, "Sceneform requires Android N or later");
       Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show();
       activity.finish();
       return false;
   }
    String  openGlVersionString =
           ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
                   .getDeviceConfigurationInfo()
                   .getGlEsVersion();
   if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
       Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
       Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
               .show();
       activity.finish();
       return false;
   }
   return true;
}  

使用 hitResult,我们可以获得被点击的位置并创建一个锚节点,它是我们场景的根节点(将增强现实场景图像为倒置树)。

接下来,我们创建一个 TransformableNode 作为椅子并将其设置为锚节点。当用户拖动对象或使用捏合缩放时,可变形节点可以对位置变化和大小变化做出反应。

让我们看一下这里的一些术语:

  • 场景:这是我们的 3D 世界将被渲染的地方。
  • HitResult:它是来自无限远的假想光线,它与现实世界的第一个交点是点击点。
  • 锚点:现实世界中的一个固定位置。用于将本地坐标(根据用户的显示)转换为真实世界坐标。
  • TransformableNode:可以对用户交互(例如旋转、缩放和拖动)做出反应的节点。

这是最终的 java 文件的样子:

 public class HelloSceneformActivity  extends  AppCompatActivity {
   private static final String TAG = HelloSceneformActivity.class.getSimpleName();
   private static final double MIN_OPENGL_VERSION = 3.0;

   private ArFragment arFragment;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       if (!checkIsSupportedDeviceOrFinish(this)) {
           return;
       }

       setContentView(R.layout.activity_ux);
       arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);

       arFragment.setOnTapArPlaneListener(
               (HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
                   Anchor anchor = hitResult.createAnchor();
                   placeObject(arFragment, anchor, Uri.parse("model.sfb"));

               });
   }

   private void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) {
       ModelRenderable.builder()
               .setSource(arFragment.getContext(), uri)
               .build()
               .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable))
               .exceptionally(throwable -> {
                           Toast.makeText(arFragment.getContext(), "Error:" + throwable.getMessage(), Toast.LENGTH_LONG).show();
                           return null;
                       }

               );

   }

   private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) {
       AnchorNode anchorNode = new AnchorNode(anchor);
       TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
       node.setRenderable(renderable);
       node.setParent(anchorNode);
       arFragment.getArSceneView().getScene().addChild(anchorNode);
       node.select();
   }


   public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
       if (Build.VERSION.SDK_INT < VERSION_CODES.N) {
           Log.e(TAG, "Sceneform requires Android N or later");
           Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show();
           activity.finish();
           return false;
       }
       String openGlVersionString =
               ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
                       .getDeviceConfigurationInfo()
                       .getGlEsVersion();
       if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
           Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
           Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
                   .show();
           activity.finish();
           return false;
       }
       return true;
   }


}  

就是这样!我们已经构建了一个功能齐全的 Android AR 应用程序。你可以在 github 上查看整个源代码 。


原文链接:

文章来源:智云一二三科技

文章标题:安卓增强现实开发入门「ARCore」

文章地址:https://www.zhihuclub.com/181969.shtml

关于作者: 智云科技

热门文章

网站地图