创建您的第一个ARCore应用程序

创建您的第一个ARCore应用程序


上一篇文章中,我已经解释了ARCore是什么以及它如何帮助开发人员在无需了解数学和OpenGL的情况下创建惊人的增强现实应用程序。


如果您还没有阅读它,我强烈建议您继续阅读本文,然后开始开发ARCore应用程序。


开始使用


要开始开发ARCore应用程序,您首先需要向项目添加ARCore支持。 这非常简单,因为我们将使用Android Studio和Sceneform SDK。 Sceneform自动执行两个主要操作:


  1. 检查ARCore。
  2. 请求使用相机的权限。

使用Sceneform SDK创建ARCore应用程序时,您无需担心这两个步骤。 您只需要将Sceneform SDK添加到您的项目中即可。


使用一个空的Activity创建一个新的Android Studio项目。


将以下依赖项添加到项目级别的build.gradle文件中:


 dependencies { classpath 'com.google.ar.sceneform:plugin:1.5.0' } 

并将此依赖项添加到应用程序级别的build.gradle文件中:


 implementation "com.google.ar.sceneform.ux:sceneform-ux:1.5.0" 

现在,将项目与Gradle文件同步,并等待构建完成。 因此,用于Android Studio的Sceneform SDK和Sceneform插件将添加到项目中。 这将允许您查看.sfb ,这些.sfb是将在相机中渲染的3D模型,还可以帮助您导入,查看和创建3D资源。


创建您的第一个ARCore应用程序


现在,Android Studio设置已完成,并且已经安装了Sceneform SDK,我们可以开始创建第一个ARCore应用程序了。


首先,我们需要在场景中添加一个Sceneform片段。 这就是我们所有3D模型将被放置的所谓场景 。 该片段将负责初始化摄像机并自行处理权限。


转到主布局文件。 就我而言,这是activity_main.xml文件。 并在其中添加Sceneform片段:


 <?xml version="1.0" encoding="utf-8"?> <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=".MainActivity"> <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> 

我设置match_parent的宽度和高度,以使场景全屏显示。 您可以根据需要选择尺寸。


兼容性检查


这是您在布局文件中需要做的所有事情。 现在我们传递给Activity,在我的例子中是MainActivity 。 向活动添加方法:


 public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.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; } 

此方法检查您的设备是否支持Sceneform SDK。 该SDK需要Android API级别27或更高以及OpenGL ES 3.0或更高版本。 如果设备不支持这两个参数,则将不会加载场景,并且您的应用程序将显示黑屏。


但是,您仍然可以实现应用程序的所有其他功能,这些功能不需要Sceneform SDK。


检查兼容性后,我们可以创建3D模型并将其附加到场景。


添加资产


现在,您需要将3D模型添加到将在屏幕上显示的项目中。 如果您熟悉创建它们的过程,则可以自己创建这些模型。 或者,您可以转到Poly


在那里,您将找到可供选择的庞大3D资源库。 此外,它们可以免费下载。


保利


在Android Studio中,在左窗格中打开您的应用程序文件夹。 您需要一个sampledata文件夹。 该文件夹将包含您的所有3D模型。 在此文件夹中,创建一个包含您的模型名称的文件夹。


在从Poly下载的档案中,您很可能会找到3个文件:


  1. .mtl文件
  2. .obj文件
  3. .png文件

这三个文件中最重要的是.obj文件。 这是您的模型。 将所有3个文件放入sampledata->“您的模型文件夹”中


3D模型的路径


现在,右键单击.obj文件。 第一个选项是Import Sceneform Asset 。 单击它,不更改默认设置,只需在下一个窗口中单击完成 。 之后,将项目与Gradle文件同步。


将在项目中使用的3D资源导入完成。 接下来,让我们在代码中使用3D模型并将其包含在场景中。


模型制作


将以下代码添加到您的活动中,我将逐行进行解释:


 private static final String TAG = MainActivity.class.getSimpleName(); private static final double MIN_OPENGL_VERSION = 3.0; ArFragment arFragment; ModelRenderable lampPostRenderable; @Override @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment); ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; }); } 

首先,我们找到arFragment ,我们先前已将其添加到布局中。 该片段负责场景的存储和操作。 您可以将其想象为我们场景的容器。


接下来,我们使用ModelRenderable类构建模型。 使用setSource方法setSource我们从导入资源时生成的.sfb文件加载模型。 thenAccept方法在创建模型后获取模型,然后将加载的模型设置为变量lampPostRenderable


对于错误处理,我们有一个exceptionally方法,如果发生异常,则调用该方法。


所有这些都是异步发生的,因此您不必担心多线程。


现在已经加载了模型并将其保存在lampPostRenderable变量中,我们将其添加到场景中。


向场景添加模型


我们的场景位于arFragment ,它将接收用户触摸事件。 因此,我们需要为片段安装一个onTap侦听器,以便处理触摸并将对象放置在需要的位置。 将以下代码添加到onCreate方法:


 arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; } Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene()); TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); } ); 

我们为我们的AR片段设置了onTapArPlaneListener侦听器。 以下语法用于lambda表达式。 如果您不熟悉它,请查看有关此主题的本小指南


首先,我们使用hitresult.createAnchor()HitResult创建 ,并将其保存在Anchor对象中。


然后,我们从该锚点创建一个节点 。 它将被称为AnchorNode并将使用setParent方法连接到场景。


接下来,我们创建一个TransformableNode ,它将成为我们的模型,并将其绑定到我们的节点。 TransformableNode仍然没有任何有关它应显示的对象的信息。 我们将使用setRenderable方法将此对象传递给它,该方法将ModelRenderable类型的对象作为参数(记住,我们得到了这样的对象并将其命名为lampPostRenderable ?)。 最后,我们调用lamp.select()方法;


哦! 术语过多。 不用担心,我现在将解释所有内容:


  1. 场景 :这是将显示所有3D对象的地方。 该场景位于我们添加到布局的AR片段中。


  2. HitResult :这是一条来自无限远的假想线(或射线),它给出了其与现实世界对象的交点。


  3. 锚点 :这是现实世界中的固定位置和方向。 可以理解为三维空间中的坐标(x,y,z)。 姿势是对象在舞台上的位置和方向。 它用于将对象的局部坐标空间转换为真实坐标空间。


  4. 锚点节点 :这是一个自动在现实世界中定位的节点。 这是检测到平面时安装的第一个节点。


  5. TransformableNode :这是您可以与之交互的节点。 可以移动,缩放,旋转等。 在此示例中,我们可以缩放对象并旋转它。 因此,名称为可变形。



没有火箭科学。 这确实相对简单。 整个场景可以以图形的形式查看,其中父级为场景,子级为锚节点,然后将其分支为其他各种节点和对象,这些对象将在屏幕上显示。


因此,您的活动应如下所示:


 package com.ayusch.arcorefirst; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.net.Uri; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.widget.Toast; import com.google.ar.core.Anchor; import com.google.ar.core.HitResult; import com.google.ar.core.Plane; import com.google.ar.sceneform.AnchorNode; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.TransformableNode; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private static final double MIN_OPENGL_VERSION = 3.0; ArFragment arFragment; ModelRenderable lampPostRenderable; @Override @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment); ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; }); arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; } Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene()); TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); } ); } public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.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; } } 

恭喜你! 您刚刚完成了第一个ARCore应用程序的创建。 开始向其中添加对象,您将看到它们如何开始在现实世界中栩栩如生。


这是您第一次了解如何在Android Studio中从头开始创建简单的ARCore应用程序。 在下一课中,我将深入研究ARCore,并为应用程序添加更多功能。

Source: https://habr.com/ru/post/zh-CN438178/


All Articles