安卓增强现实开发入门
在本文中,我们将深入研究 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 中。
- 更新清单
在你的 AndroidManifest.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="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=".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>
- 在运行时检查兼容性
我们将检查设备是否:
- 正在运行 Android API 版本 >= 24。
- 可以支持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 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"));
});
}
让我们看看这里发生了什么。
- 首先,我们在 supportFragmentManager 和片段 id 的帮助下获得了我们在布局文件中添加的片段。
- 然后我们需要将模型加载到场景中。为此,我们使用 Sceneform SDK 提供的 ModelRenderable 类。借助 ModelRenderable 的 setSource() 方法,我们可以通过传入生成的 .sfb 文件的名称来加载我们的模型。
- 模型是在后台线程上构建的,因此在加载模型后,它会呈现给主线程,然后将其渲染到场景中。
- 我们在 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上查看整个源代码 。
原文链接:Build your first Android AR app using ARCore and Sceneform
BimAnt翻译整理,转载请标明出处