如果您还没有在移动设备上体验过增强现实,让我用一个非常实用的应用程序来演示,它可以让我在院子里添加虚拟圣诞树。
这个应用程序是 IKEA Place,它是一个使用 Apple 的 ARKit API 构建的 iOS 应用程序。
NativeScript 允许您访问 iOS 和 Android API 以使用 JavaScript 构建移动应用程序,ARKit 也不例外。在本文中,我们将了解如何使用 NativeScript 构建您的第一个 AR iOS 应用程序。
注意:
- 要在 iOS 上运行 ARKit,您必须拥有 iPhone 6S+、第五代 iPad 或 iPad Pro。您可以在 Apple 的文档中找到受支持设备的完整列表。
- 对 NativeScript 中 Android 的 ARCore 的支持正在进行中。我们优先考虑 iOS 支持,因为 Android 的 ARCore 仍处于“开发者预览”状态,而 iOS 11 中已发布了 ARKit 的稳定版本。
NativeScript 的 AR 支持可通过 nativescript-ar 插件 获得。该插件将 ARKit API 抽象成一系列易于使用的 API,用于常见的 AR 任务。最终,这些相同的 API 也将支持 Android 的 ARCore,以便您可以从单个代码库构建跨平台的 AR 体验。
要开始使用该插件,让我们首先使用 NativeScript CLI 创建一个新的 NativeScript 应用程序。
tns create AR --template tns-template-blank-ng
cd AR
两点说明
tns-template-blank-ng
模板,您可以创建一个使用 Angular 的新 NativeScript 应用程序,我们将在本文的示例中使用它。但是,您不必使用 Angular 即可在 NativeScript 中使用 AR,并且 nativescript-ar 插件的 GitHub 存储库中提供了非 Angular 使用说明。现在您有了新的应用程序,您需要使用 tns plugin add
命令安装 nativescript-ar 插件。
tns plugin add nativescript-ar
然后,打开应用程序的 app/home/home.component.ts
文件并将以下代码粘贴到其中。
import { Component, OnInit } from "@angular/core";
import { registerElement } from "nativescript-angular/element-registry";
import { ARMaterial } from "nativescript-ar";
import { Color } from "tns-core-modules/color";
registerElement("AR", () => require("nativescript-ar").AR);
@Component({
selector: "demo-ar",
moduleId: module.id,
template: `
<ActionBar title="NativeScript AR"></ActionBar>
<GridLayout class="page">
<AR *ngIf="loaded"
debugLevel="FEATURE_POINTS"
detectPlanes="true"
[planeMaterial]="planeMaterial">
</AR>
</GridLayout>
`
})
export class HomeComponent implements OnInit {
loaded = false;
ngOnInit() {
// Because this is the very first component in the app ensure everything has loaded before starting up.
setTimeout(() => { this.loaded = true; }, 1000);
}
planeMaterial = <ARMaterial>{
diffuse: new Color("white"),
transparency: 0.2
};
}
我们稍后将详细讨论此代码,因为有很多内容。但首先让我们运行该应用程序,以便您可以了解此示例在实际操作中的样子。
与大多数其他 iOS API 不同,您无法使用 iOS 模拟器测试 AR 应用程序。因此,下一步,通过 USB 将您的 iOS 测试设备插入,并运行以下命令将您的应用程序部署到您的设备。
tns run ios
构建和安装完成后,您应该首先看到一个关于相机权限的提示,因为 AR 需要相机访问权限才能工作。
授予权限后,将设备的摄像头对准平坦的表面。几秒钟后,您应该会看到一些点,然后出现一个透明的平面。下面的视频显示了此过程的样子。
提示:确保您正在测试的区域有充足的光线。如果您在黑暗区域,请尝试打开设备的手电筒以提供更多光线。
使用 ARKit 时,您首先需要检测一个平面,然后才能开始与其交互。为了更详细地讨论此处发生的情况,以及您可能希望从这里开始的地方,让我们回到代码并详细分解正在发生的事情。
在 Angular 组件中,template
属性是您定义组件应呈现的 UI 元素的地方。在此 AR 示例中,您的 template
如下所示。
<ActionBar title="NativeScript AR"></ActionBar>
<GridLayout class="page">
<AR *ngIf="loaded"
debugLevel="FEATURE_POINTS"
detectPlanes="true"
[planeMaterial]="planeMaterial">
</AR>
</GridLayout>
<ActionBar>
和 <GridLayout>
是标准的 NativeScript UI 组件。<ActionBar>
在屏幕顶部放置一个导航栏,而 <GridLayout>
允许您在一系列行和列中排列子 UI 元素。如果您使用 <GridLayout>
而不提供 rows
或 columns
属性(此处的情况),则子元素将占据整个空间。
<AR>
UI 元素是真正发生神奇的地方。当您在屏幕上放置 <AR>
组件时,您将指定屏幕的该部分以显示来自设备摄像头的输入。在这种情况下,<AR>
组件是页面级 <GridLayout>
的唯一子元素,因此占据了屏幕的整个空间。但您也可以选择配置 <AR>
组件以仅占据屏幕的一部分。
<AR>
组件采用许多属性来配置 AR 体验的工作方式。您可以 参考 AR 插件的文档以获取属性的完整列表,但此处列出了此示例使用的属性。
debugLevel
— 此演示将 debugLevel
设置为 "FEATURE_POINTS"
,这将启用黄色点,使查找平面更容易。某些应用程序会在生产环境中保留这些点,例如 IKEA Place,而其他应用程序则将 debugLevel
设置为 "NONE"
以隐藏它们。但是,如果您这样做,则需要向用户提供一些明确的指示,表明应用程序需要找到一个平坦的表面。例如,支持 AR 的应用程序 Pokémon GO 不使用点,但会指示用户寻找“平坦、开阔的区域”。detectPlanes
— 此演示将 detectPlanes
设置为 true
,以便插件自动尝试查找平面。如果您希望在尝试检测表面之前向用户提供一些说明,则可能需要将此属性设置为 false
。
planeMaterial
— 此属性控制插件检测到平面后平面的显示方式。只有当您希望向用户显示平面的视觉表示时,才需要提供此属性。在此演示中,您使用 Angular 的数据绑定机制将此属性设置为以下值。
{
diffuse: new Color("white"),
transparency: 0.2
};
您可以尝试不同的颜色和透明度级别,以找到适合您的显示效果。
现在您已安装了插件并启动了一个基本应用程序,让我们开始做一些更令人兴奋的事情。
再次打开您的 app/home/home.component.ts
并将其内容替换为以下代码,该代码在用户点击平面时添加了一些调用插件 addBox()
方法的代码。
import { Component, OnInit } from "@angular/core";
import { registerElement } from "nativescript-angular/element-registry";
import { AR, ARMaterial, ARPlaneTappedEventData } from "nativescript-ar";
import { Color } from "tns-core-modules/color";
registerElement("AR", () => require("nativescript-ar").AR);
@Component({
selector: "demo-ar",
moduleId: module.id,
template: `
<ActionBar title="NativeScript AR"></ActionBar>
<GridLayout class="page">
<AR *ngIf="loaded"
debugLevel="FEATURE_POINTS"
detectPlanes="true"
[planeMaterial]="planeMaterial"
(planeTapped)="onPlaneTapped($event)">
</AR>
</GridLayout>
`
})
export class HomeComponent {
loaded = false;
ngOnInit() {
setTimeout(() => { this.loaded = true; }, 1000);
}
planeMaterial = <ARMaterial>{
diffuse: new Color("white"),
transparency: 0.2
};
onPlaneTapped(args: ARPlaneTappedEventData): void {
const ar: AR = args.object;
ar.addBox({
position: {
x: args.position.x,
y: args.position.y,
z: args.position.z
},
dimensions: {
x: 0.1,
y: 0.1,
z: 0.1
},
mass: 20,
materials: [new Color("blue")]
});
}
}
新的代码片段是 <AR>
组件现在具有的 (planeTapped)="planeTapped($event)"
属性,该属性订阅了插件的 planeTapped
事件并调用组件的新 onPlaneTapped()
方法。在该方法中,您对插件的 addBox()
方法执行以下调用。
ar.addBox({
position: {
x: args.position.x,
y: args.position.y,
z: args.position.z
},
dimensions: {
x: 0.1,
y: 0.1,
z: 0.1
},
mass: 20,
materials: [new Color("blue")]
});
此代码的作用是获取用户点击的坐标(args.position.x
、args.position.y
和 args.position.x
),并在那里放置一个具有特定质量和大小的蓝色方块。
这就是它在实际操作中的样子。
addBox()
方法是 nativescript-ar 插件提供的众多方法之一。查看 插件的 API 文档,以获取有关可用方法及其功能的更多信息。在结束之前,让我们再看看一种方法。
向现实中添加方块、文本和球体很有趣,但通常 AR 应用程序需要使用自定义 3D 模型。为此,nativescript-ar 插件提供了一个自定义的 addModel()
方法。
警告:查找 3D 模型并使其与 ARKit 一起工作可能会很痛苦。 插件的文档中提供了一些关于如何查找模型并使其工作的建议,但可能需要一些反复试验才能使事情正常运行。好消息是您正在使用 ARKit,因此您找到的任何关于为 ARKit 创建模型的现有指南都适用于 NativeScript。
对于此演示,首先下载 来自主要 nativescript-ar 演示的三个 .bae
文件,然后将其放置在应用程序的 app/App_Resources
文件夹中,如下所示。
app/App_Resources/
├── Android
│ └── ...
└── iOS
├── Models.scnassets
│ ├── Ball.dae
│ ├── Car.dae
│ └── Tree.dae
└── ...
接下来,重新打开您的 home.component.ts
文件,并将其内容替换为以下代码,该代码调用 nativescript-ar 插件的 addModel()
方法。
import { Component, OnInit } from "@angular/core";
import { registerElement } from "nativescript-angular/element-registry";
import { AR, ARNode, ARMaterial, ARPlaneTappedEventData } from "nativescript-ar";
import { Color } from "tns-core-modules/color";
registerElement("AR", () => require("nativescript-ar").AR);
@Component({
selector: "demo-ar",
moduleId: module.id,
template: `
<ActionBar title="NativeScript AR"></ActionBar>
<GridLayout class="page">
<AR *ngIf="loaded"
debugLevel="FEATURE_POINTS"
detectPlanes="true"
[planeMaterial]="planeMaterial"
(planeTapped)="onPlaneTapped($event)">
</AR>
</GridLayout>
`
})
export class HomeComponent implements OnInit {
loaded = false;
ngOnInit() {
setTimeout(() => { this.loaded = true; }, 1000);
}
planeMaterial = <ARMaterial>{
diffuse: new Color("white"),
transparency: 0.2
};
onPlaneTapped(args: ARPlaneTappedEventData): void {
const ar: AR = args.object;
ar.addModel({
name: "Models.scnassets/Car.dae",
position: {
x: args.position.x,
y: args.position.y,
z: args.position.z
},
scale: 1,
mass: 20
});
}
}
提示:将
Car.dae
替换为Bal.dae
或Tree.dae
以尝试其他模型。
当您的应用程序在设备上刷新时,您将能够将虚拟汽车放置到您的本地现实中。如果我使用该应用程序将新汽车放在我的车道上,则如下所示。
一些警告。
scale
属性来玩迷你汽车。您可以在 NativeScript 中使用 AR 做很多事情。在本文中,您学习了基础知识,例如如何检测平面、如何添加方块以及如何使用简单的 3D 模型。
您是否在 NativeScript 中使用 AR 做了一些很酷的事情?如果是,请在评论中告诉我们。并在未来关注此博客上关于 AR 的更多高级内容 😄