Unity-2018-增强现实项目-全-

Unity 2018 增强现实项目(全)

原文:zh.annas-archive.org/md5/b0bbfbb27e1009c952d32e0e793eaaaf

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

欢迎来到Unity 2018 增强现实项目。本书是为那些希望走出舒适区,跃入学习增强现实(AR)及其如何在 Unity 中创建项目的人设计的。我们将重点关注 Android、iOS 和 Windows 设备,并深入理解开始使用这一令人惊叹且不断发展的技术的根本。

本书面向的对象

本书面向任何希望扩展其 Unity 现有知识的人。他们应该有一些 C#和 Unity 的经验,并且愿意接触一点 C++、Java 和 Objective-C 语言代码。

本书涵盖的内容

第一章,什么是 AR 以及如何设置,解释了安装各种 SDK 和包以启用 AR 的过程,以及使用 AR 构建 Hello World 示例。

第二章,GIS 基础 - 地图的力量,探讨了 GIS 的历史、GIS 在应用和游戏中的影响,以及 GIS 在教育中的应用。

第三章,审查 - 各种传感器数据和插件,探讨了如何用 C#为 Unity 编写插件,如何用 C++为 Unity 编写插件,如何用 Objective-C 为 Unity 编写插件,以及如何用 Java 为 Unity 编写插件。

第四章,花团锦簇的文风之声,详细介绍了设计应用程序的步骤,探讨了项目的概念化,并探索了如何基于声音感知创建 AR 应用程序。

第五章,图片拼图 - AR 体验,帮助您设计教育应用程序,学习使用 Vuforia,并使用 Vuforia 开发一个教育 AR 应用程序。

第六章,健身乐趣 - 旅游业和随机漫步,介绍了 Mapbox,如何将 Mapbox 集成到 Unity 中,以及构建一个随机漫步到位置的 App 原型。

第七章,拍下它!为图片添加滤镜,帮助您了解 OpenCV,将 OpenCV 集成到 Unity 中,从源代码构建 OpenCV,并使用 OpenCV 构建一个面部检测应用程序原型。

第八章,通往 HoloLens 及更远之处,为您揭示了增强现实(AR)与混合现实MR)之间的区别,教授您如何使用 HoloLens 模拟器,并指导您使用 HoloLens 模拟器构建一个基本的 MR 原型。

为了充分利用本书

要充分利用本书,您应该对 Unity 编辑器、UI 和构建过程有所了解。此外,强烈建议您具备高于初学者水平的 C#技能,因为本书不会介绍如何编写 C#代码。最后,建议您至少浏览过其他编程语言,如 Swift、Objective-C、C、C++和 Java,并能一眼看出本书中遇到的代码的要点。

仅需具备 Unity 游戏引擎和 C#的基本知识,因为它们是本书的主要关注点。

下载示例代码文件

您可以从www.packtpub.com的账户下载本书的示例代码文件。如果您在其他地方购买了本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

您可以通过以下步骤下载代码文件:

  1. www.packtpub.com登录或注册。

  2. 选择 SUPPORT 标签。

  3. 点击“代码下载与勘误”。

  4. 在搜索框中输入书籍名称,并遵循屏幕上的说明。

文件下载完成后,请确保使用最新版本的以下软件解压缩或提取文件夹:

  • WinRAR/7-Zip(Windows)

  • Zipeg/iZip/UnRarX(Mac)

  • 7-Zip/PeaZip(Linux)

该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Unity-2018-Augmented-Reality-Projects。如果代码有更新,它将在现有的 GitHub 仓库中更新。

我们还有其他来自我们丰富的图书和视频目录的代码包可供选择,网址为github.com/PacktPublishing/。查看它们吧!

下载彩色图片

我们还提供了一份包含本书中使用的截图/图表的彩色图片的 PDF 文件。您可以从这里下载:www.packtpub.com/sites/default/files/downloads/Unity2018AugmentedRealityProjects_ColorImages.pdf

使用的约定

本书使用了多种文本约定。

CodeInText:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“创建一个全新的 Unity 项目。我将称它为Snap。”

代码块设置如下:

struct Circle
{
Circle(int x, int y, int radius) : X(x), Y(y), Radius(radius) {}
int X, Y, Radius;
};

当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:

extern "C" void __declspec(dllexport) __stdcall  Close()
{
_capture.release();
}

粗体: 表示新术语、重要词汇或屏幕上看到的词汇。例如,菜单或对话框中的文字会以这种方式显示。以下是一个例子:“从管理面板中选择系统信息。”

警告或重要注意事项看起来像这样。

小贴士和技巧看起来像这样。

联系我们

我们欢迎读者的反馈。

一般反馈:请通过 feedback@packtpub.com 发送电子邮件,并在邮件主题中提及书籍标题。如果您对本书的任何方面有疑问,请通过 questions@packtpub.com 发送电子邮件给我们。

勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,我们将不胜感激,如果您能向我们报告这一点。请访问 www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入详细信息。

盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,我们将不胜感激,如果您能提供位置地址或网站名称,我们将不胜感激。请通过 copyright@packtpub.com 联系我们,并附上材料的链接。

如果您想成为一名作者:如果您在某个领域有专业知识,并且对撰写或为书籍做出贡献感兴趣,请访问 authors.packtpub.com

评论

请留下评论。一旦您阅读并使用了这本书,为什么不在此处购买它的网站上留下评论呢?潜在读者可以查看并使用您的客观意见来做出购买决定,我们 Packt 可以了解您对我们产品的看法,我们的作者也可以看到他们对书籍的反馈。谢谢!

如需了解 Packt 的更多信息,请访问 packtpub.com

第一章:AR 是什么以及如何设置环境

本书从一些关于增强现实AR)的介绍性信息和理论开始。不幸的是,我们无法在不首先解决基础知识的情况下直接进入编程。如果不了解 AR 项目背后的基础知识和理论,我们就无法完全理解这项技术的工作原理或如何利用这项技术的某些更抽象的功能。这并不意味着您无法使用这项技术,只是说在更高级别上,有许多底层功能可能会难以掌握。

本书及其代码文件是为经验丰富的程序员设计的。其中采用了优化策略和某些难以理解的编程语言结构,初学者程序员可能无法立即理解。如果您在至少两年内没有学习编程,或者在那段时间内没有广泛使用 C#,我建议您手头备有一两本参考手册,以便澄清您不熟悉的任何编程术语或语法用法。真正深入研究 C#语言的最好资源之一是 C#语言规范(www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf)和《通过 Unity 2017 开发游戏学习 C#》(www.packtpub.com/game-development/learning-c-7-developing-games-unity-2017-third-edition)。

请注意,本书中至少有两个项目需要使用 Xcode,并且需要 macOS 和 iOS 设备才能正确编译和运行。如果您至少没有 2011 年款或更新的 macOS,您应该跳过实现涉及 ARKit 的章节和部分中的示例,因为您将无法跟随本书的内容。不过,您可以自由阅读这些部分,因为总有东西可以学习,即使您不能跟随示例。

我们将在本书中使用 Unity3D 的版本是 Unity 2017.2.0f3(64 位),适用于 Windows 10 和 macOS。我们将使用 Windows 10 版本 1703 构建号 15063.726 来构建 Android 版本,以及 macOS High Sierra(版本 10.13)来构建 iOS 版本,因为这些是撰写本书时的最新操作系统版本。

我们将讨论的核心信息如下:

  • 可用的 AR 工具包有哪些

  • 如何开始使用每个工具包

  • 每个工具包的优缺点

  • 开发 AR 应用和游戏的原因

可用的 AR 包

Unity3D 通过插件提供了几个创建 AR 应用和游戏的选项:

  • Vuforia AR 入门套件

  • ARCore (Tango)

  • ARToolKit

  • ARKit

应该注意的是,Vuforia Starter Kit 已经完全集成到 Unity3D 中,并且非常容易直接开始创建项目。然而,ARKit 和 ARCore 则略有不同。因为它们仍然处于实验和早期开发阶段,苹果和谷歌尚未发布完整且适当的 SDK,以便 Unity Technologies 将其纳入引擎。

对于苹果和 Android 设备,存在一个插件,您需要编译才能使其与项目一起工作,我们将在本章后面介绍如何编译并将其集成到 Unity3D 中,以便正确地使用它。现在,了解与 iOS 和 Android 一起使用 AR 需要一些额外的设置是有用的。

介绍完毕后,我们终于可以真正地讨论 AR 了,即它究竟是什么,以及如何设置 Unity3D 以利用可用的 SDK 来创建自己的 AR 游戏和应用。现在,让我们不再拖延,来定义 AR 实际上是什么。

定义 AR

AR 是增强现实。增强现实是以某种形式改变现实,以特定方式增强体验。增强现实通常指的是以下内容:

  1. 声音:

图片

声音感知

  1. 视频:

图片

这张图片中的文字并不重要。我们只是展示视频感知叠加。

  1. 图形:

图片

这张图片中的文字并不重要。我们只是展示图形感知叠加。

  1. 触觉:

图片

触觉感知

  1. GPS 数据:

图片

GPS 感知

这意味着我们可以增强一个物体的视觉图形,并以不同于我们习惯的视角来观察它,或者我们可以添加一些原本不存在的东西。视频则略有不同,因为它需要软件与专用硬件(如眼镜、手机、HUD 和其他设备)进行交互。

我们可以增强我们周围世界的听觉方面。我们可以将我们看到的一种语言中的文字转换成另一种语言,或者我们可以捕捉那些我们总是听到但忽略的微弱声音,然后放大它们,真正地将它们带到前台。

触觉感知稍微困难一些,但可以通过模拟触觉的传感器来实现。我们可以使某些东西轻微或强烈地振动来模拟各种效果,或者我们可以使游戏或应用完全基于触觉或运动传感器。在应用或游戏中,我们可以使用许多其他东西来进行触觉感知。这是一个不断被研究和扩展的领域。

对于 GPS 数据,我们可以使用用户的位置来了解用户在应用或游戏世界中的位置。GPS 数据的另一个用途是确定用户感兴趣的内容是否应该显示给他们。

由于 Unity3D 喜欢为我们处理实现的大部分细节,我们不必太担心将 DLL(动态链接库)或编写包装类与大多数流行的 AR 和 VR 设备一起使用。根据平台和引擎是否已更新以专门用于这些设备,这个规则可能有例外。

Android 和 iOS 是最受欢迎的应用和游戏集成 AR 的设备,然而,各种技术巨头一直在努力将更多设备加入其中,效果各有不同。其中一些显然不会使用 Unity3D 进行实现,尽管你可以像之前提到的那样编写包装类,但这超出了本书的范围。

AR 设备的不完全列表

让我们快速浏览一些具有 AR 功能的设备。这应该能让我们对可以使用和部署的不同类型设备有一个更清晰的认识:

  • Meta 2 是一款头戴式显示器,用于手部交互和位置跟踪,它具有 90 度的视野和 2560 x 1440 的分辨率:

图片

Meta 2

  • AR 显示可以渲染在类似眼镜的设备上,例如Google Glass

图片

Google Glass

  • 另一种这样的设备是 HoloLens:

图片

HoloLens

  • 有一种称为抬头显示的东西,通常被称为HUD。它是 AR 显示的另一种实现方式:

图片

HUD

  • 正在研究和创建许多新的设备。增强现实仍然处于起步阶段。

在整本书中,我们将创建受 AR 定义启发的应用程序和游戏。由于 AR 有四个主要方面,我们将使用这四个方面并为每一章创建一个特定的应用程序或游戏。由于 Android 和 iOS 设备可用的传感器数量有限,一些传感器将在多个项目中使用。

不同 AR 工具包的优缺点

在本节中,我们将讨论 ARCore、Vuforia、ARToolKit 和 ARKit 的优缺点。

ARCore

ARCore 是一个用于为 Android 设备构建增强现实应用的平台。ARCore 使用三种关键技术通过摄像头将虚拟内容与真实世界集成。它使用运动跟踪、环境理解和光照估计。ARCore 通过跟踪设备移动时的位置并构建对真实世界的理解来工作。它能够从手机的传感器中识别有趣的位置和读数,并且能够确定手机移动时的位置和方向。目前 ARCore 只支持少数设备,如下所示:

  • Google Pixel

  • Pixel XL

  • Pixel 2

  • Pixel 2 XL

  • Samsung Galaxy S8

如果你没有这些设备中的任何一个,你将不得不使用 Android 模拟器进行测试。这是一个非常明显的缺点,因为并非每个人都拥有这些特定的手机;此外,Android 模拟器是一个实验性软件,经常发生变化。优点是 ARCore 与 Unity3D 和 Unreal Engine 兼容,并且可以原生支持使用 Java 编程语言的 Android 设备。

ARKit

ARKit,自 iOS 11 以来推出,是一个用于轻松创建适用于 iPhone 和 iPad 的增强现实项目的框架。ARKit 的功能包括:

  • TrueDepth 相机

  • 视觉惯性里程计

  • 场景理解

  • 光照估计

  • 渲染优化

ARKit 的缺点是它是一个实验性软件,经常发生变化,并且需要使用 Apple iPhone X 来充分利用 TrueDepth 相机。你不能在 Windows 上编译它用于 Mac,因此即使是测试代码也需要 macOS。然而,优点是 ARKit 与 Unity3D 和 Unreal Engine 兼容,并且可以利用 A9、A10 和 A11 Apple 处理器。换句话说,它与 iPhone 6S 及以上版本兼容。

Vuforia

Vuforia 是最受欢迎的平台之一,可以帮助你进行增强现实开发。它支持以下功能:

  • Android

  • iOS

  • UWP

  • Unity3D 编辑器

Vuforia 能够执行许多不同的事情,例如识别不同类型的视觉对象(如盒子、圆柱体和平面),文本和环境识别,以及 VuMark,这是一种图片和二维码的组合。此外,使用 Vuforia Object Scanner,你可以扫描并创建对象目标。识别过程可以使用数据库(本地或云存储)实现。Unity 插件易于集成且功能强大。平台的所有插件和功能都可以免费使用,但包含 Vuforia 水印。

限制仅与 VuMark 的数量和云识别的数量有关:

  • 无水印的付费计划

  • 1,000 云识别

  • 100,000 个目标

  • 每月费用为 $99

显而易见的缺点是这并不是 100%免费的软件,尽管他们确实有一个开发者级别,每月免费提供 1,000 个云识别和 1,000 个目标。

ARToolKit

ARToolKit 是一个开源的 AR 项目跟踪库。它支持 Android、iOS、Linux 和 macOS。ARToolKit 具有利用以下功能的能力:

  • 单个或立体相机用于位置/方向跟踪

  • 简单黑色方块的跟踪

  • 平面图像跟踪

  • 摄像机标定

  • 光学立体标定

  • 光学头戴式显示器支持

它足够快,可以用于实时 AR 应用。它也是免费的开源软件,有 Unity 和 OpenSceneGraph 的插件。这个软件的缺点是它有大量的功能,因此集成库很困难,探索所有可用选项和设置需要更多时间。

构建我们的第一个 AR 应用程序

这个部分将定义我们可用的每个不同 SDK 的主要点,我们将用它们构建我们的第一个程序。这将是一个逐步的、非常深入的教程设计方式,因为这是一些需要打包和压缩到小节中的大量信息,而不需要在后面的章节中重复信息。

设置 Vuforia

现在是时候为每个不同的 SDK 设置一个 Unity3D 项目了,这些项目将作为我们稍后章节的基础,当我们使用它们来构建应用程序或游戏时。让我们从 Vuforia 开始,因为它是最容易设置的:

  1. 我们现在需要注册 Vuforia。导航到developer.vuforia.com/vui/user/register以进入注册登录页面。如果你居住在 Google 被封锁的国家,你应该使用 VPN,因为注册页面使用了 Google 驱动的 reCAPTCHA,没有它你无法继续:

图片

在 Vuforia 上注册

  1. 一旦你可以登录,导航到“开发”标签页;或者,点击以下链接:developer.vuforia.com/targetmanager/licenseManager/licenseListing

  2. 你将看到两个主要项目,许可证管理器和目标管理器。许可证管理器将允许你创建一个免费的开发密钥或购买一个开发密钥。我们想创建一个免费的。点击获取开发密钥。为应用输入一个名称,你可以随时更改。我将称它为VuforiaIntro

图片

添加 Vuforia 密钥

  1. 现在,我们有了 Vuforia 的密钥。为了查看许可证密钥,我们需要点击我们应用的名称:

图片

Vuforia 密钥信息

  1. 下一页提供了两个非常重要的信息:许可证密钥和使用详情。使用详情告诉我们有多少云识别、云数据库、使用的识别、使用的云目标、生成的 VuMark、VuMark 数据库、VuMark 模板和使用的 VuMark,以及我们目前剩余的 VuMark 数量:

图片

  1. 许可密钥详细信息告诉我们我们的密钥(它很容易复制到剪贴板),密钥的类型,密钥的状态,创建日期以及密钥的历史。

现在,我们已经准备好设置 Vuforia 并使演示项目适当地工作。

如前所述,Vuforia 自 2017.2 版本起完全集成到 Unity3D 中,一旦你学会了 SDK 的基础知识,它就是一个梦想的工作。Vuforia 旨在严格处理 AR 的图形部分。它可以识别图像和对象,并且因为它使用计算机视觉,所以它能够与真实世界互动。由于 Vuforia 集成到 Unity3D 中,我们将一次性安装带有 Vuforia 的 Unity。

如果你现在电脑上没有安装 Unity3D,让我们先去安装它:

  1. 导航到www.Unity3D.com并下载最新的个人版(或其他版本,如果你是高端用户)安装程序:

图片

  1. 当你到达安装程序的组件部分时,请确保选择你想要支持的所有平台。我通常选择 Android 构建支持、Linux 构建支持、SamsungTV 构建支持、Tizen 构建支持、WebGL 构建支持以及 UWP(通用 Windows 平台)构建支持。还有一个额外的选项你需要确保选择,那就是 Vuforia 增强现实支持:

图片

Vuforia Unity 安装

现在 Unity3D 已经安装完毕,让我们创建一个全新的 Unity 项目:

  1. Vuforia 建议你为他们的 AR 应用使用 3D 项目设置,所以,考虑到这一点,我将保持它作为一个 3D 项目,禁用启用 Unity 分析,并且项目的名称应该是VuforiaIntro

图片

  1. 一旦项目加载完毕,我们可以查看我们现在可以访问的一些额外的编辑器项目。在 Unity 编辑器顶部的工具栏中,我们将看到文件、编辑、资产、游戏对象、组件、窗口和帮助:

图片

  1. 游戏对象、组件、窗口和帮助中都有额外的项目被添加。看看游戏对象,我们可以看到额外的项目是 Vuforia。在 Vuforia 项目中,我们有 AR 相机、图像、多图像、圆柱形图像、云图像、相机图像、VuMark 和 3D 扫描:

图片

  1. 云图像也有一些额外的项目,让我们看看那些。我们有云提供商和云图像目标可供我们使用:

图片

  1. 相机图像也有一些额外的项目,因此我们也应该熟悉那些选项。可用的选项包括相机图像构建器和相机图像目标:

图片

在我们继续之前,我们应该确切地知道这些选项的功能以及它们在应用许可证之前添加到项目中的样子。

AR Camera 替换了标准相机,因为它具有基础相机组件和音频监听器组件。我们还看到它附加了两个脚本,Vuforia Behavior 和 Default Initialization Error Handler:

图片

  • Image 允许你将可追踪的对象添加到你的 AR 项目中,并作为允许你在相机流中设置模型基点的依据。

  • Multi Image 允许你将多个可追踪对象添加到你的 AR 项目中,并作为将模型实时引入相机流的锚点。

  • Cylindrical Image 是一个锚点,用于将图像包裹在圆柱形物体上。

  • VuMark 是 Vuforia 团队制作的一种自定义条码。它允许你将其编码数据,同时充当类似于 Image、Multi Image 和 Cylindrical Image 的 AR 目标。

  • Cloud Provider 是直接链接到你的云端数据库的专用 AR 设计品牌链接。它应该用于出版物(目录、杂志、报纸等)、零售商(产品可视化和店内流量生成)、广告商(多品牌内容、优惠券和促销)以及产品识别(酒标/瓶子、谷物箱等)。

  • Cloud Image Target 允许你将可追踪的对象添加到 AR 项目中,并作为应用将识别数据发送到云端数据库以检索信息并按需显示的锚点。

  • Camera Image Builder 是一个允许你定义一个目标图像并将其存储在数据库中以供检索和在 AR 应用中使用的功能。

  • Camera Image Target 作为锚点使用,用于使用自定义目标图像在识别时在屏幕上显示你想要的内容。

接下来要讨论的一组项目位于组件工具栏中。特殊组件位于组件窗口的 AR、脚本和 XR 部分,如下面的截图所示以供参考。为了使用它们,你必须在场景中有一个游戏对象,并从工具栏中将组件添加到它。我们提供了 World Anchor、Tracked Pose Driver、Spatial Mapping Collider 和 Spatial Mapping Renderer。我们应该深入了解这些项目,以便确切了解它们的功能:

图片

  • World Anchor 是一个组件,它代表物理世界中一个确切点与 World Anchor 的父 GameObject 之间的链接。一旦添加,带有 World Anchor 组件的游戏对象将锁定在现实世界中的位置。

  • Tracked Pose Driver 是一个组件,它将跟踪设备的当前姿态值应用于游戏对象的变换。

  • Spatial Mapping Collider 允许进行与空间映射网格的物理(或角色)交互,例如物理交互。

  • 空间映射渲染器是一个组件,它为空间映射表面提供视觉表示。这对于在视觉上调试表面和在环境中添加视觉效果非常有用。

应该注意的是,在脚本部分有一些与 Vuforia 相关的项目,但是我们将不会在这里介绍它们。但是,为了确保项目被列出,它们如下:

  • 背景平面行为

  • 云端识别行为

  • 圆柱目标行为

  • GL 错误处理器

  • 图像目标行为

  • 遮罩排除行为

  • 多目标行为

  • 物体目标行为

  • 属性行为

  • 重建行为

  • 从目标重建行为

  • 表面行为

  • 文字识别行为

  • 关闭行为

  • 关闭文字行为

  • 用户定义的目标构建行为

  • 视频背景行为

  • 虚拟按钮行为

  • Vuforia 行为

  • Vuforia Deinit 行为

  • Vu Mark 行为

  • 线框行为

  • 线框可追踪事件处理器

  • 文字行为

在检查器面板中,我们有 Vuforia 配置。以下是其截图;接下来,我们将定义它所做的工作:

Vuforia 配置允许你输入你的许可证密钥。点击添加许可证将加载 Vuforia 开发者登录页面。它还允许你指定你想要 Vuforia 配置为工作的内容,例如 HUD、智能眼镜、摄像头或智能手机。

我还想指出,智能地形追踪器已被弃用,将在 Vuforia 的下一个版本中移除。如果你正在阅读这本书,并且截图看起来不一样,你现在知道原因了,所以不必担心。

由于我们在这里,让我们继续将我们的应用密钥添加到 Vuforia 中(参见 Vuforia 添加许可证以获取其位置):

  1. 你应该创建自己的应用密钥,因为我的应用密钥在本书发布时将不再有效。在将你的密钥复制粘贴到许可证密钥框中后,只需按下Return/Enter键即可完成:

  1. 由于我们正在 PC 上进行测试,如果你有适用于该 PC 的工作摄像头,请确保摄像头设备选择了正确的摄像头用于使用:

  1. 接下来,我们需要进入 Unity 播放器设置并修复一些选项。导航到文件并点击构建设置。构建设置窗口应该会出现。确保将项目类型更改为构建到 Android,然后点击播放器设置:

  1. Vuforia 不支持 FAT 设备过滤器或 Android TV,因此我们需要更改这两个选项。位于其他设置中的设备过滤器需要更改为 ARMv7,并且需要取消选中 Android TV 兼容性。

  2. 现在,我们可以最终构建我们的“Hello World”AR 应用程序进行测试,以确保 Vuforia 和 Unity3D 一起工作良好。如果您还没有这样做,请从 Hierarchy 窗口中删除常规相机组件,并用 ARCamera 替换它:

  1. 下一步是将 Vuforia 图像添加到场景中,这同样也被称为 ImageTarget:

  1. 现在,我们需要下载并将一个 3D 模型添加到场景中。所以,让我们走捷径,只需将一个球体添加到场景中,并将 xyz 缩放设置为 0.3。特别小心确保球体是 ImageTarget 的子对象。这一点非常重要

  1. 下一步是导航到 Editor | Vuforia | ForPrint | ImageTargets,并在一张纸上打印出 target_images_A4target_images_USLetter

  1. 一旦打印出来,我们就可以开始测试的最后部分,即运行程序并将打印出的无人机图像放在网络摄像头前:

本截图中的文本并不重要。它显示了一个当图像被识别时出现在相机输入中的球体。

  1. Vuforia 已正确配置并经过适当测试,因此我们可以继续设置和配置下一个 SDK。

设置 ARToolKit

ARToolKit 的设置和开始使用稍微有些复杂。

ARToolKit 已被弃用,现在它是 Daqri Vos API 的一部分。您可以在developer.daqri.com/#!/content/develop查看它。本节保留在此,以防您想从 github 链接github.com/artoolkit/arunity5使用 ARToolkit。

您有两种不同的方式可以在项目中获取 ARToolKit 并准备开发。第一种选项是最简单的,那就是通过 Asset Store:assetstore.unity.com/packages/tools/artoolkit-6-unitypackage-94863。这是 Asset Store 中 ARToolKit 的最新版本,它将直接导入到 Unity 中。另一种选项是访问 ARToolKit 的官方网站:github.com/artoolkit/artoolkit5。这允许您获取额外的工具和实际的 SDK,以及 Unity 包。

对于 Unity3D 的安装,我们将选择第二种选项,因为它不如第一种选项直观:

  1. 导航到 ARToolKit 的官方网站,点击下载 SDK。macOS、Windows、iOS、Android、Linux、Windows 8.1 和源依赖项不需要下载,但如果你想深入了解 ARToolKit 的内部工作原理,或者你想在非 Unity 环境中使用它,则可以下载。相反,转到页面底部并点击下载 Unity 包按钮:

图片 8

如果你目前没有进行更复杂的工作,那么如果你在 macOS 上,你不需要额外的 Unity 工具,但如果你在 PC 上,我建议获取 Windows 工具,因为 ARToolKit 需要它们在 PC 上进行调试,而无需使用 Android 模拟器或测试 Linux。

  1. 现在包已经下载,我们需要打开 Unity3D 并创建一个新的项目。我将我的项目命名为 ARToolKitIntro。为了简单起见,保持默认设置:

图片 10

  1. 现在,我们需要将 Unity 包导入到 Unity 中。这个过程非常直接。右键点击 Assets 文件夹,选择导入包,然后选择自定义包:

图片 5

  1. 导航到存放下载的 Unity 包的文件夹,点击它,然后选择打开。你应该会看到一个带有复选框的对话框。点击全选,然后点击导入:

图片 3

  1. 导入完成后,你会看到三个文件夹(ARToolKit5-UnityPluginsStreamingAssets):

图片 1

ARToolKit5-Unity 文件夹中,有 Example ScenesExamplesMaterialsResourcesScriptsChangelogReadme 文件和文件夹:

  • Scripts 中,我们有一个带有以下截图所示功能的 Editor 文件夹:

图片 9

  • Editor 文件夹中,我们有以下内容:

图片 12

  • 接下来是 Plugins 文件夹。它列出了以下文件夹:

图片 7

  • 如果你查看 Unity 编辑器顶部的菜单栏,你会看到一个额外的工具栏项:ARToolKit。下拉菜单显示了几个选项:Unity 版本 5.3.2 的 ARToolKit、下载工具、构建、支持和源代码:

图片 4

  • 支持包括主页、文档和社区论坛:

图片 6

  • 源代码有查看 ARToolKit 源代码和查看 Unity 插件源代码:

图片 11

基本步骤完成,我们可以开始使用 ARToolKit 构建 "Hello World":

  1. 我们需要做的第一件事是在层次结构面板中创建一个空的游戏对象,并将其重命名为 ARToolKit

  2. 下一步是将 ARController 脚本添加到游戏对象中,并删除相机:

图片 2

  1. ARController脚本处理 AR 跟踪的创建和管理。它在运行时自动添加一个摄像头,并由我们提供的用户层控制。

  2. 使用 ARToolKit 的最新版本,已经为你提供了基本用户层:分别为用户层 8、9 和 10 提供了AR 背景AR 背景 2AR 前景

图片

  1. AR 控制器脚本有一个视频选项下拉菜单:

图片

  1. 由于我们有这么多不同的视频选项,我们需要正确设置:

图片

  1. 如果你发现在 Unity 编辑器的控制台中出现错误,那么你使用的 ARToolKit 版本不是最新的,与本书中使用的 Unity 版本不匹配。

由于我正在为 Windows 构建,我将选择视频配置的第一个选项,并输入以下内容:

 <?xml version="1.0" encoding="utf-8"?>
 <dsvl_input>
 <camera show_format_dialog="false" frame_width="1280" frame_height="720" frame_rate="29.97">
 <pixel_format>
 <RGB32 flip_v="true"/>
 </pixel_format>
 </camera>
 </dsvl_input>

现在,由于我的电脑目前没有连接摄像头,我收到了游戏中的错误消息,但代码按预期编译并运行。如果你连接了摄像头并且它被正确识别,你应该有来自摄像头的直接视频流。

这就完成了 ARToolKit 的 Hello World 示例;我们稍后会再次访问这个示例,以便更深入和有趣地使用这个 SDK。

设置 ARCore

ARCore 和 ARKit 在本质上非常相似,但你不能在 Windows 环境中编译 ARKit,这正是我现在使用的环境。不用担心;当我们到达 ARKit 时,我会使用 macOS 来给你一个使用时的正确视图和感受。

话虽如此,现在是时候更深入地了解 ARCore 了。

ARCore 是由谷歌制作的,目前处于早期预览阶段;它甚至还没有达到 1.0 版本,因此肯定会发生许多变化,其中一些可能会对现有的应用程序或游戏造成极大的损害。

有两种方式可以获取 Unity 的 SDK 预览。第一种是通过 Unity 包文件(developers.google.com/ar/develop/unity/quickstart-android),另一种是通过 GitHub(github.com/google-ar/arcore-unity-sdk)。现在,由于我最近从亚马逊网络服务下载时遇到了问题,我将使用第二个链接:

图片

记住这一点至关重要,如果你没有三星 Galaxy 8 或谷歌 Pixel 手机,你将无法在设备上运行适当的测试。然而,如果你还安装了 Android Studio,你确实可以访问 Android 模拟器:

  1. 首先,在 Unity 中创建一个新的项目,并将其命名为ARCoreTutorial

图片

  1. 在进行任何其他操作之前,我们需要将构建设置更改为 Android:

图片

  1. 接下来,我们需要更改玩家设置。我们需要更改的主要设置在“其他设置”标签页内,所以让我们看看需要更改什么。

  2. 其他设置:我们希望取消勾选多线程渲染;最小 API 级别应为 Android 7.0 ‘Nougat’ API 级别 24;目标 API 级别应为 Android 7.0 ‘Nougat’ API 级别 24 或 Android 7.1 ‘Nougat’ API 级别 25:

  1. XR 设置:我们希望 ARCore Supported 被勾选:

  1. 接下来,我们想要解压 SDK 或将包导入 Unity3D:

立即,我们应该看到tango_client_api2的 DLLNotFoundException。这是正常的,并且社区中广为人知。尽管如此,它不应该在运行时引起任何错误;它应该在后续版本中修复。

设置 ARKit

ARKit 需要使用 macOS High Sierra,因为编译和修改 API 本身需要 XCode 9 及更高版本。因此,我强烈建议使用 2011 年后期或更新的 macOS。我正在使用 2011 型号的 Mac Mini,拥有 8GB 的 RAM,尽管标准的 4GB 应该足够。Unity3D 广泛使用 OpenCL/OpenGL,这需要能够利用 Metal 的 GFX 卡。2011 年及更早的 macOS 没有这种原生能力;可以通过拥有外部 GPU(目前官方仅支持 Radeon RX 480)来解决这个问题。

在处理完这些之后,我们可以开始在我们的 macOS 上安装和配置 Unity3D 的 ARKit。

您有几种方式可以安装 ARKit:

  1. 我们可以导航到 Asset Store 上的插件页面(www.assetstore.unity3d.com/en/#!/content/92515):

  1. 或者我们可以直接从 Bitbucket 仓库下载插件(bitbucket.org/Unity-Technologies/unity-arkit-plugin/overview):

  1. 如果我们选择第一种方式,从 Asset Store 安装,我们就不必担心自己将文件复制到我们的项目中,但无论如何,这样做都很简单,所以选择你想要的方法,创建一个名为ARKitTutorial的新项目:

接下来,我们有很多东西要解开这个包实际上包含的内容:

  • /Assets/Plugins/iOs/UnityARKit/NativeInterface/ARsessionNative.mm – 这是与 ARKit SDK 实际接口的 Objective-C 代码。

  • /Assets/Plugins/iOS/UnityARKit/NativeInterface/UnityARSessionNativeInterface.cs – 这是将原生代码与 ARKit 粘合的脚本 API。

  • /Assets/Plugins/iOS/UnityARKit/NativeInterface/AR*.cs – 这些是 ARKit 公开的数据结构的等效物。

  • /Assets/Plugins/iOS/UnityARKit/Utility/UnityARAnchorManager.cs – 这是一个实用脚本,用于跟踪 ARKit 的锚点更新,并可以在 Unity 中为它们创建适当的相应 GameObject。

  • /Assets/Plugins/iOS/UnityARKit/Editor/UnityARBuildPostprocessor.cs – 这是一个在 iOS 构建时运行的编辑器脚本。

  • /Assets/Plugins/iOS/UnityARKit/UnityARCameraManager.cs – 这是应该放置在场景中 GameObject 上的组件,该 GameObject 引用您想要控制的相机。它将定位和旋转相机,并根据 ARKit 的更新提供正确的投影矩阵。此组件还作为 ARKit 会话初始化。

  • /Assets/Plugins/iOS/UnityARKit/UnityARVideo.cs – 这是应该放置在相机上的组件,用于获取渲染视频所需的纹理。它设置用于将内容写入后缓冲区的材质,并设置用于写入的命令缓冲区。

  • /Assets/Plugins/iOS/UnityARKit/UnityARUserAnchorComponent.cs – 这是根据添加到其上的 GameObject 的生命周期添加和删除 ARKit 锚点的组件。

在我们构建自己的“Hello World”示例之前,我们应该将UnityARKitScene.unity构建到 iOS 中,以了解 ARKit 的能力,因为它演示了该场景中 ARKit 的所有基本功能。

UnityARKitScene包含在插件中,以及几个其他示例项目。我们将编译UnityARKitScene作为我们的 Hello World 应用程序。

然而,在我们这样做之前,我们需要讨论文件结构,因为那些不熟悉编译到 iOS 的人在没有进一步说明的情况下编译会遇到一些严重问题。您可能已经注意到插件中有许多我们没有提到的事项,所以让我们在继续之前讨论它们的功能。

\UnityARKitPlugin 主目录文件:

  • ARKitRemote – 允许您从您的设备向 Unity3D 编辑器发送远程命令。

  • Examples – 此目录包含示例脚本和场景,以展示您可以使用 ARKit 和此插件完成的各种操作。

  • Plugins – 存储运行 ARKit 所需的目录。

  • Resources – 存储 ARKit 所需的资源文件。

Plugins\iOS\UnityARKit\NativeInterface cs 文件:

  • ARAnchor – 将对象锚定到来自相机流的世界上某个位置。

  • ARCamera – 跟踪相机的位置。

  • ARErrorCode – 错误代码。

  • ARFaceAnchor – 面部跟踪锚点。

  • ARFrame – 返回有关相机、锚点和光估计的数据。

  • ARHitTestResult – 返回任何碰撞结果。

  • ARHitTestResultType – 可用碰撞测试类型的枚举。

  • ARLightEstimate – 计算图像或视频中的亮度。

  • ARPlaneAnchor – 将平面锚定到特定的 4x4 矩阵。

  • ARPlaneAnchorAlignment – 使锚点相对于重力水平对齐。

  • ARPoint – 一个包含 x 和 y 值的点结构,以双精度表示。

  • ARRect – 一个结构体,以 ARPoint 作为原点,以 ARSize 作为大小

  • ARSessionNative – 用于指定框架依赖项和插件应针对哪些平台工作的原生插件

  • ARSize – 一个结构体,接受宽度和高度值作为双精度浮点数

  • ARTextureHandles – 一个用于相机缓冲区的原生 Metal 纹理处理程序,它为 textureYtextureCbCr 值都接受 IntPtrint 指针

  • ARTrackingQuality – 可用跟踪质量的枚举

  • ARTrackingState – 跟踪状态的枚举。选项有限制、正常和不可用

  • ARTrackingStateReason – 状态原因的枚举。选项有过度运动、特征不足和初始化

  • ARUserAnchor – 定义此锚点在世界坐标系中的旋转、平移和缩放变换矩阵

  • UnityARSessionNativeInterface – 原生插件包装代码

\Plugins\iOS\UnityARKit\Helpers cs 文件:

  • AR3DOFCameraManager – 一个用于 AR 摄像头的 3D 对象的辅助类

  • ARPlaneAnchorGameObject – 一个附加有 ARPlaneAnchor 的 GameObject 的类

  • DontDestroyOnLoad – 确保在加载时不会销毁 GameObject

  • PointCloudParticleExample – 创建一个点云粒子系统

  • UnityARAmbient – 一个用于环境照明的辅助函数

  • UnityARAnchorManagerARPlaneAnchorGameObjects 的管理器

  • UnityARCameraManager – 一个用于 ARCamera 的辅助类

  • UnityARCameraNearFar – 设置摄像机的近远距离

  • UnityARGeneratePlane – 创建一个 ARPlaneAnchorGameObject

  • UnityARHitTestExample – 测试从少量到无限量的平面碰撞

  • UnityARKitControl – 一个用于创建测试 ARSession 的辅助类

  • UnityARKitLightManager – 一个用于管理各种照明可能的辅助类

  • UnityARMatrixOps – 一个将 4x4 矩阵转换为欧几里得空间以进行四元数旋转的类

  • UnityARUserAnchorComponent – 一个用于创建锚点添加和删除事件的辅助类

  • UnityARUtility – 一个用于将 ARKit 坐标转换到 Unity 的辅助类

  • UnityARVideo – 一个将视频纹理渲染到场景的辅助函数

  • UnityPointCloudExamples – 一个用于使用粒子效果绘制点云的辅助函数

\Plugins\iOS\UnityARKit\Shaders 着色器文件:

  • YUVShader – 用于渲染纹理的伽玛 Unlit 着色器

  • YUVShaderLinear – 用于渲染纹理的线性 Unlit 着色器

\UnityARKitPlugin\Resources 文件:

  • UnityARKitPluginSettings.cs – 一个可脚本化的对象,用于切换应用是否需要 ARKit 以及切换 iPhone X 的面部追踪

UnityARKitPlugin\ARKitRemote 文件:

  • ARKitRemote.txt – 一个文本文件,解释如何设置和使用 ARKitRemote

  • EditorTestScene.unity – 当运行 ARKitRemote 时应该运行的测试场景

  • UnityARKitRemote.unity – 应该在适用设备上编译和安装的场景

  • ARKitRemoteConnection.cs – 用于将设备数据发送到 UnityEditor

  • ConnectionMessageIds – 编辑器会话消息的 GUID

  • ConnectToEditor.cs – 在编辑器和设备之间创建网络连接

  • EditorHitTest – 从设备返回碰撞数据到编辑器

  • ObjectSerializationExtension.cs – 将对象转换为字节数组的扩展

  • SerializableObjects.cs – 序列化 Vector 4 数据和一个 4x4 矩阵

  • UnityRemoteVideo.cs – 连接到编辑器,并将设备视频流传输到编辑器

UnityARKitPlugin\Examples文件:

  • AddRemoveAnchorExample – 一个示例程序,用于添加和删除锚点

  • Common – 包含在各个项目中使用的通用材料、模型、预制体、着色器和纹理

  • FaceTracking – 面部追踪示例应用程序

  • FocusSquare – 一个示例场景,它找到了特定的锚点

  • UnityARBallz – 一个示例场景,你可以在这里玩球类游戏

  • UnityARKitScene – 一个带有最小脚本的简单场景,用于测试 ARKit 是否正常工作

  • UnityAROcclusion – 一个展示各种光照条件的示例项目

  • UnityARShadows – 一个处理低光照条件的示例项目

  • UnityParticlePainter – 一个示例项目,让你可以用粒子来绘画

现在我们已经对这个包内部的所有内容有了基本的理解,让我们用 ARKit 构建我们的 Hello World。

在 ARKit 中构建 Hello World

在我们打开 UnityARKitScene 之后,我们需要做的第一件事是设置构建设置:

  1. 点击构建设置并选择玩家设置。

  2. 我们想要滚动到“识别”部分。包标识符应该设置为com.unity.ARKitHelloTutorial,版本为0.1,构建为10.1。自动签名复选框应该被勾选。自动签名团队 ID 设置留空:

  1. 仅构建 iOS 的UnityARKitScene。以调试模式运行 Xcode。

  2. 仅勾选“开发构建”复选框;其他所有内容应保持默认设置。

  3. 点击构建。我将把这个文件保存为iOSTest,保存在我的数据驱动器中名为iOS的文件夹里:

  1. 构建过程不会花费很长时间,可能第一次构建只需要大约两分钟。

  2. 下一步我们要做的是打开我们保存项目的文件夹,并在 Xcode 中打开.xcodeproj文件:

  1. 让我们看看在 Xcode 中你会看到的基项目:

  1. 我们首先想要检查的是“身份”选项卡,以确保这些设置与 Unity3D 中的设置相同:

  1. 现在,我们需要查看“签名”子部分:

  1. 我们需要确保添加我们的个人团队名称,你可以通过登录你的 Apple 开发者账户并点击你想要使用的团队的箭头来获取:

  1. 部署信息接下来。部署目标需要更改为11.2。设备应设置为仅 iPhone。主界面是LaunchScreen-iPhone.xib

  1. 点击顶部的构建设置,因为这里也有一些设置需要更改。

  2. 在架构中,iPhone 的 ARCHS 应设置为标准。SDKROOT 应为最新 iOS(iOS 11.2)。SUPPORTED_PLATFORMS 应为 iOS:

  1. 接下来,向下滚动查看签名,值应该已经设置为正确的值:

  1. 现在,点击产品并构建:

  1. 构建应该成功完成,大约有 47 个警告,这是正常的:

  1. 现在,我们可以在模拟器中构建和测试。我们想要做的是从 iPhone 切换到列表中的任何一个模拟器,所以点击你 iPhone 或任何你拥有的设备旁边的设备列表:

  1. 你将看到一个你想使用的设备的大列表。这将从设备的模拟到连接到你的 macOS 的 iOS 设备:

  1. 点击你想要使用的模拟器,然后构建并运行应用程序。

恭喜!我们已经完成了这个 Hello World 应用程序。

摘要

我们学习了从许多公司提供的四个主要 AR SDK 的基本知识。我们只需付出最小的努力,就在每个 SDK 中安装并编译了一个工作示例,现在我们可以继续利用这些 SDK 的潜力,因为它们目前处于各自的发展阶段。

我们可以看到,所有四个 SDK 都足够简单易用,安装相对容易。在我看来,目前最好的 SDK 是 Vuforia。它具有最强大的 API,并且对于使用和进一步学习有非常详细的文档。

在下一章中,我们将专注于学习 GIS 的历史以及这段历史是如何塑造我们今天在 AR 应用程序和游戏中使用 GIS 的方式的。

问题

  1. ARView 是一个你可以用来在 Unity 中制作 AR 应用程序的 SDK:

A.) 正确

B.) 错误

  1. ARKit 是专门为 iOS 设备设计的:

A.) 正确

B.) 错误

  1. ARCore 是专门为 Windows 设备设计的:

A.) 正确

B.) 错误

  1. Vuforia 是为 iOS、Windows 和 Android 设备设计的:

A.) 正确

B.) 错误

  1. 触觉感知完全是关于使用触觉:

A.) 正确

B.) 错误

  1. 声音感知是你用眼睛看到的东西:

A.) 正确

B.) 错误

  1. GPS 数据让应用程序可以通过随机猜测来指定用户的位置:

A.) 正确

B.) 错误

  1. Unity 的 Windows 和 Android 插件需要 DLL 文件:

A.) 正确

B.) 错误

  1. Meta 2、HoloLens、抬头显示(HUD)和谷歌眼镜都被视为增强现实(AR)设备:

A.) 正确

B.) 错误

  1. Vuforia 并不是一个免费使用的 SDK:

A.) 正确

B.) 错误

第二章:GIS 基础 - 地图的力量

当谈到 GIS,即地理信息系统(Geographic Information Systems)的缩写,以及 AR 编程中的数据和用法时,它有多种风味和用途。然而,在我们深入探讨如何在 AR 游戏 和应用中使用 GIS 数据之前,我们首先必须了解 GIS 究竟是什么。因此,我们将讨论如下内容:GIS 是何时开发的,GIS 的创始人是谁,GIS 可以用于何处,以及 GIS 如何与游戏和应用开发相结合。这之所以重要,是因为 GIS 的历史直接影响到今天在 AR 应用和游戏中数据的使用方式;它还使我们能够欣赏那些在过去为我们利用在线可用数据做出贡献的人的辛勤工作。在本章的后面部分,我们将探讨如何从 GIS 的历史中学习,以创建应用和游戏的一些例子。本章将涵盖以下主题:

  • 理解 GIS 是什么

  • GIS 和数据分析的历史

  • GIS 统计

  • GIS 的含义

  • GIS 和 AR

要了解 GIS 究竟是什么,我们必须深入挖掘以发现 GIS 的基本原理及其起源。GIS 和数据分析的历史非常迷人,将揭示许多让我们了解其设置和使用底层结构的事情。GIS 统计将使我们能够了解常用的数学方法,以便我们可以利用它们。GIS 的含义将向我们展示 GIS 的许多用途,不仅限于学术界,还包括教育和实际应用。

GIS 和 AR 将展示 AR 应用和游戏如何将 GIS 集成其中的许多必要示例。这将让我们对未来可以开发的内容有一个清晰的认识。

在本章中,我们将涵盖以下主题:

  • GIS 基础 – 地图的力量

  • GIS 和增强现实

什么是 GIS?

GIS 最常见的定义是地理信息系统。它由一个完整的软件和硬件系统组成,可以通过摄像头捕获地理数据和信息,通过数据库存储,通过软件进行操作,通过统计和可视化工具进行分析,以及管理和展示空间或地理数据。GIS 还有其他众所周知的定义,例如地理信息科学,尽管它已经不再普遍使用,因为它指的是研究地理信息系统的学术学科。它通常不用于 GIS 的定义,因为它是在更广泛的地理信息学学术学科中的一个大型领域。

这本质上归结为描述任何可以结合、保存以供未来使用、管理、检查、分发和展示地理信息的信息系统的能力。本质上,你可以创建工具,使用户或其他工具能够创建信息查询的双向流动,检查空间数据,操纵和检查地图数据,并以视觉或数据形式展示所有这些操作的结果。

与 GIS 相关的工具和不同应用非常丰富,包括工程、安排、管理、物流、保险、运输、电信和商业等,因此 GIS 和位置智能应用是许多位置服务的基础,如 Google Maps、Apple Maps、Bing Maps、Pokémon Go 等。

GIS 的历史

“地理信息系统”这一术语的首次使用是在 1968 年由罗杰·汤姆林森提出的。它被用于他的论文《区域规划地理信息系统》,因此他通常被称为“GIS 之父”。

空间分析的第一种已知应用是在 1832 年由一位名叫查尔斯·皮凯特的法国地理学家提出的。他通过半色调颜色渐变来表示巴黎的 48 个区,这些颜色渐变反映了每 1000 名居民因霍乱爆发而死亡的数量。

约翰·斯诺在 1854 年决心找到霍乱爆发的源头。他试图通过在地图上标记点来描绘霍乱受害者的居住地,并通过连接他发现的集群,他将爆发的源头与附近的水源联系起来。这是已知最早有效使用地理程序来研究疾病传播的例子。

在他的地图上,他使用条形图来表示在指定家庭发生的死亡;然而,在他的第一张地图中,存在一些小错误。其中之一是 Broad Street 水泵的位置:

图片

这张图片中的文字并不重要。它概述了约翰·斯诺的第一张地图

在他发布的第二张地图中,他纠正了他的错误,包括水泵的位置:

图片

这张图片中的文字并不重要。它概述了约翰·斯诺的第二张地图

虽然在制图中之前就已经存在地质学的必要组成部分,但约翰·斯诺的指南极为引人注目。它之所以新颖,是因为他利用制图技术来描绘和检查地质上从属的奇观群体。正因为如此,约翰·斯诺被许多人视为疾病地图的先驱,他所确立的许多概念至今仍与许多其他 GIS 方面结合使用,由疾病控制与预防中心CDC)。

到 20 世纪初,我们看到了照相锌版印刷术(也称为日锌版印刷术)的进步。照相锌版印刷术使地图能够分层。这意味着每一层只能包含与该特定层相关的信息,例如植被、树木或水道。它主要用于打印等高线,因为绘制这些等高线是一项非常劳动密集型的工作,因此这项技术对制图师来说非常有用。在独立层上有管道、树木或植被意味着它们可以被单独处理,而不会干扰其他层,或者当,比如说,建筑物阻挡了应该检查的东西时,不会引起问题。这种做法至今仍在使用;其中一种用途是在标记地下电线的位置时,或者为房屋标记水管的位置:

图片

使用照相锌版印刷术,像这样的地图最初是在玻璃板上绘制的,但后来改为塑料薄膜,因为塑料相对于玻璃有许多优点。塑料更轻,需要的存储空间更少,更不易碎,等等。当大多数层完成时,它们通过一个大型过程相机被合并成一张单独的图片。当彩色印刷变得可用时,层的概念也被用于生成用于生成每种颜色的单独版面。

层的利用后来成为当代 GIS 的主要特性之一,而所描述的摄影过程并不被视为 GIS 本身的组成部分,因为地图只是图像,没有任何数据库与之关联。由原子武器推动的 PC 设备进步,在 20 世纪 60 年代中期促成了广泛应用的 PC 制图应用。在 1960 年,加拿大安大略省渥太华联邦林业和农村发展部创建了世界上第一个明显的运营 GIS。

这个第一个明显的运营 GIS 是由罗杰·汤姆林森博士创建的。这个 GIS 被称为加拿大地理信息系统CGIS),它被用来存储、分解和控制为加拿大土地清查收集的信息。加拿大土地清查是一项行政管理推动,通过绘制有关土壤、园艺、娱乐、野生动物、水禽、森林服务以及土地利用的数据来决定省级加拿大的土地容量。由于规模和需要存储的信息量,创建了一个评级分类因子,以允许更简单、更有效的分析。

虽然当时还有其他计算机制图应用,但 CGIS 在提供叠加、测量、扫描和数字化地图数据的能力方面进行了重大改进。它还能够支持覆盖整个大陆的国家坐标系,使用编码线作为弧线。这意味着它具有真正的嵌入式拓扑结构,并且将属性和位置信息存储在单独的文件中。利用叠加来推进集中化地理信息的空间研究是汤姆林森被称为“GIS 之父”的动机。

在 1964 年,霍华德·T·费舍尔(Howard T. Fisher)在哈佛大学设计研究生院(Harvard Graduate School of Design)成立了计算机图形和空间分析实验室(LCGSA 1965 – 1991),在那里产生了大量处理空间信息的基本理论思想。到 20 世纪 70 年代,LCGSA 发布了开创性的软件代码和系统,包括 SYMAP、GRID 和 ODYSSEY;这些系统不仅为后续的商业开发提供了来源,而且它们自身也被分发到全球的大学、研究中心和企业集团。

MOSS 和 GRASS GIS 是两个在 20 世纪 70 年代末开发的公共 GIS 系统。大约几年后,在 20 世纪 80 年代初,新的商业 GIS 软件供应商出现了。这些商业供应商包括环境系统研究学院(Environmental Systems Research Institute)、CARIS、MapInfo 公司、ERDAS、M&S 计算公司,以及 Bentley Systems Incorporated(CAD)。这些销售商在融合众多新的 GIS 软件亮点和方式方面取得了丰硕的成果,例如将原始的空间和属性数据分割方法与第二代将属性信息组织到数据库结构中的方法相结合,以及融合 CGIS 功能。

第一个为 DOS 操作系统发布的知名桌面 GIS 产品被称为 Mapping Display and Analysis System,并于 1986 年公开发布。1990 年,MIDAS 被移植到 Microsoft Windows 平台,并在移植过程中更名为 MapInfo for Windows。这标志着 GIS 从研究领域转向商业领域的进程。

需要特别注意的是,CGIS 一直持续到 20 世纪 90 年代,并在加拿大建立了一个庞大的先进土地资产数据库。CGIS 被开发为一个基于集中式服务器的框架,作为政府的一个通用规划和管理系统。因此,它能够进行跨大陆的复杂数据集研究,但 CGIS 从未在商业市场领域提供。

在 20 世纪之交,用户开始通过互联网探索 GIS 数据。这需要数据传输标准化。所有这些都是由各种系统的快速增长所引起的,因此展示了这样一个缺陷:有许多不同的系统使用了非常少相似的方法或数据格式,需要整合。

近年来,开源 GIS 软件包的数量不断增加,它们可以在各种操作系统和软件上运行,并且可以非常容易地定制以执行特定任务。研究机构和爱好者通过互联网提供地图应用和地理空间数据。

GIS 技术和技术

如前所述,地理信息系统(GIS)技术大量利用数字信息。使用了相当多的不同数字数据编制方法。然而,最常见的数据编制方法是数字化,这是显而易见的原因。让我们快速回顾一下,定义一下数字化。数字化是指你有一个地图或调查数据的物理副本,并通过具有地理参照功能的 CAD 或类似程序将其转换为数字介质。随着正射影像设备如卫星、飞机、直升机和无人机等的丰富,抬头数字化正成为提取地理数据的首选资源。

抬头数字化是通过在航空影像上直接追踪地理数据来复制。低头数字化是将地理形状追踪到单独的数字化平板上的过程,这是一种更传统的方法。

GIS 可以参照任何可以在时空定位的变量。地球时空中的区域或度可能记录为事件的时间日期,以及 x、y 和 z 坐标用于表示经度、范围和高度。这些 GIS 方向可以涉及其他时空参照的测量框架的信息。这些 GIS 坐标可以代表其他时空参照的量化系统的数据。时空参照的一些例子包括电影帧数、流量计站、公路里程标、测量员基点、建筑地址、入口大门、街道交叉口、水深测量、POS 或 CAD 原点或单位。

记录时空数据所应用的单位可能差异很大;这包括使用完全相同的数据,因此,所有基于地球的时空位置参照都是相互关联的。这使得所有这些参照最终都能代表时空中的真实物理位置或范围。

GIS 数据用数字数据表示真实对象,这些数据决定了混合。这些数据包括道路、土地利用、高程、树木、水道、高速公路等等。这些真实对象通常分为两种不同的抽象:离散对象和连续字段。离散对象如房屋,连续字段如降雨量和评估。在 GIS 中存储数据有两种广泛使用的方法,用于这两种抽象的映射引用,这些已经成为传统:栅格图像和矢量。点、线和多边形通常用于映射位置属性引用。

目前正在使用一种新的混合数据存储方法,它能够将每个点的三维点和 RGB 信息结合起来。这能够返回一个 3D 彩色图像。GIS 主题地图在展示或确定内容方面正变得更加逼真。

有些非常流行的 GIS 文件格式被不同的软件应用使用,如下所示:

  • Shapefiles

  • 地理包

  • 世界文件

  • AutoCAD DXF

  • 笛卡尔坐标系

  • ADRG

  • 二进制文件,如 BSQ 或 BIP

  • DRG

  • ECRG

  • GeoTiff

  • JPEG2000

  • RAW

捕获 GIS 的方法

捕获 GIS 数据消耗了 GIS 从业者大部分可用时间。因此,有各种方法用于将数据输入到 GIS 中,并存储为数字格式。所有现有的打印在纸张或 PET 薄膜上的数据都可以数字化或扫描以产生数字数据。现在是定义数字化仪是什么以及它做什么的好时机。

手动数字化仪是一种经过修改的图形平板,它使用一种特殊的磁性笔、笔尖或滚轮,将信息输入到计算机中,以创建数字地图。然而,这些设备相当昂贵,但它们对于 GIS 数字化非常有用 (www.digitizerzone.com/calcomp-db6.html):

数字化仪可以从地图中产生矢量数据,如操作员跟踪点、线和多边形边界。扫描仪能够将结果扫描成栅格数据,这需要进一步处理以产生矢量数据:

largeformatscanners.com/large-format-technical-scanners.htm

使用测量仪器和称为坐标几何的技术,数据可以直接输入到 GIS 中。GPS(全球定位系统)的位置也可以收集并导入 GIS 软件。当前流行的数据收集方法允许现场计算机通过无线连接或离线编辑会话编辑实时数据。

更高可用性的低成本测绘级 GIS,具备实时厘米级精度的能力,增强了使用现场计算机编辑实时数据以及激光测距仪收集的位置的能力。使用这种技术的优势在于,它消除了野外工作后,在办公室进行的大部分后处理、导入和更新数据的工作。

越来越多的新技术正在被开发,这些技术允许用户在野外直接创建地图和进行数据分析,这使得项目和地图制作更加高效和准确。遥感数据在数据收集中扮演着重要甚至关键的角色,它由附着在平台上的传感器组成。这些传感器包括相机、数字扫描仪和激光雷达,而平台通常由飞机和卫星组成。

在 20 世纪 90 年代中期,英国创造了一种混合风筝和气球的 HeliKites。他们开创了使用紧凑型数码相机作为航空 GIS 数据收集的地理信息系统。飞机测量软件的精度达到 0.4 毫米,能够将照片与地面测量数据相连接。使用 HeliKites 的优势在于,它们可以在无人机(UAVs)被禁止使用的城镇、铁路和道路上使用。最近,微型无人机如无人机已被用于空中数据收集。目前,大多数数字数据都是从空中照片中收集的。

有软拷贝工作站用于从数字照片的立体对中数字化特征。数字照片的立体对允许在二维和三维中捕获数据。高程是通过摄影测量原理测量的。如果使用模拟的航空照片,它们必须在进入软拷贝工作站之前进行扫描,然而,如果使用高质量的数码相机,则可以跳过这一步骤。

来自卫星的遥感是用于空间数据的重要来源之一。卫星使用不同的传感器包来测量电磁波谱的一部分或/和无线电波的反射率。卫星遥感收集的栅格数据会经过不同频段的进一步处理;这有助于更好地识别物体和感兴趣的区域。

无论捕获数据来源如何,考虑数据是否以相对或绝对精度捕获都很重要。在相对或绝对精度之间进行选择会影响信息的解释以及捕获数据的直接成本。

在数据被输入 GIS 后,数据通常需要编辑。编辑确保可以移除错误或指定哪些数据部分需要进一步处理。扫描地图可能存在需要从栅格图像中移除的源图瑕疵。在使用高级分析之前,矢量数据必须制作成拓扑正确。

从栅格转换为矢量

通过 GIS 软件恢复的数据可以被转换成不同的格式。GIS 可以将卫星影像地图转换为矢量结构。这是通过在相同分类的单元格周围生成线条来实现的。它们还可以确定单元格的空间关系,例如相邻和包含关系。

图像处理可以进行更高级的数据处理。这项技术是在 20 世纪 60 年代由 NASA 开发的,并由私营部门进一步改进。它们可以进行二维傅里叶变换、对比度增强、假彩色渲染以及其他大量技术。由于数字数据以不同的方式存储和收集,数据源往往不兼容。为了解决这个兼容性问题,基于 GIS 技术的软件必须能够将地理数据从一个格式转换到另一个格式。GIS 能够做到这一点,因为它们采用了不同本体和分类背后的隐含假设,这些假设需要大量的分析。由于面向对象编程(OOP)的出现,对象本体变得更加突出,这使得它与游戏开发和 Barry Smith 及其同事的持续工作更加兼容。

投影和坐标系

地球可以用各种模型来表示,并且它们为地球表面的每一个点提供不同的坐标集。最简单的模型假设地球是一个完美的球体,尽管我们知道它不是。随着对地球的测量越来越多,地球模型变得越来越复杂和精确。有些模型具有适用于地球不同区域的不同数据,这提高了精度。NAD83 是一种美国测量,而 WGS84(世界大地测量系统)是全球测量。

NAD83 和 WGS84 之间有明显的但非常微小的差异,除了一个是全球性的,另一个是基于美国的。WGS84 使用 WGS84 椭球体,其质心误差小于 2 厘米,而 NAD83 使用大地测量参考系统(GRS80)椭球体,偏移量约为两米。NAD83 使用北美板块上的不变点,而 WGS84 使用全球所有站点的平均值,这些点不是固定的。NAD83 自创立以来没有变化;WGS84 已被修订,使用新的 EGM96 大地水准面偏差 105 米至+85。WGS84 被美国国防部(Department of Defense)使用,而 NAD83 被政府内的许多其他机构使用。

尽管 WGS84 和 NAD83 有不同的参数,但在测量过程中,结果的影响可以忽略不计。例如,WGS84 和 NAD83 的半次轴之间有 0.00010482 的差异,而扁率的倒数在两者之间有 0.000001462 的差异。为了更好地展示这一点,让我们看看 WGS84 和 NAD83 结果的美国地图比较:

图片

使用 GIS 进行空间分析

空间分析使我们能够更好地理解空间关系和模式,这反过来又使我们能够更好地理解我们的世界。正因为如此,我们能够绘制出事物的位置,了解它们之间的关系,以及这一切对环境的影响,以及采取哪些措施来逆转我们可能造成的任何不利影响。我们还能找到最佳路线,为众多不同的建设项目选择地点,进行高级预测建模,以及更多。

我们可以利用预测建模方面来了解森林火灾根据植被、特定地区的干燥程度和风力如何蔓延。不仅如此,我们还可以用它来找到建立商店的最佳位置,这将可能吸引最多的顾客。

使用 GIS 的空间分析是一个快速发展的领域。GIS 软件包正在获得越来越多的分析工具,这包括标准内置库以及可选的工具集和附加组件。原始软件供应商在许多情况下已经提供了这些工具,然而,第三方也在不断增加地提供和开发这些工具。许多产品提供与特定编程语言兼容的 SDK(软件开发工具包),具有脚本能力,以及开发定制分析工具的能力。

网站“地理空间分析”([www.spatialanalysisonline.com/](http://www.spatialanalysisonline.com/))以及由 Michael J de Smith、Michael F Goodchild 和 Paul A Longley 合著的相关书籍,能够提供关于该主题的相当全面的指南。可用性的大幅增加为商业和空间智能创造了一个新的维度,使地理和社会网络数据能够对每个人开放。通常被称为 GIS 空间分析的地理空间智能已成为现实世界中安全的关键要素。

使用 GIS 进行数据分析

当试图将湿地地图与不同地点记录的降雨量联系起来时,这可能很困难,尤其是在机场、学校和电视台等地方。GIS 可以用来可视化地球表面的二维和三维特征。这还包括从信息点获取的大气层和地下特征。GIS 可以从具有给出不同降水量指示能力的等高线快速生成地图数据。这种类型的地图被称为降雨等高线图。

许多方法能够从有限的点测量中估计地表的特征,并且需要高度复杂的技术才能准确完成。从表面建模降水点创建的二维等高线图可以与 GIS 中覆盖相同区域的任何其他地图叠加。这个派生地图能够提供额外的信息;在这种情况下,这将是水力作为可再生能源来源的潜在可行性。GIS 可以用来比较任何地理区域的许多其他可再生能源资源可行性选项。

此外,从一系列三维点中,可以通过坡度分析生成高程等高线,这可以通过计算从任何感兴趣点向上的所有区域来轻松定义流域位置。还可以从高程数据计算出连接山谷或河流沿线连续横截面最低点的预期线。

从所有这些中,我们可以确定数据分析过程有五个主要步骤:

  1. 构建问题框架

  2. 探索和准备数据

  3. 选择分析和使用的工具方法

  4. 执行分析

  5. 检查和细化结果

构建问题框架: 构建问题框架是一个好主意,可以使后续步骤更容易进行,例如,以有助于确定将用于分析的空间信息系统(GIS)工具和方法的方式来构建问题。

探索数据: 这一阶段通常被认为是耗时最长的,并且不能保证拥有分析所需的所有数据。了解将要使用的数据格式、数据的时效性、数据的比例和细节、使用的坐标系、数据是否使用任何与分析相关的几何工作、数据是否具有所需的属性以及数据是否有任何访问或使用限制,这些都是一个好主意。

准备数据: 在这一步,了解将要使用的数据格式至关重要,因为它将决定需要使用哪些工具集。确保数据是有组织的,数据可以轻松提取,并且在使用将要使用的工具处理数据时没有错误发生。

选择分析和使用的工具方法: 方法和工具应该能够通过提出的问题轻松定义。通常,问题应该直接对应于方法和工具,并且为分析绘制一个简单的图示被认为是良好的实践。以下图像提供了一个简单的例子:

图片

执行分析: 由于绘图被认为是良好的实践,这里需要做的只是按顺序执行任务。分析越复杂,可能就越有必要使用 ModelBuilder 创建一个模型来自动化过程,这将使更改参数并针对不同场景重新运行模型变得更加容易。

检查和细化结果: 这一步只是查看结果,看看是否遗漏了原始问题中的额外参数,并添加一些调整以更好地符合原始问题的愿景。

要更详细地了解,以及一些关于数据分析步骤的教程,请访问www.bcps.org/offices/lis/researchcourse/data_process.html

GIS 建模

GIS 能够识别存储在空间数据中的空间关系,并分析这些数据。这允许执行复杂的空间建模,研究几何形状的属性之间的关系,包括相邻性、包含性和邻近性。我们可以使用这些信息来更准确地建模和分析数据。

几何网络

所有这些都将我们引向几何网络。几何网络是由对象组成的线性网络,可以用来表示相互连接的特征并对它们进行空间分析。几何网络由在节点处相连的边组成。这与图论极为相似,图论在数学和计算机科学中被广泛使用:

如截图所示,网络可以分配权重和流量到边,这些边用于更准确地表示各种连接特征。几何网络的一般用途是建模道路网络和公共设施,如电力和水网络。它们也用于规划交通网络、基础设施建模和水文建模。

水文建模

GIS 中的水文模型提供了具有坡度、坡向和集水区等变量的空间元素和分析。这包括地形分析,因为水总是沿着坡度流动。坡度和坡向可以用来确定地表径流和河流、湖泊的流量积累的方向。

分流区域的面积也给出了关于集水区域的边界更清晰的指示。随着流向和积累矩阵的创建,可以执行查询以显示扩散区域。这允许向模型添加更多细节。这包括粗糙度、植被类型、土壤类型、蒸散率以及地表径流。所有这些都意味着水文建模非常适合用于环境污染研究。

地图建模

丹娜·汤姆林在 1983 年的博士论文中提出了“制图建模”这个术语,后来他在 1990 年出版的书籍《地理信息系统与制图建模》的标题中使用了它。

制图建模是产生、处理和分析同一区域主题层的过程。需要注意的是,汤姆林使用了栅格层,然而,叠加方法可以在大多数一般情况下使用。地图层上的操作然后可以与算法的使用相结合,以纳入模拟或优化模型中。

地图叠加

地图叠加是将几个空间数据集组合起来创建一个新的矢量输出数据集。你可以通过堆叠同一区域的几个地图来可视化这一点。另一种可视化方法是考虑数学中使用的维恩图叠加。有三种类型的叠加——并集、对称差集和交集叠加——用于不同的原因,这些原因不会在这里讨论,因为它们超出了本书的范围:

  1. 并集叠加是为了将两个输入的地理特征和属性表合并,并将结果输出到一个单一的输出中。

  2. 交集叠加是为了定义两个输入重叠的区域,并为每个输入保留一组属性字段。

  3. 对称差集叠加是为了定义包含两个输入总面积的输出区域,但不包括重叠区域。

GIS 中的数据提取与矢量叠加类似,具有在矢量或栅格数据分析中使用的功能。而不是结合两个数据集的属性和特征,提取数据可能涉及使用裁剪或掩膜来提取与另一个数据集相关的某个数据集的特征。

栅格数据分析使用多个栅格数据集或地图代数中的局部操作。地图代数有一个函数可以结合每个栅格矩阵的值,并且可以通过反映地理现象内部各种因素影响的索引模型与另一个函数耦合,该函数可以通过索引模型将某些输入的权重高于其他输入。

GIS 中使用的统计学

统计学在 GIS 中得到了广泛的应用,并且有一个专门处理实地数据的统计学分支。这个特殊的统计学分支使用具有连续索引的空間数据。它能够提供建模空间相关性和预测任意位置值的方法,这也就是所谓的插值。

当地理现象被测量时,观测方法可以决定任何分析的准确性。由于某些数据的性质,存在由数据收集的规模和分布决定的恒定或动态精度的限制,这种精度在测量过程中总是丢失。这种精度损失由数据收集的规模和分布决定。

在确定任何分析的统计相关性时,必须确定平均值,以便将任何测量之外的点包括到它们的预测行为中。应用统计学和数据收集方法在预测粒子、点和位置的行为方面存在局限性,这导致它们不能直接测量。

插值是通过在特定数量的样本点输入数据集来创建表面。然而,插值有几种不同的形式,并且它们各自以不同的方式处理数据,这取决于数据集的特性。当比较插值方法时,需要考虑几个点。首先,数据源是否会改变,以及是否使用精确或近似数据收集。接下来是方法是否主观,这本质上意味着是否使用人类解释或客观解释方法。接下来是点之间过渡的性质:是渐进的还是突然的?最后,检查方法是否局部或全局。

一种全局方法使用整个数据集来形成模型,而一种局部方法使用算法对小块地形进行重复。由于空间自相关规则,插值被用作估计的基本技术,该规则指出,在任何位置收集的信息将与其直接区域内的区域具有可比性或影响。

产生插值数据的数学方法如下:

  • 数字高程模型

  • 三角不规则网络

  • 边缘查找算法

  • 蒂森多边形

  • 傅里叶分析

  • 加权移动平均

  • 反距离加权

  • 克里金法

  • 样条

  • 趋势面分析

地理编码

地理编码是在空间区域中插入 xy 坐标。这些可以是来自道路地址或其他空间参考信息,例如,邮政编码、分区和地址区域。需要一个参考主题来地理编码单个位置,例如,带有地址范围的街道中心线文档。

通过检查沿街道部分的道路地址,已验证性地添加或评估了各个地址区域。这些通常以表格或数据库的形式给出。然后产品将在中心线部分该地址所在位置放置一个点。同样,地理编码也可以与真实包裹信息相关联。

反向地理编码

反向地理编码是将预期的道路地址编号恢复到给定位置的过程。你可以将其想象成一个反向电话号码查询表。同样,类似于反向电话号码查询表,反向地理编码不会返回实际的街道地址,只是基于预定范围应该存在的估计。结合 GIS,多标准决策分析技术支持领导者分析一系列空间方案。MCDA 使用决策规则来汇总标准,这允许选择答案被定位或排序。GIS MCDA 可以减少识别潜在恢复地点所涉及的费用和时间。

开放地理空间联盟标准

开放地理空间联盟OGC)是一个成立于 1994 年的非营利组织,拥有超过 384 家公司、大学、政府部门和个人参与,旨在发展公开可用的地理处理规范。

OpenGIS 规范定义了公约和接口,以帮助实现能够使网络、远程、位置服务、技术工程师和标准 IT 创建复杂空间数据和服务的系统,使其对各种用途类型有用和有价值。

网络地图服务和网络要素服务被纳入 OGC 公约。任何同意 OGC 的 OpenGIS 特定要求的产品项目被称为合规产品,当一个项目经过 OGC 测试计划的测试并获得确认后,它将自动在公开地理空间数据库中登记为一致。

成为“OGC 保证”的程序分为五个阶段:

  • 前往测试网站并选择所需产品的标准

  • 前往 OGC 在线认证系统,并提供有关产品、测试账户和所需认证标准的详细信息

  • OGC 将对许可费和新的或修订的商标许可协议进行审查和联系

  • 收到证书后,OGC 合规标志即可用于使用

  • 产品随后将出现在 OGC 实施数据库中的认证列表中

详细信息可以在官方网站www.opengeospatial.org/compliance/getCertified找到:

图片

注意,并非所有规范都提供一致性测试。尽管如此,设计师可以将他们的产品注册为实施草案或批准规范,尽管 OGC 保留审查和检查每个部分的权力。

网络地图

最近,许多免费且易于使用的专有地图软件,例如 Google Maps、Bing Maps、Apple Maps 和 Baidu Maps,以及一些免费和开源的选项,如 OpenStreetMap、GMap.NET、Wikimapia、RMaps 和 uebermaps。这些服务为大量 GIS 注入的地图数据提供免费服务。

许多系统提供 API(应用程序编程接口),允许用户创建自定义应用程序或扩展现有应用程序。这些库或系统倾向于提供道路设计、卫星符号、航拍符号、地理编码、地理参照、地理围栏、搜索和导航功能。在诸如网络地图制作等项目中,众包地理数据已被发现是一种合作任务,旨在为所有需要使用该特定应用程序或数据库的人创建免费且可编辑的世界地图。

GIS 和时间维度的结合

地球的状况,这包括地下、环境和地表,可以通过鼓励卫星信息进入 GIS 编程来分解。GIS 使专家能够利用创新来研究地球过程的变化,这些变化跨越了数日、数月、数年,甚至数十年。植被健康的变化可以通过生长季节进行模拟,以确定在特定地区干旱季节何时会有最严重的影响。这些结果可以提供一个粗略的衡量标准,以评估模拟区域植物的健康状况。仅仅使用两个因素并在一段时间后对其进行估计,研究人员就能决定降水衰减的差异以及这些差异对地区植被的影响。

高级数据在本地和全球范围内的可用性使 GIS 技术能够进行此类研究。卫星传感器每天为地球的特定区域提供两次图像。MODIS(中分辨率成像光谱仪)和 AVHRR(先进高分辨率辐射计)是用于地球表面分析的多传感器系统中的两个。这些传感器系统可以识别地球表面反射的能量在不同频率范围内的测量值,这些值适用于高达一平方公里的区域。

不仅时间正在通过 GIS 被纳入生态研究,而且跟踪和模拟人类和动物在其日常生活中的发展进程的能力也在被研究。这可以通过谷歌和 Facebook 的位置服务看到,这些服务在用户使用后可以跟踪一个人长达数天、数月甚至数年。这种数据创建和管理在没有 GIS 和这种类型的卓越分析的情况下是无法实现的。规划者还可以通过使用空间选择情感支持网络,利用模型将 GIS 内部包含的数据向前扩展来测试策略选择。

语义学

万维网联盟的语义网通过工具和技术的不断发展,在数据系统中整合信息问题变得非常有用。这些工具和技术被提议作为不同基于 GIS 的应用程序之间互操作性和信息重用的方法,并允许新的分析机制。

已经为此空间的一些概念和类别制定了一些安排,以表明它们的概念和关系的正式和机器清晰细节。这使得 GIS 能够关注信息本身,而不是信息的语言结构或结构。W3C Geo 孵化器小组建议了更简单的本体和语义元数据措施,特别是为了在互联网上表示地理空间信息。GeoSPARQL 就是其中之一,它是一种用于资源描述框架RDF)数据的地理查询语言,其中有一些基于 RDF 的进步,为定义实际结构提供了语言,例如网络本体语言OWL)和简单知识组织系统SKOS)。

GeoSPARQL 是由开放地理空间联盟OGC)开发的,并得到了众多领域专家的支持,而不仅限于英国测量局、美国地质调查局、加拿大自然资源部、工业研究组织以及澳大利亚联邦科学和工业研究组织。GeoSPARQL 为 OGC 提供了诸如地理标记语言GML)和 WTK(肯定理解内容)等字面量,以及简单的突出显示,例如 RCC8(区域关联分析)和 DE-9IM(维扩展九交叉点演示),它们提供了拓扑关系和主观思维,此外,还有 SPARQL 扩展能力和用于查询转换和解释的规则互交换格式RIF)中心推导规则。

这里有一些后续研究成果,可以在国际地理空间语义学网络研讨会和国际语义网会议上找到。

GIS 在社会中的影响

近年来,GIS 在基本领导层中变得相当知名,研究人员开始深入研究 GIS 的社会和政治影响。同样,与任何框架和信息收集与分析一样,GIS 容易受到滥用,以扭曲现实以实现政治和个人主义的目标。地理数据的生成、传播、使用和描述被认为与社会环境密切相关,并且还持有增加对政府怀疑的潜力。

被深入研究的不同点涉及潜在的版权侵权、监管和保护。该领域的许多人更加乐观,他们相信许多人将采用的社会方法是策略性地将 GIS 利用作为一种开放合作的工具。

现实世界中的 GIS

GIS 不仅可以在学术领域使用,而且在实际生活中也能非常有效地应用。我们已经看到了 GPS 应用的兴起,这些应用在很大程度上取代了传统的地图,知道你确切位置的 APP,能找到丢失的设备或孩子的 APP,以及更多。通过获取所有可能获得的地理和统计数据,现代生活的几乎每个领域都已经被或可以用于 GIS 数据。

我们可以从历史事件中真正看到这一点;让我们以黑死病为例。与过去的人不同,我们拥有 20/20 的先见之明;我们知道是老鼠传播了这种疾病。假设我们拥有所有展示老鼠移动和旅行信息的数据,然后我们可以用来研究它们的模式,并对瘟疫的起始点和传播方式有一个更准确的描述。

这还不止于此,因为那更多是关于学术方法。假设我们想要追踪过去五年内的日常模式。我们可以使用位置数据以及 GIS 来准确描绘我们的日常活动。我们还可以进一步思考如何通过创建针对 IP 地址的 GIS 来跟踪我们的互联网使用情况,该 GIS 展示了网站访问的频繁程度和稀疏程度。

然后,还有电子游戏;我们可以以多种方式将 GIS 应用于电子游戏,从复制世界各地历史战场使用的地形,到混合来自不同行星和卫星的 GIS 数据来创造一个完全陌生的世界。但我们也可以通过将 GIS 数据注入摄像头来增强我们周围的现实,以转换或识别它实时读取的相似数据。

教育中的 GIS

在 20 世纪初,地理信息系统(GIS)开始被认可为课堂上的工具。在教育中使用的 GIS 具有专注于空间思维发展的优势。然而,由于缺乏统计数据显示全球 GIS 使用的范围,其缺点是几乎没有数据来证明这一点,尽管那些具体提到 GIS 的课程的国家发展速度更快。

地方政府中的 GIS

GIS 已被证明是一个组织范围内的企业级技术,它持续适应地方政府在许多任务上的运作方式。许多,如果不是所有,政府机构都已采用 GIS 技术作为更好地管理和改进其组织的方法,例如:

  • 公共安全运营,如应急操作中心、防火、警察和治安官的移动技术和调度,以及天气风险制图

  • 公园和娱乐部门及其在资产盘点、土地保护、土地管理和墓地管理中的职能

  • 公共工程和公用事业,追踪水和暴雨排水、电气资产、工程项目以及公共交通资产和趋势

  • 纤维网络管理用于部门间网络资产

  • 学校分析和人口统计数据、资产管理以及改善/扩展规划

  • 公共行政用于选举数据、财产记录和分区/管理

开放数据倡议促使地方政府利用这项技术,并按照开放数据和开放政府模型的透明度要求共享自己的数据。由于开放数据,地方政府机构可以实施在线门户,让公民查看和利用这些信息。来自政府内部和外部对开放数据的推动已成为地方政府 GIS 技术支出和数据库管理的一个巨大推动力。

GIS 和增强现实

如前文所述,GIS 与增强现实的应用仅受限于你的想象力,尤其是当你考虑到你可以从 GIS 数据中利用的大量数据类型时。因此,在下一节中,我们将探讨并思考如何将 GIS 应用于增强现实应用和游戏。

GIS 的应用

如 Esri 应用程序原型实验室的 Richie Carmichael 在在线文章(www.esri.com/news/arcuser/0311/augmented-reality-and-gis.html)中对 Keith Mann 所说:

“想象一下,如果你能将手机摄像头对准地面,就能看到地下水管和电线的位置和方向,因为你的 AR 应用正在将 GIS 系统与你的位置交叉引用,给你一种 X 光般的视觉,让你能够可视化你下面的基础设施。”

这种思维方式被许多公司所反映,如谷歌、腾讯、微软、Facebook、Twitter、苹果等。中国的腾讯在增强现实和 GIS 方面做了很多事情。我认为回顾中国使用 AR 和 GIS 所做的事情是非常有价值的。

中国完全不使用谷歌的服务,不得不创建自己的搜索引擎,即百度。这也意味着他们必须开发能够充分利用 GIS 的地图软件。他们创建了百度地图,其工作原理与必应地图和谷歌地图类似,然而,他们在其中加入了一些微妙的改变。你可以为其添加一个单独的包,使其易于使用或集成到 AR 应用中。

通过佩戴智能眼镜,它会在你面前投射地图,显示你已经走过的步数,以及你到达目的地需要前往的第一人称覆盖位置。

他们还重度集成了社交媒体平台 QQ 和微信,以与他们的地图软件协同工作,这让我想到了微信的实时位置分享功能。它实时显示你的位置和你试图见的人的位置,并且每走一步都会更新。

当然,谷歌有谷歌地图,它显然与百度地图和必应地图非常相似。这留下了苹果地图,它是第一个将 AI 语音增强重度集成到其地图服务中的。AutoCAD 和 Blender 是两款能够读取和操作 GIS 数据的程序。它们可以导入 shapefile 并创建地形的三维表示,或者将其导出为指定的文件格式。在 AutoCAD 的情况下,它可以导出数据到 XML,然后可以用来提取所需的具体信息,例如人口密度,或类似的东西。

AuGeo 是由 Esri 制作的,它是一种开源编程形式。这款产品使你能够直接在手机上以第一人称视角控制、下载和查看信息。AuGeo 将增强现实与 GIS 结合,并在实时摄像头流上显示突出信息,以便你可以调查你的 GIS 信息。

由 Augview Limited 制作的 Augview,既是一款多功能的 GIS,使客户能够查看和修改他们在现场的利益信息,也是一款增强现实应用,使客户能够想象他们通常不会观察到的地下抗议活动。这些只是众多组织和应用中的一小部分,这些组织和应用被创建出来用于使用、查看和/或控制 GIS 信息。在我们继续之前,我们应该调查一些利用 GIS 和增强现实的应用。

EyeMaps 让您能够获取关于选定语言的信息。只需使用相机模式来获取关于您周围世界的想法。它会立即为您提供山脉、城市、城镇、博物馆等等的名称。通过链接到维基百科来获取更多信息。在 3D 地图上观看和分享您的照片。本应用的主要亮点是在提供数据检查的同时,为您创建一个周围环境的 3D 地图。

Vortex Planetarium 是一款关于天空一切的出色且简单的应用。存在大量信息,包括夜空物质的所有内容、成千上万颗星星、星群、梅西天体、卡德威尔项目等等。本应用的基本亮点在于高度可配置的内容。设置星群艺术作品的清晰度或点击您希望在夜空中找到的星星数量。

Plane Finder 让您能够实时查看全球范围内的所有航空活动。该应用在提供高度定制内容以满足您需求的同时,还允许您使用增强现实技术通过您的设备摄像头识别空中的飞机。该应用还允许您设置当飞机出现在您上空时发出警报。本应用的基本亮点在于它通过获取实时 ADS-B 信号来工作。这项技术比传统雷达更快!

iOnRoad 让您可以从手机中制作一个高度实用的工具。它通过 GPS、活动检查、视频和图片捕捉等功能为您提供帮助,并且功能相当多。本应用的亮点在于它利用您的设备本地摄像头、GPS 和传感器来识别您面前的车辆,在驾驶员处于危险时提醒他们。

在我的桌面上玩恐龙增强现实游戏让您可以尝试抚摸一只虚拟恐龙。来自远古时代的好奇而可爱的恐龙将在您的桌面上徘徊。您可以通过手动操作或在屏幕上点击它来玩耍。您甚至可以喂它。但无论您做什么——记住,它有一个贪婪的脾气!本应用的主要亮点是让您能够玩并了解恐龙的古老世界。

EmotionsAR 应用是为那些看过《哈利·波特》中的活照片并一直想为自己拥有一个的人设计的。EmotionsAR 为您提供了一种独特的拍摄方式,可以让照片栩栩如生。那会是什么样子?一个简短的动态照片,还是一个长视频故事?这由您决定。本应用的主要亮点是您可以使用 AR 视频内容创建自己的照片!

阿尔贝拉彩色活生生(Crayola Color Alive)使您能够通过从阿尔贝拉涂色页上升起的生动模型为您的阴影插图注入生命。将您最好的角色留给您的亲人,并随时使用它们。这个应用程序的主要特点是有大量的角色,允许您免费打印页面,或者购买套装,然后上色并赋予它们生命。

游戏和 GIS

游戏和地理信息系统(GIS)是一个非常有趣的话题,由于 AR(增强现实)有多种实现方式,因此有无数种方法将这一想法融入其中。要真正展示将 GIS 融入游戏并应用一种增强现实形式的典范,我们无需寻找比史上最著名的多人在线游戏《魔兽世界》更合适的例子了。

为了设定场景,我们首先需要解释一些《魔兽世界》的特点以及数据修改者需要处理的数据。在《魔兽世界》中,您可以选择许多不同的职业,所有这些职业都需要您收集制作物品所需的材料。有不同类型的布料、矿石、花朵、考古地点位置、烹饪食谱以及可以在整个世界中找到的许多不同的制作食谱。这还不包括盔甲、武器、随机生成的稀有怪物以及可以通过世界找到的世界 Boss 位置。

为了将 GIS 融入《魔兽世界》,人们绘制了世界地图的地形,或者从游戏中的数据文件中提取数据,绘制了整个世界中所有生成物的位置,并将它们抽象成不同的层,这些层与它们所参考的内容相对应。然后,他们将它们叠加在世界地图上,并附加到小地图上,以便在启用模组的情况下玩游戏时显示它们的位置。

正如您所看到的,增强现实不仅适用于现实世界,也适用于幻想世界。这使得 AR 非常灵活,尤其是在您能找到方法将 GIS 融入其中的时候。接下来,让我们看看一些专注于现实世界的纯 AR 游戏。我们将首先关注的游戏是 GeoGuessr。GeoGuessr 最初是一个小型的网络应用程序,它为您提供了一系列随机的街景图片的猜测区域测试。在您做出猜测后,它会揭示真实的位置,并根据您接近的程度给予分数。

接下来我们要介绍的游戏是 Pursued。这是一款由匈牙利游戏设计师 Nemesys Games 开发的非常受欢迎且有趣的街景游戏。游戏的基本主题如下:“你突然被绑架了。一个朋友正在试图帮助你,但你必须弄清楚你在哪里!”游戏的目标是尽快猜出你所看的城市的名字,并在文本框中输入。如果你不能通过街景中的视觉线索猜出答案,你可以通过点击街景图片来移动,并使用 '+' 和 '-' 键来放大和缩小。

在列表中排名第三的是 Smarty Pins。Smarty Pins 是由谷歌工程师开发的一款游戏。游戏的目标是发现问题的答案,并在指南上标记这个区域。例如,你会得到这样的问题“最古老的英国大学在哪里?”然后你需要把标记放在牛津。主要问题通常位于玩家的本国附近,或者与非常著名的地方或人物有关,但随着你的进步,游戏板会扩展到整个世界,难度也会增加。

Guide Race 在列表中排名第四。它的想法是向你展示一个地区的卫星照片和四个可能的答案。挑战是在最短的时间内选择正确的答案。如果你猜错了城市,你会得到更多机会来理解它,这是很糟糕的。

排名第五的是 MapsTD。MapsTD 是一款使用谷歌地图创建来自世界各地任何地区的关卡的最高峰防御游戏。你的任务是巧妙地放置和管理你的防御塔,以保护你的宫殿免受攻击者侵犯。这是一个非常标准的巅峰防御设置,但乐趣来自于在真实的街道和地区进行。

列表中排名第六的是 Build。这是谷歌和乐高合作展示谷歌 Chrome 潜在功能的一个项目。它允许用户使用虚拟乐高构建他们能想象到的一切,并将其放置在谷歌地图上,与世界分享他们的作品。正如其名所示,它只能在谷歌 Chrome 中运行。

Geo Guns 是一款坦克射击游戏,在我们的列表中排名第七。这款游戏充分利用了谷歌地图的 45°(鸟瞰)卫星视图。它将几辆坦克叠加在卫星图像上。你的任务是摧毁敌方坦克。你可以从预设的战区区域中选择坦克战斗,但你可以通过在屏幕顶部输入地区来选择任何地区。

Find Street 是一个基于 StreetView 的游戏,排名第八。它为你提供了一系列不规则的 Street View 场景。你的任务是理解每张图片的区域并选择正确的测试回复。正如你所见,你可以非常容易地在游戏中同时利用 GIS、地理参照和 AR,或者通过利用这些方面的各种方面来创建它们。

需要牢记和记住的关键点如下:

  • 地图设计和玩家与地图的交互是创建视频游戏任务的一个基本部分。

  • 因此,从图形上看,游戏的外观设定了其基调,就像控制体验、不安全感、探索或剧情一样。

  • 在竞技类游戏中,地图代表的是竞技场。每一个角落,每一个细微的修改都是至关重要的,因为玩家们根据这些信息来定位自己的位置。对这种定位的监控对于获胜队伍来说是必须的。

  • 在开放地图游戏中,游戏体验往往超过了地图提供的信息。

这些项目对于确定哪种方法最适合你想要实施的想法和结构至关重要。

摘要

在本章中,我们讨论了 GIS 的历史,GIS 数据的收集,GIS 数据的使用,GIS 应用,GIS 游戏,以及如何将 GIS 集成到增强现实应用和游戏中。提供了许多有趣的信息,例如数据格式及其随时间的变化;我们了解到 GIS 有许多应用,无论是过去还是现在,在统计和分析方面,都可能会继续在地球上和其他星球上使用,正如我们开始看到的水星、金星、火星和我们的月球一样。

GIS 是一个广泛的领域,具有以多种不同方式应用于各种目的的能力,在学习 GIS 的基本原理及其历史时,我们现在可以将这些信息应用于我们创建的游戏和应用中。在下一章中,我们将学习关于 Unity 中的传感器和插件。

问题

  1. GIS 的历史始于 1970 年:

A.) 正确

B.) 错误

  1. GIS 代表地理信息策略:

A.) 正确

B.) 错误

  1. 克里斯托弗·皮凯特进行了已知的第一项空间分析应用:

A.) 正确

B.) 错误

  1. 约翰·斯诺在 1854 年找到了霍乱爆发的准确来源:

A.) 正确

B.) 错误

  1. 约翰·斯诺被许多人认为是疾病制图的先驱:

A.) 正确

B.) 错误

  1. 现今,CDC 使用 GIS 进行疾病制图:

A.) 正确

B.) 错误

  1. 头部数字化的数字化是通过在航空影像上直接追踪地理数据来复制的:

A.) 正确

B.) 错误

  1. 流行的 GIS 文件格式包括 Shapefiles、AutoCAD DXF 和 GeoTiff:

A.) 正确

B.) 错误

  1. 在应用中使用 GIS 时,GIS 不用于确定地理位置:

A.) 正确

B.) 错误

  1. GIS 在教育中没有被用于任何形式:

A.) 正确

B.) 错误

第三章:保密 - 各种传感器数据和插件

希望您能原谅标题中的俏皮双关语。在本章中,我们将讨论我们可以通过提供的各种 SDK 访问的各种传感器。这包括 ARKit、Vuforia、ARCore、Swift API 和 Java API。现在,我们将采取这条路线的原因是,核心 API 中有一些内容在提供给 Unity 的 SDK 中没有暴露,但我们可以通过使用 C# 中的包装调用原生插件来利用这些内容。为了简化说明,不超出本书的范围,我将不会教授 Java 或 Swift 编程语言的语法;已经有其他 Packt 作者编写了一些关于这些材料的优秀书籍,例如 《Swift 入门》 (www.packtpub.com/application-development/beginning-swift) 和 《Java 编程入门》 (www.packtpub.com/application-development/java-programming-beginners)。

本章将分为几个主要部分,具体如下:

  • 利用插件利用传感器

  • 编写 Unity 插件

  • C# 语言插件

  • C++ 语言插件

  • Swift 语言插件

  • Objective-C 语言插件

  • Java 语言插件

通过将这些章节划分为不同的部分,我们可以让您更容易找到您想要的特定部分。

项目概述

我们将使用 C#、C++、Swift、Objective-C 和 Java 创建基本的插件。每个插件都将是一个基本数学返回值的实现。使用原生代码编写插件,每个代码片段的完成时间不应超过 10 分钟。您必须在 Unity 中有一个可工作的测试。

入门

在处理 AR 应用程序和游戏时,必然会有先决条件,而本书也不例外。

以下是对 Apple Mac 计算机的要求:

  • macOS 11

  • Xcode 9

  • Mono 框架 5.14.0

  • Unity 2017

  • ARKit

建议您使用 2013 年或更晚的型号的 Mac 计算机,因为旧版本不支持图形的 Metal API。

当您在 Mac 上安装 Unity 时,它还会安装 Visual Studio for Mac;但要注意,它需要 Mono 框架才能运行,因此请确保下载并安装所有内容。

这里是 Windows 计算机的要求:

  • Windows 10

  • 8 GB 或更多 RAM

  • Unity

  • ARCore

  • JDK 8 或更高版本

  • Visual Studio

  • Android Studio

更多信息,请点击以下链接:

store.unity.com/

developer.apple.com/arkit/

www.mono-project.com/download/stable/#download-mac

www.visualstudio.com/

developer.Android.com/studio/

传感器

首先,我们需要对传感器是什么以及它们可以用于什么有一个良好的理解,然后我们才能进入与我们将要使用的每个 SDK 相关的各种小型项目。这个传感器列表绝对不是完整的列表,而是我们在 AR 应用和游戏中可以利用的一些最常见的传感器:

  • 指纹传感器

  • 辐射传感器

  • 心率监测器

  • 步数计

  • 空气湿度传感器

  • 温度计

  • 气压计

  • 光传感器

  • 距离传感器

  • 磁力计

  • 陀螺仪

  • 加速度计

  • 环境光传感器

  • 眼睛扫描仪

  • 红外遥控发射器

  • 触摸传感器

  • 麦克风

  • 摄像头

  • 全球导航卫星系统(GNSS)

  • 近场通信(NFC)

  • 激光

  • 空气手势传感器

  • 信号接收器

  • LiFi

  • 时钟

在本节中,我们将描述这些传感器各自是什么,以及除了它们的基本功能外,它们还可以用于什么。

距离传感器:距离传感器可以检测手机是否在特定范围内,并操纵软件或硬件以某种方式做出反应,一旦传感器被触发。它通常用于在手机达到用户耳朵或口袋的特定范围时降低电池消耗总量。在 AR 游戏和应用中的理论使用需要一点跳出思维定势。我们知道距离传感器不能检测物体之间的差异,因此我们可以做的是检测设备附近是否有多个物体,并基于此注册事件。

陀螺仪:陀螺仪是一种传感器,用于读取和输出安装了传感器的手机或设备的方向。它通常用于为应用程序供电并检测设备的方向,以确定 UI 是否应以横幅或纵向模式显示。在 AR 游戏和应用中的理论使用可以是使用设备作为穿越游戏世界的指南针。

指纹扫描传感器:指纹扫描传感器是一种传感器,用于检测是否对特殊板施加了压力,并从板上读取输入数据。

通常用于在登录密码之上增加一层额外的安全措施。与大多数标准密码相比,它更加安全且难以绕过,即使是在加盐的 AES 加密下也是如此。

摄像头:摄像头本身就是一个传感器。它能够将光波和发射的电磁辐射数字化,以便设备可以解释信息并以用户可理解的方式显示。它通常用于拍照存储和检索。

气压计:气压计传感器旨在检测大气压力的变化,这反过来意味着它可以有效地作为预测天气的手段。

它通常用于确定用户所在的一般地区的天气。

温度计: 温度计传感器是一种用于检测温度变化并将该信息存储/发送以供显示或处理的传感器。它通常用于跟踪和测量设备中敏感组件的温度。

加速度计: 加速度计是一种用于检测设备动量的传感器,并且通过扩展,可以检测用户的动量。它通常用于确定用户在持有设备时的移动速度。

计步器: 计步器是一种传感器,它设计为将用户的动量转换为步行步数。它通常用于计算用户的每日步数,并在特定时间显示给用户查看。

触摸传感器: 触摸传感器设计为检测用户的手指何时触摸设备的屏幕,并返回手指在该位置的位置和时间长度。

它通常用于激活和操作设备的所有基本和高级用法。

麦克风: 麦克风是一种传感器,设计为检测声波并将它们转换为设备可以理解和存储的数字信息。它通常用于在电话通话期间拾取声波并将这些数据传输到远程连接的设备。

环境光传感器: 环境光传感器设计为能够对各种光照条件做出反应,以模仿人类眼睛对这些不同光照场景的感知和反应。它通常用于通过调整背光亮度级别(使屏幕变亮或变暗)来节省电力,这取决于设备周围的光照。

虹膜扫描传感器: 虹膜扫描传感器设计为创建眼睛的高分辨率图像。它主要用于安全目的。它被认为是一种生物识别安全形式,因为它只会接受用于解锁设备的特定眼睛的数据。

空气手势传感器: 空气手势传感器能够通过红外传感器检测设备屏幕前的手势运动。它通常用于在不使用触摸屏的情况下添加对设备的基本控制,例如激活屏幕或应用程序。

心率监测传感器: 心率监测传感器是一种通过结合算法、绿色 LED 和加速度计来测量血流量并存储该信息的传感器。它通常用于在运动期间准确测量心率。

空气湿度传感器: 空气湿度传感器是一种热导率传感器,它利用温度传感器的某些方面来检测湿度。

光传感器: 存在许多不同类型的光传感器,可能是光敏电阻、光电二极管,甚至是光电晶体管。它们被设计用来检测特定区域是否存在光线,以及如果存在,有多少光线可用。光传感器通常与环境光传感器协同工作,以提供准确的拍照光线评估。

磁力计: 磁力计是一种用于测量磁力的传感器。磁力计通常用于寻宝应用。

红外遥控发射器传感器: 红外遥控发射器传感器是一种设计用来模拟红外遥控器的传感器。它通常用于为各种设备创建通用遥控器应用。

GNSS全球导航卫星系统):GNSS 是一种传感器,旨在接收来自多个卫星的信号,以实现更高的精度、可用性和冗余数据收集。

它通常用于轮询用户的位置,以便在 GPS 应用中提供更准确的结果。

NFC近场通信):NFC 传感器被设计为基于近距离通信的无线数据传输器。它们通常用于使用如 Apple Pay 和 Apple Wallet 支付等服务。

信号接收器传感器: 信号接收器传感器是一种设计用来接收无线电波并将它们转换为设备可以理解的数字形式的传感器。它通常用于电话通话或从收音机播放音乐。

LiFi 传感器: LiFi 传感器,也称为光 fidelity 传感器,使用发光二极管LEDs)来传输数据。它们通常用于无法使用 Wi-Fi 的区域,如发电厂,以发送和接收数据。

时钟: 实时时钟RTC)被设计用来准确跟踪时间。

这是一个显示确切时间的时钟。

利用插件利用传感器

如前所述,我们可以访问任何暴露的硬件提供的信息,并将这些信息发送到我们在 Unity 中创建的应用程序和/或游戏中。问题是,如果 Unity 或我们用于 AR 应用的 SDK 中没有实现,我们需要创建一个带有包装器的插件来访问该传感器。

这也高度依赖于我们想要针对哪些设备,以及我们是否想要针对 iOS 和 Android 设备而不进行任何实现。如果是这样,那么我们需要自己创建插件。我们不能仅仅用 C#编写插件;我们需要本地插件来调用这些传感器以完成我们的任务。这意味着我们需要利用 Java 和 Swift 语言为它们各自的操作系统。对于 Android,本地级代码将是 Java 或 C++,而对于 iOS,本地级代码将是 Swift、Objective-C 或 C++。

极其重要的是,我们首先了解传感器值是如何从 JDK 和 Apple SDK 返回给我们的。JDK 将所有传感器分解为特定类别。加速度计、陀螺仪和计步器都属于运动传感器类别;温度传感器位于环境传感器类别中。

需要明确区分需要完全理解的类别。环境传感器类别为每个传感器事件返回单个传感器值;而运动传感器类别将返回每个发生的事件的多维数组。有了这些信息,让我们继续下一部分,我们将学习如何用 C++、C#、Java、Swift 和 Objective-C 编写和剖析基本的 Unity 插件。

编写 Unity 插件

我们首先需要了解 Unity 中插件是什么,这样我们才能创建并剖析一个非常简单的 Unity 插件。

什么是插件?

一个 插件 是一个 dll 文件,它存储了用不同编程语言编写的代码,这是某些需要执行的事件的基础实现,或者是在相同语言中提供核心代码基础实现,这些代码作为库或不可更改的事件。

现在,这是一个非常简单的定义,但我们可以通过解释它们能为开发者或想要利用你编写的代码的开发者做什么来做得更好。插件允许开发者通过访问对它们公开的方法和属性来扩展现有代码,而不必通过源库进行艰难的搜索,从而为游戏引擎添加不是原生存在的功能,分离特定操作系统的代码,并且可以减小应用程序的大小。

对于 Unity 来说,插件允许我们直接与本地调用进行接口交互,并在我们的应用程序或游戏中按需使用它们。许多开发者倾向于创建使用本地系统调用的插件来扩展渲染管线或增强着色器。

重要的是要注意,在 Unity 中有两种非常不同的插件类型可供使用。这两种类型是本地插件托管插件。对本地插件和托管插件之间差异的非常简化的解释是,本地插件用于低级调用,而托管插件是隐藏源代码的一种简单方法。

然而,它们之间的区别比这个古老的谚语要微妙得多。

管理插件可以在开发者想在资产商店出售东西时轻松隐藏源代码。它还可以用于包含其他情况下无法轻易获得的库和框架。例如,开发者可以将 Entity Framework dll 文件导入 Unity,并利用 Entity Framework 在 Unity 中创建、管理和处理数据库代码。管理插件还能做的最后一件事是允许开发者利用 Unity 不支持的某些 .NET 语言和编译器,例如 F#、JScript、IronPython、ClosureCLR 或甚至 Powershell。例如,开发者可以为 Unity 创建一个插件,允许使用 IronPython 进行脚本编写,或者他们可以使用 IronPython 编写游戏代码,将其作为插件导入并使用而不会出现问题。

另一方面,本地插件的功能强大得多。本地插件通常由使用 Java、Swift、Objective-C 或 C++ 访问各自设备的直接硬件,并提供开发者在其他情况下无法在 Unity 中访问的功能。假设一个开发者正在与一个连接到智能手机的设备合作,而这个设备通常不在智能手机中;在这种情况下,我们将以 BACtrack Mobile Pro 作为我们的例子。

BACtrack Mobile pro 是一款警用级别的酒精测试仪,可以检测用户的血液酒精含量,并通过蓝牙连接将信息发送到设备。这位开发者想制作一款饮酒风格的 AR 游戏,并希望游戏难度随着最终用户血液酒精含量(BAC)水平的升高而增加。这位开发者需要使用本地插件来访问 BACtrack 设备传感器的结果。

现在应该已经从这一解释中获得了牢固的理解,我们最终可以开始查看 C++、Swift、C# 和 Java 插件的结构。我们将创建一个非常简单的插件,该插件将简单地相加两个数字。这是为了保持简单,并使整体工作流程的步骤更容易遵循。

Unity 会自动识别一系列文件类型作为插件。我们熟悉这些文件格式非常重要:

  • .dll

  • .winmd

  • .so

  • .JAR

  • .aar

  • .xex

  • .def

  • .suprx

  • .prx

  • .sprx

  • .rpl

  • .cpp

  • .cc

  • .c

  • .h

  • .jslib

  • .jspre

  • .bc

  • .a

  • .m

  • .mm

  • .swift

  • .xib

此外,还有一些文件夹类型被视为单个插件;它们如下所示:

  • .framework

  • .bundle

  • `.plugin`

使用 Unity 的本地插件时,可能会遇到导致称为 名称混淆 的现象的链接问题。名称混淆也称为 名称装饰,它本质上是一个为程序中的每个函数赋予唯一名称的过程;这样,链接器就可以区分语言中的常见名称。问题在于没有标准,它们通常与 C 编译器不兼容。

C# 语言插件

让我们开始用 C# 创建我们的第一个插件:

  1. 我们需要首先打开 Visual Studio 并创建一个新的项目。这个新项目类型将位于 Visual C# 的 Windows Desktop 子文件夹中,并且需要是一个类库 (.NET Framework):

图片

项目类型

  1. 项目名称将是 CSharpManagedPlugin,框架版本将是 .NET Framework 3.5。选择 OK 按钮:

图片

项目设置

确保将框架版本更改为 3.5 非常重要,因为我们需要确保 Unity 可以利用我们的插件而不需要实验性支持。

  1. 现在我们已经创建了我们的解决方案,我们可以将类名从 Class1 改为 Addition。现在,添加一个名为 addify 的整数方法,参数为 ab,然后返回 ab。你的代码应该如下所示:
namespace CSharpManagedPlugin
{
    public class Addition
    {
        public int Addify(int a, int b)
        {
            return a + b;
        }
    }
}

我们现在可以构建解决方案,这将生成我们需要的 dll 文件。现在我们可以打开 Unity,看看我们如何使用这个插件:

  1. 加载 Unity,让我们首先创建一个新的项目。项目类型将是 3D,我将给它命名为 Packtpub。我将首先创建两个文件夹;第一个将命名为 Plugins,另一个将命名为 PluginWrappers。这将使我们能够保持项目整洁:

图片

项目设置

  1. 我们将首先将我们创建的 C# dll 文件拖放到 Plugins 文件夹中。我将我的 dll 文件命名为 CSharpManagedPlugin,以便在最后区分我们拥有的不同插件:

图片

插件已添加

  1. 如果你点击 CSharpManagedPlugin,在检查器中,你会看到更多信息:

图片

检查器

  1. 只要目标 .NET 版本与 Unity 的相同或更低,你就不会收到错误,并且应该能够在编辑器、独立应用、WebGL、Linux、Windows 和 Mac OS 中使用它。

  2. 我们现在可以转到我们的 PluginWrappers 文件夹,并让这个家伙运行起来。

  3. 创建一个新的脚本;我的脚本将命名为 CSharpWrapper。现在我们可以用 Visual Studio 打开这个脚本:

图片

脚本

  1. 管理插件是最简单的,我们只需要直接调用我们的插件,就像它是一个非 Monobehavior 脚本一样。你的代码应该如下所示:
using UnityEngine;
public class CSharpWrapper : MonoBehaviour
{
    private void Start()
    {
        var addition = new CSharpManagedPlugin.Addition();
        var add = addition.Addify(5, 2);
        print(add);
    }
 }

如你所见,我们像调用程序集中的另一个命名空间一样调用我们的插件。现在我们可以将这个 Unity 类附加到一个 GameObject 上,我们将在 Unity 编辑器的控制台中看到第 7 步的结果。

C++ 语言插件

接下来,我们将使用 Visual Studio 再次创建这个项目:

  1. 这个项目类型将在 Visual C++ | Windows Desktop | 动态链接库 (DLL):

图片

  1. 这个项目的名称将是NativeWindowsPlugin,由于名称修饰,C++将与托管插件略有不同,我们将在下一部分学习如何避免这种情况。

  2. 因此,为了解决名称修饰的问题,我们需要创建一个头文件和 cpp 文件。看看这段代码:

The header will have the extern c and a preprocessor win32 define along with __declspec, dllexport functions to make sure that name mangling does not occur. Again, we will define our public function of addify, which will be our addition function. Your header should look like this.

 #pragma once
extern "C" {
#if (defined(WIN32) || defined(__WIN32__))
       __declspec(dllexport) int addify(int a, int b);
#else
       int addify(int a, int b);
#endif
}
  1. 实际上,当我们使用__declspec, dllexport调用时,我们是在避免使用.def文件。

  2. 现在我们已经创建了头文件,我们需要填写 cpp 文件中的信息。

  3. 确保包含本地 Windows 插件的头文件,并填写addify函数的详细信息。你的代码应该如下所示:

#include "stdafx.h"
#include "NativeWindowsPlugin.h"
int addify(int a, int b)
{
       return a + b;
}
  1. 点击构建解决方案,我们将准备好跳入 Unity。

加载 Unity,然后打开我们的Packtpub项目:

  1. 就像我们之前做的那样,我们将使用我们的PluginsPluginWrappers文件夹来保持事物有序。将CPlusPlusPlugin复制到Plugins文件夹中:

图片

文件夹结构

如果你查看检查器中的插件,你会注意到它仅适用于 Windows。这是因为我们只设置了 if 指令针对 Windows,没有其他操作系统。当你想用 C++在多个操作系统上工作时应记住这一点。

  1. 现在,我们可以在PluginWrappers文件夹中创建一个新的 C#类,名为CPlusPlusWrapper

图片

CPlusPlusWrapper

  1. 这里的代码将与我们用于本地插件的代码不同。我们需要使用一个称为DllImport的非常特殊的属性来导入 dll 文件。这个属性需要我们使用的插件的字符串名称,然后在属性下面,我们需要确保它是一个公共静态外部方法

  2. 公共静态外部方法类型指定了我们想要使用的方法调用将是静态的、公共的,并且从外部程序集加载。要使用 DLL 导入属性,我们需要使用 System.Runtime.InteropServices 命名空间。你的代码应该如下所示:

using System.Runtime.InteropServices;
using UnityEngine;
public class CPlusPlusWrapper : MonoBehaviour {
    [DllImport("CPlusPlusUnManagedPlugin")]
    public static extern int Addify(int a, int b);
    private void Start()
    {
        var add = Addify(2, 4);
        print(add);
}
 }

在完成这些之后,后续的调用基本上是相同的。它有点不同,也稍微复杂一些,但一旦你理解了它是如何工作的,总体来说是非常简单的。你现在可以将这个 C#脚本附加到一个 GameObject 上并运行它来测试结果。

Swift 语言插件

Swift 语言插件的扩展名为.swift,与 C#、Java 和 C++的结构完全不同,这是可以预料的,因为 Swift 仅在 macOS 设备上可用。这种语言本身融合了多种来源的元素,虽然我不会深入探讨语言的细微之处,但我可以说我喜欢他们融入语言结构中的方法。

Swift 和 Objective-C 需要使用 Xcode,尽管基本设置非常相似,但也有一些关键区别。Swift 插件要求你同时使用 Objective-C 和 Swift 来创建一个插件,该插件最终归结为 Swift 的实现,并在 Objective-C 中调用这些 Swift 代码。这超出了本节的内容,因为两种语言的细微差别需要进一步探索。

Objective-C 语言插件

Objective-C 插件在某些方面与 Swift 插件相似,许多基本步骤都是相同的。Objective-C 已经存在很长时间了,它是苹果的 C 语言家族版本。虽然 Swift 被设计成 Objective-C 的继任者,但苹果并没有废弃这种语言,它仍然是一个强大且值得使用和了解的工具:

  1. 首先,打开 Xcode,准备享受乐趣:

图片

  1. 点击“创建一个新的 Xcode 项目”,我们将有一个长长的项目列表可供选择。

  2. 转到 macOS 并选择库。

虽然库在 iOS 项目中不可用,但你也可以选择使用 Bundle 或 Cocoa 框架库类型。

  1. 选择库并点击下一步:

图片

  1. 将产品名称设置为 ObjectiveCPlugin;这使我们保持与迄今为止项目开发的方式一致:

图片

  1. 现在,在我们继续之前,让我们看看下拉菜单中可用的各种框架:

图片

我们有 Cocoa、STL 和 None。Cocoa 为我们提供了 Objective C 和 Swift 所需的一切,STL 是 C++ 的 标准模板库,而 None 是一个不带标准库的空白 C++ 和 C 项目。我们将坚持使用 Cocoa。

接下来,我们应该看看类型选项中有什么可用:

图片

类型提供了动态和静态的选择,这将是一个 动态库静态库。静态库是一个在编译时解析并复制到目标应用程序中的库,该应用程序生成一个目标文件和一个可执行文件。动态库则相反。它在运行时解析,只生成可以在其他应用程序或程序中调用的头文件和源文件。我们将坚持使用动态库。

图片

  1. 我们的库基础文件已经为我们创建了一个 .h.m 文件,所以我们只需填写所需的代码。让我们先填写头文件。看看这段代码:
#import <Foundation/Foundation.h>
@interface ObjectiveCPlugin : NSObject
int Addition(int a, int b);
@end
  1. 立刻,我们可以看到它与 C++ 非常相似,只是语法略有不同。接下来,让我们看看 .m 文件:
#import "ObjectiveCPlugin.h"
@implementation ObjectiveCPlugin
int Addition(int a, int b)
{
 return a + b;
}
@end
  1. 再次强调,它与 C++ 几乎相同,我们只需填写方法实际执行的内容。现在我们可以构建项目,并准备好将其导入到 Unity 中:

图片

  1. 现在,在项目构建完成后,我们可以打开 Unity 并准备好进入有趣的部分。在之前创建的Plugins文件夹中,创建一个名为iOS的新文件夹:

图片

  1. iOS文件夹中,复制创建的.h.m文件:

图片

  1. 现在,转到PluginWrappers文件夹并创建一个名为ObjectiveCWrapper的新脚本:

图片

  1. 现在,我们可以在 C#中打开类并添加我们的代码:
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;
public class ObjectiveCWrapper : MonoBehaviour
{
 private Text text;
#if UNITY_IOS && !UNITYEDITOR

 [DllImport("__Internal")]
 public static extern int Addition(int a, int b);
#else 
 [DllImport("ObjectiveCPlugin")]
 public static extern int Addition(int a, int b);
 #endif
private void Start()
 {
 text = GetComponent<Text>();
 text.text = Addition(1,5).ToString();
 }
}

Objective-C 的好处是它没有 C++那样的名称混淆问题,所以我们不需要担心在之前做extern方法。相反,由于 iOS 设备编译代码的方式,我们必须调用__internal,而不是插件的名称。

最后,我们需要为 iOS 构建这个项目并在 Xcode 中打开它来完成编译过程,然后在 iPhone 或 iPhone 模拟器上运行以测试结果。

Java 语言插件

对于 Java 语言插件,我们有两种选择都可以正常工作。我们有 Java 库,它编译成 JAR 文件,还有 Android 库,它编译成 AAR 格式。要访问 Android 特定的功能,我们需要创建 Android 库,而对于纯 Java 语言的使用,我们会创建 Java 库。

两者之间有一个主要区别,这一点应该被讨论。考虑以下内容:

  • Android 库项目包含本地和 Java 代码以及资源文件和 AndroidManifest。它们将包括需要预编译到 Android Studio 项目中的.class文件和.jar文件,然后导入到 Unity 中。

  • Java 库项目直接构建为 JAR 文件,并且可以导入到 Unity 中。

这两个插件都需要在 Android 设备上运行;这意味着你无法在编辑器中测试它们;你必须构建并在模拟器或实际设备上运行。如果你想从插件中获得最佳效果,使用 Java 语言。Android 库项目提供了最大的性价比。

话虽如此,让我们打开 Android Studio 并创建我们的基本库:

  1. 点击文件,高亮显示新建,并定位到新建模块。模块选项窗口将在新窗口中打开:

图片

Android Studio

  1. 在这里,我们有选择 Java 库或 Android 库的选项。正如之前讨论的那样,使用 Android 库更有优势,所以选择它并点击下一步:

图片

库选择

  1. 现在,我们可以命名和配置我们的模块。我将设置库名为AndroidLibrary;模块名将自动设置为库的小写名称。

  2. 包名将更改为com.packtpub.Androidlibrary,最小 SDK 版本为API 21: Android 5.0 (Lollipop)

图片

模块设置

  1. 一旦设置好,点击“完成”。

  2. 在 Android Studio 编辑器的左侧,我们可以看到项目的布局:

图片

布局

  1. 我们想要关注的主要区域是名为com.packtpub.Androidlibraryjava文件夹。我们需要右键单击这个特定的文件夹,并向其中添加一个新的 Java 类。这将打开一个全新的窗口来设置类:

图片

新类

  1. 我将把类命名为Additions以指定我们只是创建一个简单的数学库,然后选择“确定”按钮。

  2. 对于 C#,过程是相同的:我们只需添加一个名为AddMe的公共int,参数为int aint b,返回值为a + b。你的代码应该如下所示:

package com.packtpub.Androidlibrary;
public class Additions {
    public int AddMe(int a, int b)
    {
        return a + b;
    }
}
  1. 点击编辑器窗口顶部的“构建”按钮,然后点击“构建项目”。这将为我们构建项目。

  2. 让我们快速查看一下项目的输出文件夹:

图片

构建项目文件夹

我们可以看到这里有很多文件夹和其他杂项文件。我们需要的 AAR 文件位于AndroidLibrary文件夹中。确切的位置是 Android library,Build,Outputs,AAR。

AAR 文件在技术上是一个 zip 文件,因此你可以使用“7zip”解压并查看其内容;然而,这正是我们在 Unity 中需要使用的文件。现在,是时候打开 Unity,看看我们如何让 Unity 与这个文件交互了。

启动 Unity,并打开我们的Packtpub项目:

  1. 就像我们之前做的那样,我们将使用我们的PluginsPluginWrappers文件夹来保持组织有序。将 AAR 文件复制到Plugins文件夹:

图片

插件文件夹

  1. PluginWrappers文件夹中,创建一个名为JavaWrapper的 C#类,然后在 Visual Studio 中打开它。

  2. 代码与 C#和其他本地实现略有不同。我们需要一个预处理指令来检查此代码是否在 Android 上执行。

  3. 然后,我们将创建一个新的 Android Java 对象,其字符串名称为我们创建的 Java 类中的字符串名称。

  4. 我们将调用该类,使用我们想要的方法的字符串值,然后是参数。你的代码应该如下所示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JavaWrapper : MonoBehaviour
{
       // Use this for initialization
       void Start () {
#if UNITY_Android && !UNITY_EDITOR
        var javaClass = new AndroidJavaObject("Addition");
        javaClass.Call("Addification", 2, 9);
#endif
}
 }

现在,我们无法在 Unity 编辑器中测试这段代码,但我们可以构建项目并在连接到游戏对象后,在 Android 设备上测试它。

在 Java 中创建传感器驱动程序

现在,如果我们想从提供的硬件中实现自己的传感器呢?实际上,谷歌已经想到了这一点,并有一个非常深入的教程,关于创建和注册自己的驱动程序,可以在developer.Android.com/things/sdk/drivers/location查看。我将简要介绍其中的一些项目,但最好阅读他们所写的内容。

简而言之,我们只需查看提供的示例代码,这样我们就可以将其作为插件转换 GPS 数据。其基本结构与我们在 Java 中创建基本插件时使用的结构完全相同。下一步将是编写我们的代码,以便它返回数据,这样它就可以从本地插件传递到 Unity。看看这个:

// Convert latitude from DMS to decimal format
private float parseLatitude(String latString, String hemisphere) {
 float lat = Float.parseFloat(latString.substring(2))/60.0f;
 lat += Float.parseFloat(latString.substring(0, 2));
 if (hemisphere.contains("S")) {
 lat *= -1;
 }
 return lat;
}
// Convert longitude from DMS to decimal format
private float parseLongitude(String longString, String hemisphere) {
 float lat = Float.parseFloat(longString.substring(3))/60.0f;
 lat += Float.parseFloat(longString.substring(0, 3));
 if (hemisphere.contains("W")) {
 lat *= -1;
 }
 return lat;
}
// Return a location from an NMEA GPRMC string
public Location parseLocationFromString(String rawData) {
 // Tokenize the string input
 String[] nmea = rawData.split(",");
Location result = new Location(LocationManager.GPS_PROVIDER);
 // Create timestamp from the date + time tokens
 SimpleDateFormat format = new SimpleDateFormat("ddMMyyhhmmss.ss");
 format.setTimeZone(TimeZone.getTimeZone("UTC"));
 try {
 Date date = format.parse(nmea[9] + nmea[1]);
 result.setTime(date.getTime());
 } catch (ParseException e) {
 return null;
 }
// Parse the fix information tokens
 result.setLatitude(parseLatitude(nmea[3], nmea[4]));
 result.setLongitude(parseLongitude(nmea[5], nmea[6]));
 result.setSpeed(Float.parseFloat(nmea[7]));
return result;
}

现在,你需要做的就是按照上一节中指定的方式编译插件,并将其以完全相同的方式添加到 Unity 中。

摘要

在本章中,我们讨论了通常可以从移动市场设备中获得的各种传感器。我们讨论了如何为不同平台创建基本插件的主要语言,我们现在拥有开始使用 Unity 制作 AR 应用程序和游戏所需的所有基本知识。

在下一章中,我们将把我们学到的东西应用到创建一个原型项目中,这个项目将使我们能够将声音作为 AR 应用程序的基础。

尝试一下,英雄

在继续下一章之前,我建议花时间阅读我在进一步阅读部分提供的参考资料,这些资料将为你提供有关如何访问 Android 和 Apple 设备上各种传感器的见解。

这将极大地帮助你解决以下提出的编码挑战:

  • 创建一个简单的 C++ 插件,该插件与 Linux、Windows 和 Mac 桌面环境兼容

  • 创建一个 Java 插件,允许设备主动读取 10 秒钟的温度并在你的设备屏幕上显示

  • 创建一个 C# 插件,可以访问你的笔记本电脑上的网络摄像头,并将这些信息发送到 Unity 编辑器

以下挑战是为那些能够访问 Mac 计算机的人准备的(如果你没有,你可以修改这些以适用于 Windows 或 Android):

  • 创建一个 Swift 插件,该插件将读取屏幕上的手指按压,并通过文本或通过屏幕上的显示颜色记录手指按压的确切位置

  • 创建一个 Objective-C 插件,该插件从摄像头传感器获取信息,并以二进制格式将其记录在文本文件中

问题

  1. Unity 能够使用从 C++ 插件:

A.) 正确

B.) 错误

  1. 你为自己的传感器实现创建自己的实现,并通过插件注入到 Unity 中:

A.) 正确

B.) 错误

  1. 你可以使用 ARKit 创建一个 Objective-C 插件用于 Unity:

A.) 正确

B.) 错误

  1. 你可以构建针对 iOS 设备的 Java 插件,用于与 Unity 一起使用:

A.) 正确

B.) 错误

  1. Swift 插件比 Objective-C 插件更容易为 Unity 开发:

A.) 正确

B.) 错误

  1. 指纹传感器仅在 Android 设备上可用:

A.) 正确

B.) 错误

  1. 摄像头在技术上是一个传感器:

A.) 正确

B.) 错误

  1. 在 iOS 和 Android 设备上始终使用陀螺仪:

A.) 正确

B.) 错误

  1. 使用温度传感器来跟踪和测量敏感组件的温度:

A.) 正确

B.) 错误

  1. 加速度计不是一种用于检测设备动量的传感器:

A.) 正确

B.) 错误

进一步阅读

官方文档始终是了解更多关于传感器的最佳地点。查看以下链接获取更多信息:

第四章:花草丛中的声音

在本章中,我们将设计和创建我们的第一个 AR 应用程序,使用 macOS 和利用 ARKit。这将是一个利用触摸传感器和摄像头传感器协同工作,从各种文学来源中启动声音片段的应用程序。这将作为编程和设置 Unity 以使用我们可用的 AR 工具的绝佳介绍。这将使我们能够利用内置的用于使用摄像头传感器和触摸传感器的功能。

在本章中,我们将涵盖以下主题:

  • 项目构思

  • 设置 Unity 项目

  • 代码实现细节

  • 使用 XCode

项目概述

这个应用程序的概念是能够在摄像头的视频流中的任何地方进行选择,并且它将根据该区域的照明读取一首诗或书籍的随机段落。构建时间大约为 30 分钟。

入门

以下为软件先决条件:

  • XCode

  • Unity 2018 for Mac

  • ARKit

  • Visual Studio for Mac

  • MonoFramework

软件可以从以下网站下载:

以下是最小硬件要求:

  • 2011 年或更新的 Mac 电脑

  • 8 GB 的 RAM

项目构思

在构建任何游戏或应用程序之前,了解你确切想要构建的内容始终是第一步。你不需要知道确切的实现细节,只需知道你想要构建的内容以及你打算如何构建它。这应该包括以下内容:

  • 基本想法/概念

  • 要使用的编程语言

  • 平台发布选择

  • 要使用的游戏引擎或库/框架

  • 设计文档/设计大纲

  • 用于证明概念的书面或代码实现原型

现在,为什么这些点如此重要?它们之所以重要,是因为它有助于巩固想法,为你想要实现的内容提供清晰的路径,最重要的是,证明项目是可构建的。让我们深入每个点,并使用它们来构建我们的第一个 AR 应用程序。

基本想法/概念

应用程序或游戏的基本想法或概念不应超过一个段落,解释你想要创建的内容。它不是用来解释完整的功能或你希望在应用程序或游戏中包含的所有内容。相反,它只作为一个基本的起点,表明这是你想要工作的整体想法。

这很重要,因为它是应用程序或游戏想法的核心,你可以定义应用程序或游戏的主要功能,并为研究提供一个清晰的参考点。

我们的基本概念是能够在摄像头的视频流中的任何位置进行选择,然后根据该区域的光线读取一首诗或书籍的随机段落。现在,这并没有深入探讨应用程序将做什么,但我们可以以此为基础,在第四步中扩展基本想法,创建一个功能齐全且详细的解释。

选择合适的编程语言

在开发应用程序或游戏时,这个选择并不总是那么明显。虽然您自己的知识在选择要使用的语言时起着重要作用,但应用程序或游戏的需求以及您团队的知识也同样重要。在最终确定决策之前,这一步应该与下一步同时进行,因为您的研究可能会确定您偏好的语言可能没有为开发您想要的特定游戏或应用程序提供适当的库或功能。

幸运的是,我们的示例将使用 C#。

选择您的发布平台

这一点相当直接。您是想在 Android、iOS、Windows 还是其他平台上发布?这将决定您需要选择哪种语言以及我们需要哪种游戏引擎或库/框架——这引出了下一个部分。

选择您的游戏引擎、库和框架

如前所述,这一步应该与前面的步骤同时进行,因为它们本质上是相互关联的。这一步要求您对基本想法/概念进行深入和高度详细的研究。您不仅要查看您想要做的事情是否可行,还要了解您想要使用的语言、游戏引擎或库/框架是否支持它。这也要求您知道您想要在哪个平台上发布。

根据这个应用程序的基本想法,我们知道它将需要利用摄像头并处理触摸事件来检测某个区域是否光线充足,从而确定是否播放音频文件。

开发游戏设计和应用程序设计文档

设计文档更像是一个设计规范文档,它描述了整个应用程序。这意味着所有数据级、架构级、界面级和组件级的设计都为其进行了描述。以下示例展示了文档的样式。您可以从ec.europa.eu/idabc/servlets/Doc7e17.doc?id=18632下载模板的副本:

图片

技术设计模板

对于游戏设计,设计文档可能比应用程序更复杂。典型的游戏设计文档将需要尽可能详细地填写所描述的章节。您可以从 docs.google.com/document/d/1-I08qX76DgSFyN1ByIGtPuqXh7bVKraHcNIA25tpAzE/edit 下载模板的副本:

图片

游戏设计模板

现在,您可能认为这对于应用程序或游戏来说工作量很大。成功的关键永远不会来自懒惰或纯粹的运气。在创建如此深入的文档时,您确保自己确切地知道需要做什么以及为什么需要这样做,如果您招募团队成员,他们可以阅读文档并充分理解您的目标和意图,而无需您提供太多输入。

这也意味着您可以确保自己始终与项目保持一致,迫使您不要添加任何小宠物功能,除非在项目达到完成标志后作为额外的里程碑。

奖励 – UML 设计

统一建模语言UML)是可视化您应用程序或游戏设计的一种绝佳方式。NClass 是一个免费的 UML 编辑器,您可以下载并使用它。

您可以使用 UML 预先规划所有的方法、属性、属性、类和枚举——几乎与编程相关的所有内容。UML 真正有助于下一阶段,即实际实现原型:

图片

实现的进一步规划可以在以下屏幕截图中看到:

图片

原型设计

现在,我们的概念验证实际上将是完整的项目,尽管对于您未来的项目,运行小规模实现以确保 100%必要的功能能够得到实现并适当工作。

这也意味着,如果由于任何原因您无法实现应用程序或游戏的主要功能,您在项目上浪费的时间和金钱将不会像在大规模实现上那样多。

设置 Unity 项目

我们将要做的第一件事是在我们的 Mac 计算机上设置 Unity,以便能够创建我们的项目。由于我们知道我们需要 ARKit,它只能在 macOS 上运行,我们将为不同的章节有不同的项目,因为我们不希望有任何编译问题:

  1. 让我们创建一个新的项目,我们将称之为 Chapter4Sound of Flowery Prose

图片

  1. 接下来,我们需要点击商店并搜索 ARKit 以下载并将其添加到我们的项目中:

图片

  1. 我对组织有点挑剔,所以我们必须确保设置好所有必要的空游戏对象以保持事物有序。因此,我们将有四个空游戏对象,分别命名为CameraParentARKitControlARCameraManagerHitCubeParent。你的项目应该看起来像下面截图中的那样:

  1. 将相机拖入CameraParent空游戏对象中:

  1. 创建一个Cube并将Cube拖入HitCubeParent对象中:

现在我们已经基本按照要求设置了 Unity,我们可以继续创建和附加项目所需的脚本:

  1. 点击相机组件——我们需要向其中添加两个脚本。第一个脚本是 Unity AR Camera Near-Far,第二个是 Unity AR Video。

  2. Unity AR Video 也需要一个清晰的材质,所以让我们将其设置为YUVMaterial

  1. ARCameraManager需要附加适当的脚本——在这种情况下,它被称为 Unity AR Camera Manager:

  1. ARKitControl也需要附加一个脚本,该脚本称为 Unity AR Kit Control:

  1. 我们需要做的最后一件事是在HitCubeParent对象内部设置我们的Cube,并为它创建一个新的脚本。

  2. 点击Cube对象,选择添加组件 | 脚本 | 新脚本。名称应该是ARHitCube

代码实现细节

显然,任何项目的最重要部分实际上是实现我们想要完成的事情。我们希望这个项目能够自动播放从音频样本列表中的文学引文。为此,我们需要一个音频源和音频剪辑。我们还希望这个项目利用 ARKit 来运行,因此我们需要编写一个 C#类,该类利用从 Objective-C 和 C++库中公开的 ARKit 插件的功能。

让我们打开ARHitCube类,填写详细信息,并同时在解释正在发生的事情。我应该注意的是,非常相似的代码已经提供在名为UnityARHitTestExample的脚本文件中;我创建了这个脚本,以便能够只显示所需的内容,并能够解释创建所需功能所需的工作流程/思想:

using System;
using System.Collections.Generic;
  1. 如同往常,我们只会调用我们项目所需的特定命名空间。在这种情况下,是SystemSystem.Collections.Generic
namespace UnityEngine.XR.iOS
  1. 我们将使用命名空间来组织我们的代码,以确保它与 ARKit 和 Unity 的 API 保持分离,这将避免命名冲突:
public class UnityARHitTestExample : MonoBehaviour
{
            public Transform m_HitTransform;
            public AudioClip[] clips;
            public AudioSource source;
  1. 我们的这个类将继承自MonoBehavior,因为我们希望能够直接从对象中使用它(以及确保它可以附加到游戏对象上)。

  2. 我们创建了一个公共变换以使我们能够更容易地跟踪位置,以及一个公共音频剪辑数组:

bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
    List hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
  1. 我们创建了一个具有ARPointARHitTestResultType参数的Boolean方法类型。这两个都是 ARKit 暴露的,你可以阅读它们的文档或查看 Unity 中的源代码以更好地理解它们。简而言之,ARPoint是从 Vector 3 值派生出的点坐标,而ARHitTestResultType是一个枚举,可能的返回值有ARHitTestResultTypeFeaturePointARHitTestResultTypeEstimatedHorizontalPlaneARHitTestResultTypeEstimatedVerticalPlaneARHitTestResultTypeExistingPlaneARHitTestResultTypeExistingPlaneUsingExtentARHitTestResultTypeExistingPlaneUsingGeometry

  2. 我们创建了一个名为hitResults的列表,它将被设置为UnityARSessionNativeInterface.GetARSessionNativeInterface().HitTest,参数为点和结果类型填充。这样做是每次注册原生接口碰撞测试时创建一个列表,并存储值:

if (hitResults.Count > 0) {
    foreach (var hitResult in hitResults) {
        Debug.Log ("Got hit!");
        m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
        m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
        return true;
    }
}
return false;
}
  1. 接下来,我们进行一个if检查,以验证计数是否大于0。如果不是大于0,则返回false,否则进入foreach循环。在foreach循环内部,我们检查所有碰撞结果并记录结果。HitTransform的位置将始终设置为UnityARMatrixOps.GetPosition,参数为hitresult.worldTransform

  2. HitTransform的旋转也将始终设置为UnityARMatrixOps.GetRotation,参数为hitresult.worldtransform。我们最后返回true。本质上,这个函数所做的只是检测是否有碰撞被注册,并将信息传递到需要这些信息的正确区域:

void Update () {
/* Let’s start the update method as it is probably the second most important aspect of the code.
*/
 if (Input.touchCount > 0 && m_HitTransform != null)
 {
 var touch = Input.GetTouch(0);
  1. 我们首先要检查input.touchcount是否为0,以及HitTransform是否不等于null。如果这两个检查中的任何一个失败,我们就无法检索到所需的信息。

  2. 我们将触摸变量设置为input.gettouch,参数为00是基本点击手势:

if (touch.phase == TouchPhase.Began)
{
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
  1. 这里if触摸阶段语句是一个检查以查看初始化的是哪种触摸阶段。开始触摸阶段是我们想要的,因为它是触摸事件的起始位置。

  2. 我们创建了一个屏幕位置变量,并将其设置为相机屏幕到视口点,参数填充为触摸位置:

ARPoint point = new ARPoint 
{
    x = screenPosition.x,
    y = screenPosition.y
};
  1. ARPoint 点设置为一个新的 ARPoint,我们希望x值是屏幕位置的x值,而y值是屏幕位置的y值:
ARHitTestResultType[] resultTypes = {
    ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
    ARHitTestResultType.ARHitTestResultTypeHorizontalPlane,
    ARHitTestResultType.ARHitTestResultTypeFeaturePoint
};
  1. ARHitTestResultType是一个名为结果类型的数组。我们想确保理解碰撞测试结果类型,在这种情况下,我们有三种类型可以使用:ExistingPlaneUsingExtentHorizontalPlaneFeaturePoint
foreach (ARHitTestResultType resultType in resultTypes)
    if (HitTestWithResultType (point, resultType))
      {
          source.PlayOneShot(clips[Random.Range(0, clips.Length)]);
          source.Stop();
          return;
      }
  1. 我们现在可以对 ARHitTestResultType 执行最终的 foreach 循环,并创建一个 if 语句来检查带有参数的点 HitTestWithResultTyperesultType。这实际上只是检查是否发生了适当的触摸事件,如果发生了,则激活播放方法。在另一个触摸事件之后,它将停止正在播放的媒体。随后,我们返回并跳出循环。

  2. 我们可以回到 Unity 编辑器,查看附加在立方体对象上的脚本:

  1. 我们可以将 Cube 附加为击中变换,因为我们点击时,这将是我们读取信息的注册对象:

我们现在可以构建这个项目:

  1. 要这样做,请点击文件并选择构建设置。我们将使用 iOS 作为平台:

  1. 在玩家设置中,我们需要在捆绑标识符区域更改我们应用程序的名称,并在相机使用描述中写一个简短的描述。

  2. 我将命名这个应用为 com.rpstudios.arkitscene,描述将是 AR BABY

  1. 一旦我们选择构建应用程序,Unity 将创建一个 XCode 项目,这是为 Android、Windows 和 Linux 构建时的主要区别:

主要工作已经完成;现在我们只需要熟悉 XCode 并完成那里的构建过程。

使用 XCode 进行工作

我们可以导航到应用程序的 Build 文件夹,并点击它以打开我们的 XCode 项目:

  1. 在屏幕的左侧,你应该能看到 Unity-iPhone 是你可以选择的项目之一。点击它,你应该在中心看到 Unity-iPhone,在右侧看到身份和类型:

  1. 确保身份信息正确。对我来说,显示名称是 Chapter4,捆绑标识符为 com.rpstudios.arkitscene

  1. 现在,在签名部分,你需要确保自动管理签名的复选框被勾选,并且你的团队已经将你的电子邮件地址附加到它上。签名证书非常重要,因为如果没有它,你将无法正确编译或发送到模拟器。如果没有,你必须注册一个 Apple 开发者账户,请访问 developer.apple.com

  1. 滚动并查找链接框架和库。AVFoundation 应该从可选更改为必需。我注意到,当它设置为可选时,链接器无法正常工作:

  1. 定位到架构,因为我们需要从默认的架构更改为标准架构。这是由于存在不同的架构,iOS 已经不再使用 ARM 架构:

  1. 现在,你可以点击构建,并将你的 iPhone 6 或更高版本连接到你的 Mac 电脑。构建并在设备上运行它。它会要求你信任手机上的应用程序,所以按照指示进行信任设置。

  2. 点击你手机上的应用程序,然后就是!它会加载,你可以玩这个应用程序。

摘要

在本章中,我们学习了如何使用 ARKit 和 Unity 为 Mac 设备构建 AR 应用程序。虽然这是一个非常简单的实现,但它肯定为你将不同方面的声音融入自己的 AR 游戏和应用铺平了道路。

学习处理 AR 的基础可能是最困难的部分,同时弄清楚为什么为不同设备构建不按你最初期望的方式工作。调试和测试应该是开发每个方面的基本组成部分。我建议要么让某人测试每个构建,要么在有机会的时候进行自动化测试。

在下一章中,我们将创建一个面向儿童的具有教育风格的游戏原型,通过谜题的方式挑战他们的认知推理技能。

问题

  1. ARKit 与 Unity 标准捆绑:

A.) 正确

B.) 错误

  1. 你可以在 Windows 上为 macOS 和 iPhone 进行构建:

A.) 正确

B.) 错误

  1. 包标识符可以设置为app.unity.test

A.) 正确

B.) 错误

  1. ARPoint 是什么?它有什么作用?

  2. 设计文档对于大型项目不是必需的:

A.) 正确

B.) 错误

  1. UML 代表统一建模语言:

A.) 正确

B.) 错误

  1. ARKit 内置了 VR 支持:

A.) 正确

B.) 错误

  1. 你能否在 Windows 机器上将 ARKit 导入 Unity 项目?

A.) 是

B.) 否

  1. 如果你使用 Objective-C 插件与 Windows 配合使用会发生什么?

A.) 正确

B.) 错误

  1. 你能否在同一项目中同时使用 Vuforia 和 ARKit?

A.) 正确

B.) 错误

进一步阅读

为了更好地理解不同的设计文档模板,以下是一个你可以下载和查看模板和示例的地方列表:

UML 是一个在许多领域都有讨论的话题,关于它的资源非常丰富,比我所涉及的深度要深得多。原因在于,关于 UML 可以写一本书来公正地对待它:

Unity 也有一些非常出色的教程,你可以通过它们学习如何使用 Unity 来学习 ARKit:

这些参考资料应该能让你对我在轻描淡写中提到的主题有更深的理解。

第五章:图片拼图 - AR 体验

在本章中,我们将创建另一个基于 AR 的应用程序。这次,重点将是一个可以用于教育的谜题,用于教授语言或词汇识别。这样做的原因是,基于 AR 的应用程序和游戏也是非常有前景的灵感来源和目标受众。

本章将向您介绍以下内容:

  • 如何更新现有的 Unity 安装以添加 Vuforia 支持

  • Unity Hub

  • 如何为 Windows、Android 和 iOS 构建基于教育的 AR 应用程序

让我们直接深入这个项目的背景,以及为什么它与 AR 相关。

项目背景

就像任何其他项目一样,最好从想法开始。当我第一次想到这个项目时,我想展示 AR 应用程序和游戏也能反映教育。我教育过孩子们英语,深知学习新语言的挫败感。

游戏和应用开发也应该教会用户一些东西;它不一定是历史、数学、语言、科学或地理;它也可以是某些无害的东西,比如反应训练或手眼协调。作为开发者,我们在世界上有一个独特的位置,能够以有趣的方式融入学习,而不会让用户觉得这是他们“必须”做的事情。

这并不意味着我们必须深思熟虑,试图将其纳入我们的应用程序和游戏中;它可能,并且通常就是这样,只是自然而然发生的事情。然而,在这个项目中,我特别针对学习方面,以展示它如何轻松地融入 AR 项目。

项目概述

本项目基于这样一个想法:通过为孩子们创建一个真正简单的现实世界谜题,让他们去解决,然后他们可以用这个应用程序来检查,看看他们是否解决了这个谜题,以此来教授孩子们词汇联想和拼写。

本项目的构建时间最多为 15 分钟。

开始学习

这里是 Unity 版本 2018.1.5 的系统要求:

  • 发布日期:2018 年 6 月 15 日

  • 操作系统:Windows 7 SP1+、8、10

  • GPU:具有 DX9(着色器模型 3.0)或具有 9.3 功能级别的 DX11 的显卡。

查看以下内容:

unity3d.com/ www.turbosquid.com/FullPreview/Index.cfm/ID/967597

安装 Vuforia

我知道我们在第一章,“什么是 AR 以及如何设置”中讨论过这个问题,但为了以防那一章被快速浏览或者 Unity 已经更新,这里需要简要回顾一下。

要在 macOS 和 Windows 上安装 Vuforia,步骤相当简单;然而,我想向您展示获取 Vuforia 软件和 Unity 的不同方法。

Unity 还有一种可以安装的类型,称为 Unity Hub,您可以从 Unity 网站获取,而不是 2018 安装程序文件。Unity Hub 的作用是允许您在单个位置拥有多个 Unity 安装,这是一种设置您首选 Unity 编辑器的方法,将您的项目合并到单个启动器中,轻松更新您想要安装的组件,并且它还提供了对项目预设类型模板的访问。按照以下步骤操作:

  1. 导航到 Unity 网站并点击获取 Unity:

图片

  1. 您将看到一个选项,可以选择个人、高级或专业。如果您适合并需要个人版本,请点击尝试个人:

图片

  1. 这将带您到下载页面,在那里您需要勾选复选框以接受条款,并给您提供下载 Unity 应用程序本身或预览中的 Unity Hub 的选项。我们想要 Unity Hub:

图片

  1. 一旦您下载并安装了 Unity Hub,您就可以打开它,它将为您提供项目、学习或安装的选项。点击安装以查看可用的版本:

图片

  1. 我们想安装 Unity 的最新版本,即 2018.1.5f1:

图片

  1. 一旦您点击安装您想要的版本,点击您想要的组件,然后按完成安装 Unity 编辑器:

图片

现在,假设您在安装 Unity 时忘记选择在此步骤中安装 Vuforia——没问题;您可以跳过前面的点,从这里继续操作。

  1. 在 Unity 中打开一个项目;这可能是一个您不想要的虚拟项目,或者它可能是本章项目的起点。

  2. 点击文件菜单中打开的构建菜单:

图片

  1. 我们想从窗口中选择玩家设置:

图片

  1. 应该会打开一个窗口,其中包含通常的检查器面板。找到 XR 支持安装程序并点击 Vuforia 增强现实:

图片

  1. 这将打开您的浏览器并要求您下载一个文件。点击保存以下载文件:

图片

  1. 关闭 Unity 编辑器并安装此文件。这将添加 Vuforia 支持到您的 Unity 安装中,而无需重新安装整个编辑器。

现在完成这些后,我们可以在 Windows 中创建此项目。

macOS 和 Windows 设置之间的差异

在为各自平台构建之前,macOS 和 Windows 的基本设置之间几乎没有区别。我已经以完全相同的方式设置了项目,以便更容易地遵循流程。如果您同时拥有 macOS 和 Windows 计算机,那么当您进入 macOS 部分时,可以跳到构建部分。如果您只有 Windows,那么您只需遵循那里的说明。相反,如果您只有 macOS 设备,那么您将拥有完整的说明,并且可以跳过Windows 项目设置部分。

Windows 项目设置

如果你还记得,在第一章,什么是增强现实以及如何设置,我们创建了我们的 Vuforia 开发者账户。我们将需要它,因为我们将会使用 Vuforia 来创建这个项目。导航到 Vuforia 开发者门户并登录您的账户。现在按照以下步骤操作:

  1. 在 Vuforia 开发者门户中,点击开发,并确保子菜单已选择许可证管理器。我们需要创建一个新的开发许可证密钥,应用名称为Chapter5Picture Puzzle

图片

  1. 在创建新密钥后,您应该看到许可证管理器显示了我们所创建的VuforiaIntroChapter5密钥:

图片

  1. 点击Chapter5以访问您的许可证密钥。您应该将其复制并粘贴到记事本或 Notepad++中以备后用:

图片

  1. 点击目标管理器,因为我们将要为这个项目创建自己的图像目标:

图片

  1. 点击添加数据库以创建我们将要在项目中使用的全新数据库:

图片

  1. 您可以给数据库起任何名字;在我的情况下,我将称之为Words_Pictures,类型为设备,然后点击创建:

图片

  1. 应该带我们回到目标管理器页面,并展示我们的新Words_Pictures数据库:

图片

  1. 点击Words_Pictures以访问数据库,然后当您看到它时点击添加目标:

图片

  1. 现在,我们将能够向数据库添加一个新的目标。在这种情况下,我们想要一个单独的图像。

我强烈建议您创建并使用 JPG 格式,因为 PNG 格式需要一个 8 位灰度图像或 24 位 RGB。

  1. 宽度应设置为与您的图像相同的宽度。名称应反映图像的内容:

图片

  1. 打开 Microsoft Paint,我们可以开始创建我们将用于目标的文件:

图片

  1. 下一步是找到我们想要用于这张图片的确切大小,我认为最好的方法是知道我们将会使用什么图片。在我们的例子中,它将是 72 磅的字体大小,字体名为 Bastion,并显示单词TREE

图片

  1. 调整比例,使其接近单词的边缘:

图片

  1. 将文件保存为 JPG 格式,命名为Tree

图片

  1. 如果你查看画图工具菜单的底部,它会告诉你我们刚刚创建的文件的尺寸。在这种情况下是253x106,这是我们想要的大小。

  2. 导航回添加目标网页,并选择我们刚刚创建的Tree文件:

图片

  1. 将宽度设置为253,名称设置为Tree,然后点击添加:

图片

  1. 这将带你回到数据库,你应该看到名为TreeWord的条目,名称为Tree。类型应该是单张图片,并且应该有一个三星评级:

图片

  1. 评级系统旨在告诉你它是否是正确的尺寸,以便你的 AR 设备能够正确读取。我们目前有一个三星评级,这意味着它应该很好,但可以更好。我们能做什么来修复这个问题?我们可以放大图片。

  2. 让我们删除数据库中的图片。为此,点击Tree旁边的复选框,上面将出现一个非常小的删除按钮:

图片

  1. 让我们回到画图工具并调整图片大小。680x480应该很完美,尽管500x300也可以:

图片

  1. 上传新的目标,结果应该有五星评级:

图片

  1. 点击下载数据库(全部):

图片

  1. 这将打开一个新窗口,询问我们想要使用哪个开发平台。我们想要 Unity 编辑器。点击下载:

图片

它将下载一个 Unity 文件,我们需要将其导入到我们的 Unity 项目中——现在,我们可以在 Unity 中开始工作,而无需离开编辑器去做其他工作。打开 Unity,让我们开始构建我们的项目。

构建 Windows 项目

创建一个新的 Unity 项目,如果你还没有的话,一开始就命名为Chapter5。然后加载项目。现在按照以下步骤操作:

  1. 我们下载的Words_Pictures文件现在需要被定位并导入到项目中:

图片

  1. 在我们深入创建项目之前,让我们看看导入时创建的文件夹。

  2. 我们的主要Assets文件夹现在将有一个Editor文件夹、一个StreamingAssets文件夹和一个Scenes文件夹:

图片

  1. Editor文件夹内,将有一个名为Vuforia的文件夹:

图片

  1. Vuforia文件夹内将有一个名为ImageTargetTextures的文件夹:

图片

  1. ImageTargetTextures文件夹内,将有一个名为Word_Pictures的文件夹:

图片

  1. Word_Pictures文件夹将包含我们的树图像精灵:

图片

  1. 返回主Assets文件夹,让我们看一下,从StreamingAssets开始:

图片

  1. StreamingAssets文件夹内将有一个Vuforia文件夹:

图片

  1. Vuforia文件夹内将有两个文件:Words_Pictures.xmlWords_Pictures.dat文件:

图片

  1. 让我们深入查看 XML 文件,看看里面具体有什么。看看这段代码:
<?xml version="1.0" encoding="UTF-8"?>
<QCARConfig  xsi:noNamespaceSchemaLocation="qcar_config.xsd">
  <Tracking>
    <ImageTarget name="Tree" size="680.000000 480\. 000000" />
  </Tracking>
</QCARConfig>

XML 文件已经设置了默认的架构,主标签是QCarconfig

下一个标签,包含我们的图像,是ImageTarget。它有名称,我们设置为Tree,以及用浮点值表示的大小。

XML 文件非常简短且直接。这个文件专门用于存放 Vuforia 需要知道的数据,我们使用图像的大小,以及如果有多张图像时能够引用正确的文件。继续按照步骤操作:

  1. 前往 TurboSquid 网站下载我们将使用的免费Tree模型:

图片

  1. 你需要Tree_FBXTree_textures文件来完成下一部分:

图片

  1. 返回主Assets文件夹,创建一个名为Models的新文件夹:

图片

  1. 提取树模型和纹理。将模型和纹理复制粘贴到 Unity 内部的Models文件夹中:

图片

  1. 从层次面板中删除标准相机。

  2. 右键点击层次面板,导航到 Vuforia;点击添加 AR 相机:

图片

  1. 在层次面板中点击AR Camera。转到检查器面板,点击打开 Vuforia 配置:

图片

  1. Unity 会要求你导入和下载更多 Vuforia 项目,并接受 Vuforia 许可:

图片

  1. 将你的应用许可密钥复制粘贴到应用许可密钥部分:

图片

  1. 右键点击层次面板,创建一个名为ImageTarget的空游戏对象。

  2. 右键点击ImageTarget对象,高亮显示 Vuforia 并点击图像:

图片

  1. 点击图像对象,查看检查器面板。图像目标行为应设置为预定义类型;数据库应为 Words_Pictures,图像目标应为 Tree:

图片

现在,我们需要添加我们的模型。我假设您知道如何为模型设置材质,所以这里不会详细说明。

  1. 将模型拖放到场景中。将xyz位置设置为0,0,0,比例设置为xyz坐标的0.09。最后一步是将它设置为 ImageTarget 对象内图像的子对象:

图片

  1. 打印出Tree文本,并将纸张剪成四条条带。

  2. 通过点击“文件”|“构建设置”,为 PC、Mac 和 Linux Standalone 或 Android 构建项目,然后点击“构建”:

图片

现在,使用您的 Android 设备或 PC 摄像头,将条带按正确顺序拼接在一起,Tree 模型将出现在纸张上方。

macOS 项目设置

在 Mac 上设置项目的步骤几乎相同,主要区别在于我们将使用什么软件来创建文本文件,但无论如何,这里应该简要说明,因为预计 Mac 用户不会想阅读本章的 Windows 部分。我们将使用 Vuforia 来创建此项目。导航到 Vuforia 开发者门户并登录您的账户。现在按照以下步骤操作:

  1. 在 Vuforia 开发者门户中,点击“开发”,并确保子菜单已选择许可证管理器。我们需要为名为Chapter5的应用程序创建一个新的开发许可证密钥:

图片

  1. 在创建新密钥后,您应该会看到许可证管理器显示了创建的VuforiaIntroChapter5密钥:

图片

  1. 点击Chapter5以获取您的许可证密钥。您应该将其复制并粘贴到记事本或 Notepad++中以备后用:

图片

  1. 点击目标管理器,因为我们将为这个项目创建自己的图像目标:

图片

  1. 点击“添加数据库”以创建我们将要在项目中使用的全新数据库:

图片

  1. 您可以命名数据库为任何您想要的名称;在我的情况下,我将称之为Words_Pictures,类型为设备,然后点击创建:

图片

  1. 这应该会带我们回到目标管理器页面,并展示我们的新 Words_Pictures 数据库:

图片

  1. 点击Words_Pictures以访问数据库,然后当您看到它时点击“添加目标”:

图片

  1. 现在,我们能够向数据库添加一个新的目标。在这种情况下,我们想要一个单独的图像。

我强烈建议您创建并使用 JPG 格式,因为 PNG 格式需要一个 8 位灰度图像或 24 位 RGB 图像。

  1. 宽度应设置为与您的图片相同的宽度。名称应反映图片的内容:

图片

  1. 打开 Microsoft Paint,我们可以开始创建用于目标的文件:

图片

  1. 下一步是找到我们想要用于此图片的确切尺寸,我认为最好的方法是知道我们将要使用的图片。在我们的案例中,它将是 72 磅的字体大小,字体名为 Bastion,并显示单词Tree

图片

  1. 将比例调整得接近单词边缘:

图片

  1. 将文件保存为 JPG 格式,并命名为Tree

图片

  1. 如果您查看 Paint 菜单的底部,它会告诉您我们刚刚创建的文件尺寸。在这种情况下是253x106

  2. 返回到添加目标网页,并选择我们刚刚创建的Tree文件:

图片

  1. 设置宽度为253,名称为 Tree,然后点击添加:

图片

  1. 这将带您回到数据库,您应该看到单词Tree,名称为Tree,类型为单张图片,并且应该有一个三星级评分:

图片

评分系统旨在告诉您它是否具有正确的尺寸,以便您的 AR 设备正确读取。我们目前有一个三星级评分,这意味着它应该很好,但可以更好。我们能做什么来修复它?我们可以放大图片。让我们继续按照步骤操作:

  1. 让我们从数据库中删除这张图片。为此,点击Tree旁边的复选框,然后在其上方会出现一个非常小的删除按钮:

图片

  1. 让我们回到 Paint 并调整图片大小。680x480应该很完美:

图片

  1. 上传新的目标,结果应该有一个五星级评分:

图片

  1. 点击下载数据库(全部):

图片

  1. 这将打开一个新窗口,询问我们想要使用哪个开发平台。我们想要 Unity 编辑器。点击下载:

图片

它将下载一个 Unity 文件,我们需要将其导入到我们的 Unity 项目中——现在,我们可以在 Unity 中开始工作,而无需离开编辑器去做其他工作。打开 Unity,让我们开始构建我们的项目。

构建 macOS 项目

如果您还没有创建,请创建一个新的 Unity 项目,并首先将其命名为Chapter5。然后,加载项目。现在按照以下步骤操作:

  1. 我们下载的 Words_Pictures 文件现在需要定位并导入到项目中。

  2. 在我们深入创建项目之前,让我们看看导入时创建的文件夹。我们的主要 Assets 文件夹现在将有一个 Editor 文件夹,一个 StreamingAssets 文件夹,和一个 Scenes 文件夹:

图片

  1. Editor 文件夹内,将有一个名为 Vuforia 的文件夹:

图片

  1. Vuforia 文件夹内将有一个名为 ImageTargetTextures 的文件夹:

图片

  1. ImageTargetTextures 文件夹内,将有一个名为 Word_Pictures 的文件夹:

图片

  1. Word_Pictures 文件夹内,我们将有我们的树图像精灵:

图片

  1. 返回主 Assets 文件夹,让我们看看,从 StreamingAssets 开始:

图片

  1. StreamingAssets 文件夹内将有一个 Vuforia 文件夹:

图片

  1. Vuforia 文件夹内将有两个文件:Words_Pictures.xmlWords_Pictures.dat

图片

  1. 让我们深入查看 XML 文件,看看里面具体有什么内容:
<?xml version="1.0" encoding="UTF-8"?>
<QCARConfig  xsi:noNamespaceSchemaLocation="qcar_config.xsd">
  <Tracking>
    <ImageTarget name="Tree" size="680.000000 480\. 000000" />
  </Tracking>
</QCARConfig>

XML 文件已经设置了默认的架构,主标签是 QCarconfig

下一个标签,包含我们的图像,是 ImageTarget。它有名称,我们设置为 Tree,以及用浮点值表示的大小。

XML 文件非常简短且直接。此文件专门用于存放 Vuforia 需要知道的数据,我们使用的图像大小,以及如果我们要使用多个图像时能够引用正确的文件。让我们继续下一步:

  1. 前往 TurboSquid 网站,下载我们将使用的免费 Tree 模型:

图片

  1. 你将需要 Tree_FBXTree_textures 文件来完成下一部分:

图片

  1. 返回主 Assets 文件夹,创建一个名为 Models 的新文件夹:

图片

  1. 提取树模型和纹理。将模型和纹理复制粘贴到 Unity 中的 Models 文件夹内:

图片

  1. 从层次结构面板中删除标准相机。

  2. 在层次结构面板中右键点击,导航到 Vuforia;点击添加 AR Camera:

图片

  1. 在层次结构面板中点击 AR Camera。切换到检查器面板,并点击打开 Vuforia 配置:

图片

  1. Unity 应该会要求你导入和下载更多 Vuforia 项目,并接受 Vuforia 许可协议:

图片

  1. 将你的应用程序许可证密钥复制并粘贴到应用程序许可证密钥部分:

  1. 在层次结构面板上右键单击,创建一个名为 ImageTarget 的空游戏对象。

  2. ImageTarget 对象上右键单击,高亮显示 Vuforia,然后点击 Image:

  1. 点击 Image 对象,查看检查器面板。Image Target Behavior 的类型应该是 Predefined。数据库应该是 Words_Pictures,Image Target 应该是 Tree:

现在我们需要添加我们的模型。我假设你知道如何为模型设置材质,所以这里不会详细说明。让我们继续下一步:

  1. 将模型拖放到场景中。将 xyz 位置设置为 0,0,0,并将比例设置为 xyz 坐标的 0.09。最后一步是将它设置为 ImageTarget 对象内图像的子对象:

  1. 打印出 Tree 文本,并将纸张剪成四条带。

  2. 通过点击 File | Build Settings 来为 iOS 构建项目。确保选中 Development Build 复选框:

使用 Xcode

我们可以导航到应用程序的 Build 文件夹,并点击它以打开我们的 XCode 项目。按照以下步骤操作:

  1. 在屏幕的左侧,你应该看到 Unity-iPhone 是你可以选择的项目之一。点击它,你应该在中心看到 Unity-iPhone,在右侧看到 Identity 和 Type:

  1. 确认 Identity 是否正确。我的显示名称是 Chapter5,包标识符为 com.rpstudios.Packtbook

  1. 现在,在签名设置中,你需要确保自动管理签名的复选框被勾选,并且 Team 中附有你的电子邮件地址:

  1. 滚动并查找 Linked Frameworks and Libraries。AVFoundation 应该从 Optional 设置为 Required。我注意到,当它设置为 Optional 时,链接器无法正常工作:

  1. 定位到 Architectures,因为我们需要从默认的设置更改为 Standard。这是由于存在不同的架构,iOS 不再使用 ARM:

  1. 现在你可以点击 Build,并将你的 iPhone 6 或更高版本连接到你的 macOS 计算机。构建并在设备上运行它。它将要求你在手机上信任该应用程序,所以按照指示进行信任设置。

  2. 点击手机上的应用程序,——哇!——它将加载,你可以玩这个应用程序。

现在利用你的 iOS 设备,将条带按正确的顺序放在一起,Tree 模型将出现在纸张的上方。

摘要

在本章中,我们学习了如何为儿童创建教育游戏,使他们能够了解与他们相关的单词所指的对象。我们学习了如何使用 Vuforia 进行开发,适用于 macOS 和 Windows,以及 Android 和 iOS 设备。我们还了解到,在 Windows 和 macOS 设备上构建的基本构建块在代码上相当相似,唯一的重大区别是编译到 iOS 或 macOS 所需的额外步骤,使用 XCode。

在下一章中,我们将构建一个健身应用的原型,该应用允许用户随机选择他们想要散步的位置,以增添乐趣。

问题

  1. 要为 Unity 安装 Vuforia,您必须访问 Vuforia 网站下载 SDK:

A.) 正确

B.) 错误

  1. 您需要为 Unity 2017 版本安装旧版插件:

A.) 正确

B.) 错误

  1. Unity Hub 使得安装多个 Unity 版本变得容易:

A.) 正确

B.) 错误

  1. Microsoft Paint 可以创建 Vuforia 图像目标所需的 PNG 和 JPG 文件:

A.) 正确

B.) 错误

  1. Vuforia 图像目标可以接受 TIFF 文件格式:

A.) 正确

B.) 错误

  1. Vuforia 对 PNG 和 JPG 文件的文件大小限制为 5MB:

A.) 正确

B.) 错误

  1. Vuforia 在 macOS 上不可用:

A.) 正确

B.) 错误

  1. Unity Hub 在 macOS 和 Windows 上可用:

A.) 正确

B.) 错误

  1. Vuforia 数据库中的星级评分系统是用来衡量图像质量的:

A.) 正确

B.) 错误

  1. 使用 Unity 时,您不需要 Vuforia 许可证密钥:

A.) 正确

B.) 错误

第六章:娱乐健身 - 旅游和随意漫步

在本章中,我们将利用 Mapbox 创建一个 AR 健身应用程序原型。这样做的原因是,主要关注利用 GPS、地理位置和 Android/Apple 设备硬件与卫星通信并接收数据。Mapbox 是一个 SDK,旨在利用 Unity 中 Android 和 Apple 设备的地理位置功能。我们将与 Unity 一起使用的软件,以使这一切更加无缝,就是 Mapbox。Mapbox 处理了许多最困难的工作部分,因此我们只需专注于我们的游戏和应用,这些游戏和应用利用了该软件。我们将学习如何使用 Mapbox 与 Unity 一起创建一个促进在您居住区域周围散步的健身应用程序。基本上,用户将点击一个随机位置,它将目的地设置为该位置。然后用户必须走到那个位置,这将触发该标记的破坏。

在本章中,我们将涵盖以下主题:

  • 了解 Mapbox

  • 将 Mapbox 集成到 Unity 中

  • 将 Mapbox 数据集成到 AR 应用程序中

Mapbox 的背景信息

Mapbox 允许您创建基于位置的城市模拟器、桌面 AR 和世界级 AR 应用程序和游戏。对于任何可能需要地理位置的项目,Mapbox 是您应该使用的软件。Mapbox 从头开始构建,以与 Unity、Android 和 iOS 兼容。

Mapbox 对 Web 和移动 SDK 免费,每月最多可提供 50,000 次地图查看、地理编码请求、方向请求和矩阵元素。达到 50,000 的限制后,对于移动 SDK 和 Web 应用程序,每月每 1,000 次 Web 地图查看、地理编码请求、方向请求和矩阵元素收费 0.5 美分。免费版本还包括 5GB 的卫星和街道地图数据集存储、Mapbox Studio 的无限制样式,以及创建公共和免费 Web/移动应用程序的权限。

现在,应该注意的是,当你拥有付费的免费或订阅制网站、具有受限访问权限的私有网站或跟踪资产/监控人或事物的应用程序或网站时,需要选择商业选项。商业计划包括最多 250 个座位的私有或付费应用程序、最多 1,000 个不同资产的资产跟踪以及最多 50 个座位的路线导航应用程序。除了每月 499 美元的费用外,成本与免费计划相同:

图片

项目概述

我们将创建一个小应用程序,允许用户选择他们想要步行到的位置,并将该位置设置为目的地。构建时间大约为 20 分钟。

入门

此应用程序的技术要求如下:

  • 内核版本为 24 或更高版本的 Android 设备

  • Unity 2018

  • Mapbox (www.mapbox.com/)

设置 Mapbox

我们现在将看到如何设置 Mapbox:

  1. 我们需要做的第一件事是注册 Mapbox。这需要一个用户名、电子邮件地址和密码:

图片

  1. 在注册并验证您的电子邮件地址后,它将带您到一个页面,以了解您需要哪个版本的 Mapbox。您可以选择 iOS、Android、Web 和 Unity:

图片

  1. 我们想要的版本显然是 Maps SDK for Unity,所以在继续之前,请确保下载 Unity 包:

图片

  1. 根据以下截图,您将获得一个访问令牌,这是使用 Mapbox 软件所必需的。请确保复制此密钥并将其粘贴到记事本中以便以后使用:

图片

  1. 创建一个新的 Unity 项目,并将其命名为 Chapter6Fitness for Fun

图片

  1. 将 Mapbox Unity 资产文件导入到项目中:

图片

  1. 这可能需要一些时间来安装:

图片

  1. 立即安装后,你应该会注意到一个名为 Mapbox 的新菜单项。这为我们打开了许多新的功能,我们可以进行探索:

图片

  1. Mapbox 为我们提供了 Atlas Template Generator、Clear File Cache、Setup 和 Map Editor 选项:

图片

  1. Mapbox Atlas Template Generator 是一个允许您创建和测试自定义地图图集的工具:

在本节中查看每个项目后,立即退出,以便我们继续。我们将重新访问在构建项目时需要的项目。

图片

  1. 地图编辑器允许您可视化您创建和使用的地图的底层数据结构:

图片

  1. 此外,地图编辑器的数据直接关联到地图对象的抽象地图脚本。你对抽象地图脚本数据的任何更改都会反映在地图编辑器中,你在地图编辑器中的任何更改都会反映在抽象地图脚本的数据中:

图片

  1. Mapbox 设置选项允许您选择示例场景或地图预制件,但是,这只能在复制并粘贴您的访问令牌并提交信息后访问。这需要您连接到互联网进行验证:

图片

需要注意的重要事项

根据不同的项目类型,您将会有预制件会自动添加到活动场景中。在本节中,我们将介绍任何模板类型都会添加的主要对象,即地图对象。

地图是我们添加到任何模板中的最重要的对象,其中包含许多非常重要的项目,我们应该对其进行审查:

Map对象中的第一个项目是抽象地图脚本。其中最重要的项目是地图层、通用、位置和其他:

在通用选项卡中,我们有:

  • 纬度经度:如果您点击搜索,您可以通过输入地址、国家城市,甚至城市和州来设置此选项,具体取决于您想要利用的位置。它将自动将其转换为纬度和经度值。

  • 缩放:这是专门设置地图可以绘制多近或多远的距离;请注意,如果为它生成了适当的瓦片集,缩放功能才能正常工作。

  • 范围选项:这些是您想要地图绘制多远的选项。默认情况下,它设置为摄像机的边界。

  • 摄像头:这是您想要使用的摄像头,无论是带有 Vuforia、ARCore、ARKit 还是常规的 Unity 摄像头。

  • 更新间隔:这是程序在更新位置和绘制之前应该等待多长时间。

  • 初始化于开始时:这是一个布尔值,用于确定是否希望在场景开始时立即绘制地图:

在其他选项卡中,我们也有一些选项:

  • 放置选项允许您在位置中心和对齐瓦片中心之间进行选择。这控制了瓦片的中心或根放置。位置中心可以由您定义,而瓦片中心是瓦片的中心。

  • 将地图吸附到原点是一个布尔值,用于指定地图的根是否应该吸附到 0,0,0。

  • 缩放选项允许您选择是否希望使用自定义或世界缩放。自定义由 Unity 使用墨卡托转换因子定义。世界缩放意味着实际缩放将被渲染,墨卡托转换将被忽略。

  • Unity 瓦片大小是以 Unity 单位为单位的瓦片大小。

  • 加载纹理是在加载纹理时使用的纹理。

下一页签是图像选项卡:

  • 数据源:这是我们地图的来源。我们可以使用 Mapbox 街道、Mapbox 户外、Mapbox 暗色、Mapbox 亮色、Mapbox 卫星、Mapbox 卫星街道、自定义或无。这些基本上是您想要使用的地图的主题选项。

  • 使用 Retina:这是一个布尔值,允许您选择是否启用使用更大的纹理图和更好的视觉质量以适应视网膜显示屏。

  • 使用压缩:这是一个布尔值,允许您选择是否使用 Unity 压缩瓦片纹理。

  • 使用 Mip 映射:这是一个布尔值,让您选择是否使用 Unity 生成的 Mip 映射。

下一页签是 TERRAIN,它为我们提供了修改 Mapbox 地图地形的能力:

图片

  • 数据源:这是第一个选项,它让我们可以选择使用 Mapbox 地形、自定义或无。Mapbox 地形为我们提供全球覆盖的数字高程。自定义允许我们使用自定义的地形模型。无是平坦地形。

  • 地图 ID:这是我们想要使用的对应瓦片集的 ID。

  • 高程层类型:这为我们提供了选择平坦地形、有高程的地形、低多边形地形和地球地形之间的选项。这允许我们以指定的地高类型渲染地形。平坦地形渲染没有地高的平坦地形。有高程的地形渲染从指定源获得地高的地形。低多边形地形渲染从指定源获得地高的低多边形地形。地球地形渲染没有地高的地球地形。

  • 基础材质:这是用于渲染地形瓦片的材质。

  • 夸大因子:这个因子乘以垂直夸大地形地高的值,但是它不适用于平坦地形地高层类型。

  • 添加碰撞器:这是一个布尔值,允许我们将 Unity 物理碰撞器添加到地形瓦片中,用于检测碰撞。

地形标签页内的其他标签页也有几个可供我们选择的选项:

  • 样本计数:这为我们提供了地形的分辨率,结果是一个 n x n 的网格。

  • 使用相对高度:这是一个布尔值,它允许我们使用世界相对比例来缩放地形高度。

  • 地球半径:这是我们想在 Unity 单位测量中使用的地球半径,即米。

  • 显示侧墙:这是一个布尔值,它为地形网格添加侧墙,这减少了视觉伪影。

  • 添加到 Unity 层:这会将地形瓦片添加到 Unity 层。勾选复选框后,你将可以选择将它们添加到哪个层——默认、透明 FX、忽略射线投射、水、UI、后期处理和添加层。

接下来是地图层标签页:

图片

  • 数据源:这是矢量数据的数据源。

  • 地图 ID:这是我们正在使用的地图的 ID。

  • 使用优化样式:这是一个布尔值,允许我们使用 Mapbox 风格的优化瓦片集,这些瓦片集移除了任何未由 Mapbox 样式表示的层或特征。样式优化的矢量瓦片更小,通过线传输,并且是减少离线缓存大小的绝佳方式。

  • 启用协程:这是一个布尔值,允许我们使用协程。

  • 每个协程实体数:这指定了在单个协程调用中可以组合在一起多少个实体。

兴趣点是下一个标签页。在这里,你可以为你的应用程序或游戏中的重要位置创建特殊标记:

图片

  • 必需的地图 ID:这是我们正在使用的瓦片集的地图 ID,不能为空。

  • 添加层:这允许我们添加兴趣点层。

  • 删除选中项:这允许我们删除一个图层。

最后一个标签是“功能”,它提供了矢量图层可视化器,可以选择添加或删除可视化器。功能允许我们修改某些功能相对于我们创建的兴趣点的显示方式:

图片

  • 添加可视化器:这允许我们更改兴趣点图层可视化的方式

  • 删除选中项:这允许我们删除选中的可视化器

图片

最后,我们还有一个名为“使用位置提供者初始化地图”的脚本,它只提供将一个抽象地图对象添加到其中的选项。这个脚本做的正如其名——它会根据你是在 iOS、Windows 还是 Android 设备上注册,并选择最适合它的位置提供者。

设置项目

现在是时候设置我们的项目了:

  1. 让我们创建一个新的场景并命名为FitnessFun:

图片

  1. 点击 Mapbox 然后设置。这将打开一个设置菜单,你需要粘贴你的访问令牌以获取访问地图预制体模板的权限:

图片

  1. 我们想要使用的地图预制体模板是基于位置的游戏:

图片

  1. 它将在场景中添加一个预制体,看起来像场景编辑标签中的棋子:

图片

  1. 如果你查看层次结构面板,你会注意到那里添加了一个LocationBasedGame预制体,如果你深入查看其中的对象,你会看到一个地图、玩家和位置提供者。你还会注意到自动添加到层次结构中的 Canvas 和 EventSystem:

图片

  1. 在“场景”文件夹内,创建一个“脚本”文件夹:

图片

  1. 在那个“脚本”文件夹内,创建一个名为TargetLocationController的 C#脚本:

图片

  1. 创建另一个名为DestroyTargetLocation的脚本:

图片

  1. 返回到层次结构面板并复制 Player 组件:

图片

  1. 删除带有位置和旋转的即时位置脚本,并将其重命名为targetLocation

图片

  1. 在“场景”文件夹内,创建一个名为“预制体”的文件夹:

图片

  1. TargetLocation对象拖放到“预制体”文件夹中:

图片

  1. 导航到我们的“脚本”文件夹并打开 TargetLocationController 脚本。

我们需要编写脚本以创建一个TargetLocation对象的新实例,并在发生某些事情时销毁该对象。

脚本化项目

在本节中,我们将看到如何脚本化我们的项目:

  1. 我们首先确保使用 Unity 引擎,因为我们需要访问MonoBehaviour
using UnityEngine;
  1. 我们的公共类将命名为TargetLocationController,这与我们在 Unity 编辑器中命名的脚本文件名相同。我们还将从MonoBehaviour继承:
public class TargetLocationController : MonoBehaviour
{
  1. 我们将创建一个名为targetObject的公共GameObject,这样我们就可以将我们的预制体拖放到这个对象上,以便设置对其的引用:
private GameObject targetObject;
  1. 在这一点上,我们将创建一个Start()方法。我们想要找到项目中带有targetLocation标签的对象,因为我们将在触摸事件发生时创建它:
private void Start()
{
    targetObject = GameObject.FindGameObjectWithTag("targetLocation");
}
  1. 我们需要创建一个SetLocation方法并实例化一个新的射线投射,以便以我们想要的方式利用触摸事件来读取屏幕上的手指按压:
private void SetLocation()
{
RaycastHit hit = new RaycastHit();
  1. 我们需要通过触摸事件循环检查我们的输入:
for (int i = 0; i < Input.touchCount; ++i)
  1. 我们检查触摸次数是否大于0,并且我们的触摸阶段是否为移动:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
  1. 现在,我们将从屏幕上的当前触摸坐标构造一条射线:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
  1. 我们需要检查射线投射是否击中任何物体:
if (Physics.Raycast(ray, out hit))
  1. 如果射线投射击中任何物体,我们将基于我们的触摸事件创建一个新的预制体实例:
Instantiate(targetObject, new Vector3(Input.GetTouch(i).position.x, 4.23f, Input.GetTouch(i).position.y), Quaternion.identity);
}
}
  1. 在我们的Update()方法中,我们调用我们的SetLocation脚本:
private void Update()
{
SetLocation();
}
}
  1. 现在,我们只需要一个简单的碰撞检测脚本,用于检查玩家对象是否与targetlocation对象发生碰撞。如果玩家对象与之碰撞,我们希望销毁我们的targetLocation对象。

  2. 打开Destroy Target Location脚本。

  3. 我们需要像往常一样使用UnityEngine命名空间,因为我们想要从MonoBehaviour继承:

using UnityEngine;
 using System.Collections;
  1. 类的名称与我们所给的 C#脚本文件名相同,并从MonoBehaviour继承,因此我们可以将其附加到 Unity 编辑器中的游戏对象:
public class DestroyTargetLocation: MonoBehaviour
 {
  1. 我们创建了一个带有Collision col参数的OnCollisionEnter方法:
void OnCollisionEnter (Collision col)
{
  1. 我们将进行一个简单的if检查,以查看我们碰撞的是否是targetLocation对象,通过对象的标签名称:
if(col.gameObject.tag == "targetLocation")
{
  1. 如果简单的if检查返回 true,那么我们将销毁targetLocation对象:
Destroy(col.gameObject);
}
}
}

我们已经拥有了完成项目所需的一切。

最终完成项目

我们现在将最终完成我们的项目:

  1. 返回 Unity 编辑器,将targetLocation脚本附加到玩家对象,并将该对象设置为targetLocation对象:

图片

  1. DestroyTargetLocation脚本附加到我们的LocationBasedGame对象:

图片

  1. 现在,我们可以点击文件 | 构建:

图片

  1. 设置 Android 的项目类型:

图片

  1. 确保为构建添加的唯一场景是Chapter6场景。如果场景列表为空,请点击添加当前场景:

图片

  1. 现在,构建项目并将其安装到您的 Android 设备上以运行程序。

摘要

在本章中,我们构思并创建了一个健身应用程序原型,鼓励用户为了娱乐而前往不同的地点。我们了解了 Mapbox 及其功能,并学习了如何将其集成到 Unity 中。然后我们利用 Mapbox 创建了一个可查看的 AR 地图,能够使用地理定位技术跟踪用户的位置和目的地。

在下一章中,我们将介绍通过创建图片拼图游戏来帮助儿童学习的应用程序/游戏的制作。

问题

利用 Vuforia、ARCore 或 ARKit 来读取世界中的某些对象,以保存您的行踪或使此应用程序游戏化。为此,您需要创建 AR 标记,这些标记有大量的文档和在线示例,展示了如何为不同项目类型利用它们。

  1. 您可以使用 Mapbox 与 ARCore、ARKit 和 Vuforia 一起使用:

A.) 正确

B.) 错误

  1. Mapbox 完全免费:

A.) 正确

B.) 错误

  1. Mapbox 完全集成以与 Unity 一起工作:

A.) 正确

B.) 错误

  1. Mapbox 提供基于网页的软件来创建自定义地图:

A.) 正确

B.) 错误

  1. Mapbox 预建了一个示例场景,允许您使用 UnityChan 作为您的玩家模型:

A.) 正确

B.) 错误

进一步阅读

Mapbox 对 Unity、iOS、Android、React Native 和 QT 进行了大量的文档记录。他们有关于如何使用 Mapbox Studio、如何直接利用他们的地图、路线和地理编码 API 的教程。访问他们文档的最快方式是访问 www.mapbox.com/developers/

第七章:拍摄!给图片添加滤镜

在本章中,我们将创建一个应用程序,它将允许我们在人的头上添加一个叠加层。如果这个应用程序听起来很熟悉,那是因为市场上有很多应用程序就是做这个的,今天,您将学习如何做到这一点。

在本章中,您将了解以下内容:

  • OpenCV

  • 设置 OpenCV

  • 将 OpenCV 集成到 Unity 中

  • 使用 OpenCV 和 Unity 创建原型项目

项目概述

此项目大量使用了人脸识别和检测算法,这需要了解 OpenCV。

构建时间:两小时

开始使用

在本节中,我们将介绍您将需要的一些内容,以及一些可选项目,以更深入地了解从源代码构建的要求。

什么是 OpenCV?

OpenCV 代表 Open Computer Vision。OpenCV 是一个开源的计算机视觉和机器学习软件库,它使用 C++ 构建,并具有 C++、Python、Java 和 Matlab 接口,以支持 Windows、Linux、Android 和 macOS。

OpenCV 主要关注实时视觉应用,尽管它也可以很好地用于机器学习。该库有许多优化的算法和函数,用于组成或支持这些算法,以支持最先进的计算机视觉和机器学习,大约有 2,500 个。要具体说明这个比例,大约有 500 个算法,其余的是用于组成或支持这些算法的函数。

讨论算法很有趣,但我想你更想知道这些算法能做什么。这些算法被设计用来检测人脸、识别人脸、识别物体、在视频流中检测和分类人类动作、跟踪相机运动、移动对象跟踪、从物体中提取 3D 模型、从立体相机中生成点云以在 3D 中制作,将图像拼接成高分辨率图像、快速从图像数据库中找到相同或相似的图像、去除红眼、眼动追踪、检测场景、并为增强现实叠加建立标记,以及更多。

OpenCV 可以轻松与 TensorFlow、Caffe、Torch、Yolo、Vuforia、ARCore 和 ARKit 一起工作。OpenCV 可用于增强现实AR)、虚拟现实VR)和混合现实MR)。你可以使用视觉脚本选项,如 PlayMaker,并访问 OpenCV 中所有可用的方法。OpenCV 还与众多不同的硬件兼容,例如 HoloLens、Oculus Rift、Telepathy、Kinect 和 Raspberry Pi 等。

我们有两种不同的方式来获取对 OpenCV 的访问权限。第一种是从源代码构建并创建我们自己的包装器来创建一个 Unity 插件。第二种是从 Unity Asset Store 购买 OpenCV for Unity。

如果你想要走捷径并购买 Unity 扩展,它将花费 70 美元,除非你有 Unity Plus/Pro 会员资格,这将把成本降低到 56 美元。好消息是它支持 Unity 版本 5.6 或更高版本,并且基于 OpenCV 3.4.1。

你可以从 Unity Asset Store 或 GitHub 下载示例资产包,这些包将为你提供用于与 HoloLens 人脸检测叠加、人脸关键点检测、面部遮罩、实时人脸识别、无标记 AR、面部交换、与 OpenCV 结合的 Kinect、面部跟踪、与 Vuforia 和 OpenCV 一起工作以及基于标记的 AR 等工作的预构建示例。

现在,另一种选择,换句话说,是便宜的方法,因为,让我们说实话,Unity 插件相当昂贵,尤其是对于年轻的开发者或那些只想尝试 OpenCV 以看它是否适合的人。从源代码构建的好处是什么,除了低成本之外?

首先,我们有权决定需要库的哪些方面,这是一个巨大的优势,因为我们可以通过移除冗余来减少文件和编译的大小。然而,即使这样做,你仍然可以拥有与 Unity 插件相同的功能,甚至更多,因为你是在从源代码构建。

坏处是,你需要处理许多事情才能完成源代码的完整编译,这取决于你是否想使用预构建的二进制文件还是从头开始构建自己的库。

要从头开始构建,你需要安装了 C++模块的 Visual Studio,CMake,Python 2.7 或更高版本,Numpy,Intel Threading Building BlocksTBB),Intel Integrated Performance PrimitivesIPP),Intel IPP Asynchronous C/C++,Eigen,CUDA Toolkit,OpenEXR,OpenNI Framework,以及 Doxygen。

使用付费资产创建项目

在本节中,我们将使用 Unity 资产文件,因为它们设置起来更短。Dlib FaceLandmark Detector 的价格为 40 美元,OpenCV for Unity 的价格为 70 美元。这意味着要构建这个项目,你需要花费 110 美元。遗憾的是,Unity 资产商店中没有免费的替代品,如果你想在没有购买资产的情况下构建项目,你需要自己构建包装和实现。现在,按照以下步骤操作:

  1. 创建一个新的 Unity 项目。我将称它为Snap

  1. 确保你的Assets目录完全为空:

这张截图中的文本并不重要。它表明资产目录是空的。

  1. 我们将首先将 OpenCV 导入 Unity。这需要一些时间来完成:

  1. 你将会有很多示例,包括一些非常好的着色器,这些着色器可以在其他项目中使用,所以导入所有内容:

  1. 你的Assets目录应该有一个OpenCVForUnity和一个Realistic_Water_Fountain文件夹:

  1. 现在,我们需要导入 Dlib Facelandmark Detector。

  2. 我们最后需要的资产是 FaceMask 示例。点击此链接:assetstore.unity.com/packages/templates/tutorials/facemask-example-79999

  3. 此软件包包含一些额外的脚本,以及如何将面部遮挡应用于摄像头的一些示例,以便能够录制视频或拍照。

  4. 使用 FaceMask 示例场景,这将创建我们的基本原型。

我们现在有了 Snap 的可用原型。你可以添加更多功能,比如不同的面部覆盖物品,只覆盖头部的一小部分,为场景添加着色器效果,等等,以创建基于 OpenCV 和 Dlib Facelandmark Detector 的自己的功能丰富的 AR 应用。

安装和构建 OpenCV

现在,如果你没有足够的资金使用付费资产来简化你的生活,你会怎么办?好吧,选择从头开始构建。这要复杂得多,通常是一个只有经验丰富的开发者才会深入其中的兔子洞,而对于初学者来说则不然。

这并不是说初学者不能跟随并从头开始构建;事实上,我建议如果你是初学者,就跟随,因为从这个练习中可以学到很多新东西,从处理他人的源文件,到理解代码库并将其纳入自己的项目中。

要将 OpenCV 设置好以便与 Unity 一起运行,我们需要经过几个步骤。我们需要下载 OpenCV 和 CMake。OpenCV 是我们将大量使用的库,而 CMake 是允许我们在任何给定的操作系统和编译器中独立管理构建过程的软件。

下载 OpenCV

让我们首先下载 OpenCV 开始。我们可以选择获取纯源文件或预构建的二进制文件,这两种方法都有其自身的优缺点。例如,纯源文件版本将要求我们安装并配置 OpenCV 中使用的每个库和语言,以便能够构建自己的二进制文件。我们将通过选择预构建二进制方法来简化这个过程。按照以下步骤操作:

  1. 要从预构建二进制文件开始构建 OpenCV,我们首先需要下载所需的文件。有两种可能性,opencv.org/opencv-3-3.htmlsourceforge.net/projects/opencvlibrary/

  1. 我们需要选择我们想要的安装版本;在这种情况下,我将选择最新版本,即3.4.1,因为它与 Unity 扩展版本相同:

  1. 可执行文件大小为 172 MB,因此,根据你的互联网连接速度,下载时间可能会很长:

  1. 创建一个新的文件夹来存放提取的 OpenCV 文件:

  1. 现在,我们有了 OpenCV 自解压文件:

  1. 右键单击安装文件,并选择以管理员身份运行。我们需要提升权限以确保项目正确提取:

  1. 选择你创建的文件夹作为安装位置:

  1. 提取文件不应花费很长时间:

  1. 现在,我们已经提取了 OpenCV。

下载 CMake

现在 OpenCV 已经下载完毕,是时候下载 CMake 了,因为这两个文件对于正确继续都是必不可少的。

这只适用于你决定选择源代码方向而不是二进制方法的情况,所以我也将简要介绍这些步骤。

下载 CMake 是一个相当快速且无痛苦的过程,无论您使用的是 Linux、macOS 还是 Windows。由于我想用 Windows 进行构建,我将针对该特定操作系统展示步骤。

  1. 访问 CMake.org;点击下载最新版本,然后滚动到最新发布版下载 CMake:

图片

  1. 双击 CMake 运行安装向导:

图片

  1. 许可协议 块中勾选复选框,然后点击下一步:

图片

  1. 确保将 CMake 添加到系统 PATH 中,针对当前用户或所有用户,具体取决于您的偏好。只需确保在点击下一步之前将其设置为系统路径即可:**

图片

  1. 点击下一步将 CMake 安装到您想要的任何文件夹:

图片

  1. 要安装 CMake,需要提升权限,因此如果您启用了 UAC 并且没有管理员权限,请确保附近有可以给您安装权限的人:

图片

  1. 安装过程可能需要几分钟才能完成:

图片

  1. 点击完成以完成安装过程:

图片

配置 CMake 和 OpenCV 源文件

现在,我们可以继续配置 CMake,并设置好所有内容以构建 OpenCV 库,以便在 Unity 中使用。为此,您需要 OpenCV 的完整源代码,而不是二进制文件,您可以从 github.com/opencv/opencv/archive/3.3.0.zipgithub.com/opencv/opencv/archive/3.3.0.zip 获取。

启动 CMake (CMake-gui)。您可以在开始菜单的搜索中再次输入它,或在所有程序 | CMake 2.8 | CMake (CMake-gui) 中获取它。首先,选择 OpenCV 库源文件的目录(1)。然后,指定您将构建 OpenCV 库二进制文件的目录(2)。

点击配置按钮以指定您想要使用的编译器(以及 IDE)。请注意,您可以选择不同的编译器来制作 64 位或 32 位库。选择您在应用程序开发中使用的编译器。

CMake 将根据您的系统变量启动,并尝试自动定位尽可能多的包。您可以在 WITH ‣ WITH_X 菜单点中修改用于构建的包(其中 X 是包缩写)。

选择您想要使用的所有包,然后再次按下“Configure”按钮。为了更容易地查看构建选项,请确保在二进制目录选择下的“Grouped”选项已开启。对于某些包,CMake 可能无法找到所有必需的文件或目录。如果它找不到所有这些文件,CMake 将在其输出窗口(位于 GUI 底部)中抛出错误,并将其字段值设置为未找到的常量。

再次按下“Configure”按钮,并确保没有错误报告。CMake 将通过按下“Generate”按钮创建项目文件。转到构建目录并打开创建的 OpenCV 解决方案。根据您选择了多少选项,解决方案可能包含相当多的项目,因此请在 IDE 启动时保持耐心。现在,您需要构建“Release”和“Debug”二进制文件。使用 IDE 上的下拉菜单在构建其中一个之后切换到另一个。

最后,您可以在 bin 目录中观察到构建的二进制文件。

要将您在项目中使用头文件和二进制文件收集到单独的目录中(类似于预构建的二进制文件的方式),您需要明确构建“Install”项目。

要测试您的构建,只需进入“Build/bin/Debug”或“Build/bin/Release”目录,并启动几个应用程序,例如“contours.exe”。如果它们运行,则表示您已完成。

更多关于此方面的详细信息,请访问 docs.opencv.org/3.0-beta/doc/tutorials/introduction/windows_install/windows_install.html。OpenCV 文档将更详细地介绍此内容,以及您将需要安装的其他工具以走这条路。

OpenCV 与 Unity

现在,我们可以继续将我们的 dlls 导入 Unity,并编写我们的包装类以处理与 OpenCV 和 Unity 的接口。这样,我们就可以创建我们的脚本来构建我们的项目:

  1. 创建一个文件夹。我将我的文件夹命名为 ConfigureOpenCV

  1. 我们需要在 Visual Studio 中创建一个新的空 C++ 项目。我将我的项目命名为 ConfigureOpenCV,并将其位置设置为 ConfigureOpenCV 文件夹中:

  1. 在 Visual Studio 中将平台设置为 x64:

  1. 右键单击项目属性文件并选择“属性”:

  1. 这将打开我们的属性窗口:

  1. 我们需要做的第一件事是在“常规”选项卡中将目标扩展名从 .exe 更改为 .dll

  1. 我们需要将配置类型从应用程序 (.exe) 更改为动态库 (.dll):

  1. 在 VC++目录中,将我们的OPENCV_DIRs添加到包含目录中:

  1. 在链接器的一般选项卡中,将$(OPENCV_DIR)\lib\Debug添加到附加库目录选项中:

  1. 最后,在链接器的输入选项卡中,我们需要将一些项目添加到附加依赖项选项中。这些项目将是以下内容:

    • opencv_core310.lib(或opencv_world330.lib,取决于您的 OpenCV 版本)

    • opencv_highgui310.lib

    • opencv_objdetect310.lib

    • opencv_videoio310.lib

    • opencv_imgproc310.lib

图表显示了链接器输入选项卡中附加依赖项的位置,其中添加了 opencv_core。

  1. 现在,我们可以创建一个新的 CPP 文件:

我们将现在整合我们绝对需要的头文件和命名空间:

#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
  1. 声明一个struct,它将被用来从 C++传递数据到 Mono:
struct Circle
{
Circle(int x, int y, int radius) : X(x), Y(y), Radius(radius) {}
int X, Y, Radius;
};
  1. CascadeClassifer是一个用于对象检测的类:
CascadeClassifier _faceCascade;
  1. 创建一个字符串,它将作为窗口名称:
String _windowName = "OpenCV";
  1. 视频捕获是一个用于打开视频文件、捕获设备或 IP 视频流以进行视频捕获的类:
VideoCapture _capture;
  1. 创建一个用于存储缩放的整数值:
int _scale = 1;
  1. extern "C",作为一个提醒,将避免 C++的名称修饰。我们的第一个方法是Init用于初始化:
extern "C" int __declspec(dllexport) __stdcall  Init(int& outCameraWidth, int& outCameraHeight)
{
  1. 我们将创建一个if语句来加载CVFeatureParams部分中的 LBP 人脸cascade.xml文件;如果无法加载,则将退出并返回代码-1
if (!_faceCascade.load("lbpcascade_frontalface.xml"))
return -1;
  1. 现在,我们将打开视频捕获流:
_capture.open(0);
  1. 如果视频流没有打开,我们将以返回代码-2退出:
if (!_capture.isOpened())
return -2;
  1. 我们将设置相机宽度:
outCameraWidth = _capture.get(CAP_PROP_FRAME_WIDTH);
  1. 我们还需要设置相机高度:
outCameraHeight = _capture.get(CAP_PROP_FRAME_HEIGHT);
return 0;
}
  1. 现在,我们需要确保我们创建一个方法来关闭捕获流并释放视频捕获设备:
extern "C" void __declspec(dllexport) __stdcall  Close()
{
_capture.release();
}
  1. 下一步是创建一个设置视频缩放的方法:
extern "C" void __declspec(dllexport) __stdcall SetScale(int scale)
{
_scale = scale;
}
  1. 接下来,我们将创建一个方法,使我们能够检测一个对象:
extern "C" void __declspec(dllexport) __stdcall Detect(Circle* outFaces, int maxOutFacesCount, int& outDetectedFacesCount)
{
Mat frame;
_capture >> frame;
  1. 接下来,如果帧为空,我们需要通过从方法中退出来防止由此产生的可能错误:
if (frame.empty())
return;
  1. 创建一个名为faces的向量:
std::vector<Rect> faces;
  1. 我们将创建一个名为grayscaleFrameMat,这是形成矩阵的各种构造函数之一:
Mat grayscaleFrame;
  1. 我们接下来需要将帧从 RGB 颜色空间转换为灰度,以便进行适当的级联检测:
cvtColor(frame, grayscaleFrame, COLOR_BGR2GRAY);
Mat resizedGray;
  1. 下一步是将视频缩放缩小以获得更好的性能:
resize(grayscaleFrame, resizedGray, Size(frame.cols / _scale, frame.rows / _scale));
equalizeHist(resizedGray, resizedGray);
  1. 接下来,我们将检测faces
_faceCascade.detectMultiScale(resizedGray, faces);
  1. 我们现在将创建一个循环来绘制人脸:
for (size_t i = 0; i < faces.size(); i++)
{
Point center(_scale * (faces[i].x + faces[i].width / 2), _scale * (faces[i].y + faces[i].height / 2));
ellipse(frame, center, Size(_scale * faces[i].width / 2, _scale * faces[i].height / 2), 0, 0, 360, Scalar(0, 0, 255), 4, 8, 0);
  1. 现在,我们将将这些信息发送到应用程序:
outFaces[i] = Circle(faces[i].x, faces[i].y, faces[i].width / 2);
outDetectedFacesCount++;
  1. 由于我们有一个矩阵,我们需要确保我们不会超过数组的限制。为此,如果人脸计数等于我们分配的最大人脸计数,我们将退出循环:
if (outDetectedFacesCount == maxOutFacesCount)
break;
}
  1. 我们最后需要做的是显示调试输出:
imshow(_windowName, frame);
  1. 现在,构建dll文件,我们就可以开始在 Unity 中工作了。

OpenCV 和 Unity

现在,我们终于可以在这个部分开始使用 Unity 了。这是比较简单的一部分,我们只需要创建我们的包装器和附加到对象的MonoBehaviour脚本。

导航到我们创建的dll文件。这应该在源项目的 x64 | Debug 文件夹中:

图片

在 Unity 中创建两个名为PluginsScripts的文件夹,就像我们在第三章中做的那样。

现在,我们将创建两个脚本。一个用于我们的Wrapper类,另一个用于我们的MonoBehaviourWrapper类将被命名为OpenCVWrapper,而MonoBehaviour类将被命名为OpenCVFaceDetection

在 Visual Studio 中打开OpenCVWrapper类。现在是时候写一些代码了。

我们只需要为这个类使用InteropServices命名空间:

using System.Runtime.InteropServices;

我们将创建一个internal static class,这次:

internal static class OpenCVWrapper
{

我们将导入我们在上一步创建的Init函数,并确保我们引用了参数。ref关键字与 C++中的&关键字非常相似:

 [DllImport("UnityOpenCVSample")]
 internal static extern int Init(ref int outCameraWidth, ref int outCameraHeight);

我们将导入Close函数,它将关闭连接,并避免我们在使用我们创建的函数时出现内存泄漏:

[DllImport("UnityOpenCVSample")]
 internal static extern int Close();

我们将导入我们创建的SetScale函数,同时保留我们在 C++中需要的参数:

[DllImport("UnityOpenCVSample")]
 internal static extern int SetScale(int downscale);

我们将导入Detect函数,这个函数有点不同,因为我们实际上使用了一个指针;这很快就会变得非常重要,因为它涉及到 C#和 Unity 中的不安全代码。如果你不熟悉,*关键字表示指针,它是对象在内存中的地址:

[DllImport("UnityOpenCVSample")]
 internal unsafe static extern void Detect(CvCircle* outFaces, int maxOutFacesCount, ref int outDetectedFacesCount);
 }

最后,我们将创建一个需要顺序排列且具有正确字节大小(3 个整数= 4 字节 * 3 = 12 字节)的结构,用于 CvCircle:

 [StructLayout(LayoutKind.Sequential, Size = 12)]
 public struct CvCircle
 {
 public int X, Y, Radius;
 }

这就处理了包装类,我们现在可以转到我们的MonoBehaviour类。

我们需要几个命名空间,因为它们将在脚本中完全使用:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

我们在 Unity 编辑器中的类名与文件名相同,并继承自MonoBehaviour

public class OpenCVFaceDetection : MonoBehaviour
{

在这里需要注意的主要是,我有一个对摄像头的引用和一个WebCamTexture。这是因为我们将从网络摄像头向摄像头提供数据:

 public Camera camera;
 public static List<Vector2> NormalizedFacePositions { get; private set; }
 public static Vector2 CameraResolution;
 private const int DetectionDownScale = 1;
 private bool _ready;
 private int _maxFaceDetectCount = 5;
 private CvCircle[] _faces;
 private Quaternion baseRotation;
 private WebCamTexture webCamTexture;

在这个Start方法中,我们设置并运行一切。我们还检查确保cascades.xml文件可以被找到(更多内容将在下一节中介绍):

void Start()
 {
 int camWidth = 0, camHeight = 0;
 webCamTexture = new WebCamTexture();
 Renderer renderer = GetComponent<Renderer>();
 renderer.material.mainTexture = webCamTexture;
 baseRotation = transform.rotation;
 webCamTexture.Play();
 camWidth = webCamTexture.width;
 camHeight = webCamTexture.height;
int result = OpenCVWrapper.Init(ref camWidth, ref camHeight);
 if (result < 0)
 {
 if (result == -1)
 {
 Debug.LogWarningFormat("[{0}] Failed to find cascades definition.", GetType());
 }
 else if (result == -2)
 {
 Debug.LogWarningFormat("[{0}] Failed to open camera stream.", GetType());
 }
 return;
 }
CameraResolution = new Vector2(camWidth, camHeight);
 _faces = new CvCircle[_maxFaceDetectCount];
 NormalizedFacePositions = new List<Vector2>();
 OpenCVWrapper.SetScale(DetectionDownScale);
 _ready = true;
}

这个方法将确保与网络摄像头的连接被关闭。这将释放资源并确保我们不会泄漏任何内存:

void OnApplicationQuit()
 {
 if (_ready)
 {
 OpenCVWrapper.Close();
 }
 }

这个Update方法确保网络摄像头的方向被纠正,检查摄像头是否被读取,并积极跟踪人脸检测:

void Update()
 {
 if (!_ready)
 {
 return;
 }
 transform.rotation = baseRotation * Quaternion.AngleAxis(webCamTexture.videoRotationAngle, Vector3.up);

int detectedFaceCount = 0;
 unsafe
 {
 fixed (CvCircle* outFaces = _faces)
 {
 OpenCVWrapper.Detect(outFaces, _maxFaceDetectCount, ref detectedFaceCount);
 }
 }

NormalizedFacePositions.Clear();
 for (int i = 0; i < detectedFaceCount; i++)
 {
 NormalizedFacePositions.Add(new Vector2((_faces[i].X * DetectionDownScale) / CameraResolution.x, 1f - ((_faces[i].Y * DetectionDownScale) / CameraResolution.y)));
 }
 }
}

保存脚本并返回 Unity 编辑器。你会立即注意到 Unity 会显示一个类似“需要允许不安全代码”的错误。让我们继续并启用这个功能。为此,前往你的玩家设置,它位于构建设置内部。

在玩家设置中,向下查看其他设置中的配置,有一个名为“允许不安全代码”的复选框。请确保它被勾选:

Scripts文件夹中,你需要添加一个额外的文件;在我的示例文件中,你可以下载,我比你要添加的.xml文件多得多。这样做的原因是让你能够尝试不同的.xml文件,看看它们的结果。你将不得不更新 C++插件以适应你想要使用的正确的.xml文件;或者,你可以更新Init函数以接受一个字符串参数,以便在 Unity 编辑器中更改.xml文件。

在你的OpenCV文件夹中,导航到OpenCV\opencv\build\etc\lbpcascades

你想要将lbpcascade_frontalface.xml复制到 Unity 的脚本文件夹中。(我的项目所有内容都在一个XML文件夹中,因为我有很多.xml文件要使用。)

最后,我们只需要创建一个平面来面对相机。

最后一步是将OpenCVFaceDetection脚本附加到平面上。

现在,项目将适当地编译和运行(如果你遇到 dll 导入错误,请确保 dll 设置为 x86-x64,并且项目是为 Windows 构建的):

摘要

在本章中,我们学习了如何使用 CMake 从源代码构建 OpenCV,将其导入 Unity,并创建一个类似于市场上许多能够可靠地在人脸上添加图像并跟踪其运动的 AR 应用程序,通过使用 OpenCV 和 DLib FaceLandmark Detector,以及使用 Dlib C++库。

在下一章,也是最后一章,我们将探讨为 MR 设备(如 HoloLens)构建。作为一个简短的预告,MR 将 AR 和 VR 的元素结合到一个单一的游戏或应用程序中,这可能会产生巨大和有趣的效果。

问题

  1. OpenCV 是跨平台的,可以与 Android、Linux、MacOS、iOS、Windows、HoloLens 和 Oculus Rift 一起工作:

A.) 正确

B.) 错误

  1. Dlib C++库是使 OpenCV 在 Windows 上工作所必需的:

A.) 正确

B.) 错误

  1. OpenCV 不能从源代码构建:

A.) 正确

B.) 错误

  1. Unity 与 OpenCV 不兼容:

A.) 正确

B.) 错误

  1. 你可以使用 OpenCV 与 ARKit、ARCore 和 Vuforia 一起使用:

A.) 正确

B.) 错误

  1. OpenCV 是一个为机器学习和计算机视觉设计的库:

A.) 正确

B.) 错误

  1. OpenCV 可以用于 AR、VR 和 MR 项目类型:

A.) 正确

B.) 错误

进一步阅读

  • 对于那些能让你更深入了解如何在 Unity 中使用 OpenCV 的免费资源,你可以从以下 GitHub 链接下载:github.com/EnoxSoftware/OpenCVForUnity

  • 要阅读 Dlib C++库的文档,请访问dlib.net/

  • 要了解关于方法、属性、领域以及 C++、Python 和 Javascript 中的 OpenCV 教程,并深入理解 OpenCV 的构建方式,您可以访问以下链接:docs.opencv.org/3.4.1/

第八章:从 HoloLens 到更远

在本章中,我们将探讨如何使用 HoloLens 来理解如何制作混合现实游戏和应用。主要关注点将是针对 HoloLens 设备进行编码,但也能够使用模拟器来模拟 HoloLens 和混合现实查看器。这将使我们能够测试和查看正在发生的事情,无论我们是否拥有实际的 HoloLens 设备。

本章的学习目标如下:

  • 学习什么是混合现实

  • 理解混合现实的工作原理

  • 实现基本的混合现实原型

混合现实是什么,它是如何工作的?

混合现实被称为MRXR扩展现实)并且可以指代增强现实、虚拟现实,将 AR 和 VR 结合成一个单一的应用或游戏,或者它可以指代游戏世界由现实世界驱动和修改。有许多方法可以将增强现实(AR)和虚拟现实(VR)以及扩展现实(XR)的方面结合到一个单一的应用或游戏中。

应该注意的是,微软独家使用 MR 来表示混合现实;然而,XR 和 MR 这两个术语可以互换使用,人们能够理解你所指的是什么。

让我们来看看 Gbanga Millform Inc 公司的一些著名的混合现实游戏示例,并剖析为什么它们是混合现实游戏而不是仅仅的 AR 或 VR 游戏。其中两款我认为非常值得注意的游戏是 Smart Urban Golf (gbanga.com/gameography/smart-urban-golf/) 和 Urban Hunt (gbanga.com/gameography/gross-stadt-jagd/)。

城市狩猎

Urban Hunt 是一款 iOS 和 Android 平台上的实时游戏,玩家需要在苏黎世整个城市中奔跑并逃离一辆一直在追捕他们的车。游戏时长从 90 分钟(一个半小时)到 150 分钟(两个半小时)不等。获胜者将获得一辆真实的梅赛德斯-奔驰 CLA Shooting Brake 汽车。 看看这个截图:

这张图片中的文字并不重要。这是一张 Urban Hunt 正在使用的图片

游戏结合了 GPS 和基于位置的数据来构建游戏世界。游戏旨在让苏黎世市的所有人都能玩。游戏中有一个 AI,玩家需要在实时中逃离它。

现在,让我们来分析一下这款游戏中的 AR、VR 和 MR 是什么。

立刻就可以看出,这个游戏中完全没有添加 VR 元素。所以,我们不必担心 MR 的这个方面。它利用了 GPS、位置数据和苏黎世的市地图。这意味着游戏通过设计内置了一些 AR 的方面。继续前进,它具有 MMO 元素;这既不是 AR 或 VR 特有的,而是大规模多人在线游戏特有的。最后,AI 是你这个玩家需要躲避的。这就是 XR 或 MR 发挥作用的地方。原因是你不通过按钮提示来控制角色;你就是角色,它基于你的真实生活中的行走和跑步动作。这是通过现实世界的交互增强游戏世界,或者相反,通过游戏世界增强现实世界的方面。

现在,你可能认为,“那最后一句话是 AR 的直定义”,但让我们进一步分析。游戏并没有将投影到现实世界,现实世界也没有完全投影到游戏中。AI 仅存在于游戏世界中,而你(玩家)同时存在于游戏世界和现实世界中。你仍然必须全神贯注于游戏世界的规则和 AI,以及现实生活的规则和挑战。这就是混合现实,而不仅仅是增强现实。

智能都市高尔夫

智能都市高尔夫是一款使用手机作为球杆来打高尔夫的游戏,你在游戏世界中击打高尔夫球。你可以通过练习场模式来练习,该模式会根据你的当前位置生成随机课程,或者你可以参加实时锦标赛模式,在那里你与其他人竞争在线排行榜上的最高分。

看看这个截图:

图片

智能都市高尔夫

分析游戏元素,我们可以看到,作为手机的球杆自动将 AR 作为被利用的技术之一。基于位置的随机课程意味着地理定位和 GPS 被大量使用,这在 AR 应用中很常见。与其他人竞争是标准的游戏机制。球只存在于游戏世界中,但受到球杆(你的手机)的影响,所以游戏是 XR 或 MR。

媒体中的 XR 应用

通过展示这两个示例游戏,我们应该对 XR 或 MR 有更好的了解。但我想我们可以更进一步——使用 VR 和 AR 结合会怎样呢?在 YouTube 上,有一些人利用 AR 和 VR 的结合,让观众既能看到游戏中的内容,也能同时看到他们的身体位置,就像在使用 VR 应用一样。看看这个:

图片

Jazza

在这里,我们看到来自 Draw with Jazza 的 Jazza 正在使用 Oculus Rift 在 VR 应用程序中雕刻一个模型。我们可以看到他正在雕刻的内容,以及他在应用程序外的工作情况。这是一个利用 XR 来增强第三方观看体验的例子。

但让我们也看看一个用于游戏的 XR 视频。看看这个:

Brometheus

Brometheus 正在用 HTC Vive 玩一款名为 Nevrosa Prelude 的游戏,这也是一款 VR 游戏,但通过 AR 投影增强了第三方观看体验。

使用 HoloLens 的 XR

这一切都很不错,但让我们再用一个 HoloLens 的例子来看看。看看这个:

Minecraft

在 2015 年 E3 展会上,我们看到了 HoloLens 和 Minecraft 的演示,其中在现实世界中投影了游戏的 AR 图像,同时使用 HoloLens 在 VR 模式下的人也在其中。

最后,让我们用一个 HoloLens 和Windows 混合现实WMR)的例子来结束,因为我认为所有这些例子合在一起才能真正体现 MR 或 XR 的完整体验。让我们看看这个:

这张图片中的文字并不重要。它给你提供了一个使用 Fragments 的混合现实示例

这张截图中的游戏叫做 Fragments,是一款冒险风格的侦探游戏。使这款 MR 或 XR 超越纯 VR 的是,游戏将扫描你的位置,并允许游戏中的物体和角色无缝地与之交互。正如你从截图中所见,角色正坐在玩家的沙发上。

在本节中我们了解到,XR 或 MR 本质上是在现实世界环境和情境中无缝集成 VR 和 AR 元素。这是我们如何将 AR 或 VR 提升到下一个水平以实现适当的混合现实集成的基石。

准备混合现实

HoloLens 要求你的电脑满足一些要求,包括支持 Hyper-V 和 VR 就绪。这也适用于使用 HoloLens 模拟器。那么,我们需要满足哪些要求?请看以下内容:

  • 64 位 Windows 10 专业版、企业版或教育版。

如果你使用的是 Windows 10 家庭版,它不支持 Hyper-V 或 HoloLens 模拟器。

  • 64 位 CPU

  • 四核或更多核心的 CPU,或至少四核心的多个 CPU

  • 8GB 或更多 RAM

  • 支持 DirectX 11.0 或更高版本的 GPU

  • 支持 WDDM(Windows 显示驱动模型)的 GPU,1.2 驱动程序或更高版本

我们还需要一个支持以下功能并已启用的 BIOS:

  • 硬件辅助虚拟化

  • 二级地址转换SLAT

  • 基于硬件的数据执行保护DEP

微软有一份方便的规格列表,适用于笔记本电脑和台式电脑,包括最低和推荐设置。或者,您可以使用 Microsoft Store 上的软件运行 PC 兼容性检查 (www.microsoft.com/en-us/p/windows-mixed-reality-pc-check/9nzvl19n7cnc)。

图片

微软规格

Hyper-V 必须在您的系统上启用。让我们遵循以下步骤:

  1. 要启用 Hyper-V,请转到控制面板:

图片

  1. 选择程序:

图片

  1. 选择程序和功能:

图片

  1. 选择“启用或关闭 Windows 功能”:

图片

Windows 功能

  1. 通过勾选并点击“确定”按钮选择所有 Hyper-V 功能:

图片

启用 Hyper-V

接下来,我们需要绝对确定 Visual Studio 已正确设置。请遵循以下步骤:

  1. 从您的开始菜单打开 Visual Studio 安装程序。如果您有 Visual Studio 社区版,它也可以工作:

图片

VS 安装程序

我们需要确保我们拥有最新版本的 Visual Studio。因此,如果它告诉您更新而不是修改,请先进行更新。

  1. 现在,我们需要点击“修改”,然后,一旦一切准备就绪,点击“单个组件”:

图片

单个组件

  1. 滚动到您看到 Windows 10 SDK 列表的位置。我们需要最新的一个,即 10.0.17134.0,还需要 Windows 10 SDK for UWP C#,版本为 10.0.16299.0:

图片

Windows 10 SDK

  1. 最后一件我们需要做的事情,如果您没有遵循本书中的任何其他章节,确保您的 Unity 最小版本是 2017,尽管我们将使用最新的 Unity 版本,即 2018.1.6f1。如果您没有它,请确保使用 Unity Hub 进行更新:

图片

Unity 最新版本

  1. 我们还需要确保我们拥有 Windows Store .NET 脚本后端、Windows Store IL2CPP 脚本后端以及 Windows IL2CPP 脚本后端,以确保我们能够有效地将 Unity 特定代码转换为 Windows 代码:

图片

Unity 组件

它将在您的硬盘上占用总共 8.8 GB 的空间。

项目概述

此项目将是一个基本原型,确保我们可以在 HoloLens 中查看时显示基本模型。

混合现实体验

让我们从首先下载我们将用于此项目的模型开始。再次,让我们遵循以下步骤:

  1. 前往 turbosquid.com 并将scifi作为搜索参数:

  1. 接下来,将定价更改为免费:

  1. 找到一个您喜欢的。我喜欢机器人,我使用 FBX 格式,因为它易于与多个项目和游戏引擎一起使用。所以,我会选择这个:

  1. 它会带您到一个下载页面,所以请确保您选择正确的文件,如果它有一个textures文件夹,也请下载它:

下载机器人

  1. 前往您下载 zip 文件的文件夹,并解压它:

  1. 现在我们可以进入 Unity。创建一个新的项目,我将称之为Chapter8

  1. 创建一个名为Models的新文件夹:

  2. 将模型导入项目:

我们现在需要完成安装 HoloLens 模拟器的步骤。我应该指出,这仅适用于 Visual Studio 2015 版。如果您有 Visual Studio 2017 或更高版本,您可以使用内置在 Windows 10 SDK 中的混合现实模拟器。让我们按照以下步骤进行:

  1. 前往 http://go.microsoft.com/fwlink/?LinkID=823018下载模拟器。

  2. 点击安装程序以开始安装过程:

  1. 它会询问您是否同意使用 CEIP 程序;选择您的答案并点击下一步:

  1. 接下来是标准的微软许可协议;我建议您阅读它以了解您同意的内容,然后点击接受:

  1. 选择您想要安装的功能;我建议获取模拟器和模板以供将来参考。点击安装:

现在我们可以开始设置项目的其余部分。

设置相机

由于我们或用户使用的是 HoloLens,我们将使用第一人称相机;重要的是要记住,我们的起始位置应始终默认为 Vector 3 的 x 值为0,y 值为0,z 值为0。其他所有内容都应始终根据这一知识进行偏移。

  1. 因此,首先要做的是在层次结构面板中点击相机:

已选择相机

  1. 相机的默认值设置为 X 为0,Y 为1,Z 为-10

默认相机值

  1. 我们需要将其更改为 X 为0,Y 为0,Z 为0。 查看此截图:

修改后的相机值

  1. 由于这是为 HoloLens 制作的,我们不需要 Skybox 纹理;我们希望相机渲染的一切。为此,我们需要将清除标志从默认值更改。

  2. 清除标志的默认值是 Skybox:

默认清除标志

  1. 我们将将其更改为纯色:

清除标志已修改

  1. 接下来,我们需要点击清除标志下方的背景选项,这将打开颜色选择器窗口并将 RGBA 值设置为以下值:0,0,0,0

背景颜色

如果您正在针对沉浸式头戴式设备的目标混合现实应用程序,可以保留 Unity 相机为 Skybox 提供的默认设置。

性能和质量控制

与任何其他游戏或应用程序一样,性能是必须牢记的重要事项。我们需要为混合现实头戴式设备和 HoloLens 保持高帧率。由于这些头戴式设备尚未在市场上销售多年,并且不像 PC、Android 手机、iOS 设备或游戏机那样可升级,因此最好将质量设置设置为尽可能低的值。

  1. 要做到这一点,请点击“编辑”并查找“项目设置”:

项目设置

  1. 点击质量设置:

质量设置默认值

  1. 将质量设置从超清或任何默认值更改为非常低:

质量设置

  1. 最后,点击质量设置旁边的箭头并将这些默认值也设置为非常低。看看这个截图:

设置质量设置

针对 Windows 10 SDK

下一步是确保我们设置了构建所需的目标,在本例中是 Windows 10 SDK。首先,我们需要更改脚本后端。让我们按照以下步骤进行:

  1. 要做到这一点,请打开构建设置菜单:

  1. 现在将目标从 PC、Mac 和 Linux 更改为通用 Windows 平台:

  1. 点击“玩家设置”并查找“配置”。您的脚本运行时版本应设置为.NET 4.x 等效版本,脚本后端应设置为.NET,API 兼容级别应设置为.NET 4.x:

  1. 现在向下滚动并选择 XR 设置:

  1. 点击方框在“虚拟现实支持”框中勾选以启用它;Windows 混合现实应该自动出现,立体渲染方法默认为多通道:

执行机器人操作

我们正在进入这个原型项目的最后步骤。所以,让我们将机器人添加到场景中,开始冲刺。你知道该怎么做——按照以下步骤操作:

  1. 我们需要将机器人添加到场景中:

图片

添加机器人

  1. 我们需要更改几个值,首先是来自检查器面板的位置,然后是旋转,最后是缩放。默认值将其放置在玩家的原点,目前太大,没有实际用途:

图片

机器人检查器

  1. X 位置应设置为 0.26,以补偿我们从分组中略微偏移的位置。Y 位置应设置为 0,Z 位置应设置为 2

图片

位置

  1. 接下来是旋转;我们将设置 X 轴旋转为 45,Y 轴旋转为 45,Z 轴旋转为 45

图片

旋转

  1. 最后,但同样重要的是,是缩放比例。X 轴的缩放将设置为 0.6,Y 轴的缩放设置为 0.6,Z 轴的缩放设置为 0.6

图片

缩放

现在我们已经准备好构建并完成它。

从 Visual Studio 构建 和 部署

好的,这是最后一步,所以请按照以下最终步骤操作:

  1. 在 Unity 中点击构建设置:

图片

构建设置

  1. 确保在 Unity C# 项目中勾选了复选框;其他所有内容都应预先正确设置:

图片

配置

  1. 点击构建:

图片

构建

  1. 它会要求你选择要构建的文件夹;创建一个名为 App 的新文件夹,并选择它:

图片

创建文件夹

  1. 它将花费相当长的时间来构建,所以请做好等待的准备:

图片

构建

  1. 完成后,文件夹应自动打开;选择 App 文件夹,查看它:

图片

应用文件夹

  1. 点击 Chapter8.sln 文件以在 Visual Studio 中打开它:

图片

Visual Studio

  1. 将配置从调试更改为发布:

图片

调试

  1. 将架构从 ARM 更改为 x64:

图片

64 位

  1. 将设备更改为 HoloLens 模拟器:

图片

HoloLens

  1. 点击调试,并选择无调试启动:

图片

无调试

它现在将在模拟器中显示。你已经完成了混合现实程序的第一个原型。

摘要

我们学习了混合现实的工作原理以及我们可以从理论应用到实际使用的一些不同技术。我们查看了一些混合现实示例,并设置了我们的计算机以使用 HoloLens 模拟器构建混合现实应用。

超出这本书的范围,我建议你更多地了解 VR 方面的内容,或者也许可以看看微软为 HoloLens 所做的工作,因为其大部分应用和游戏都是开源的,并且位于 GitHub 上。有许多令人着迷的事情可以学习并融入 AR 和 XR 应用中;这仍然是游戏和应用开发的一个全新的方面,所以进行实验并测试新想法。

问题

  1. HoloLens 需要 Windows 8 SDK:

A.) 正确

B.) 错误

  1. 混合现实与 VR 和 AR 是分开的。

A.) 正确

B.) 错误

  1. Unity 可以被设置为常规 PC 构建,以构建混合现实应用。

A.) 正确

B.) 错误

  1. 安装 HoloLens 模拟器可以通过 Unity 编辑器完成。

A.) 正确

B.) 错误

  1. HoloLens 需要 Windows 10 SDK。

A.) 正确

B.) 错误

  1. 混合现实只能在 iOS 上实现。

A.) 正确

B.) 错误

  1. 增强现实将现实世界扩展到数字世界。

A.) 正确

B.) 错误

  1. 安卓设备是 AR 设备。

A.) 正确

B.) 错误

  1. HoloLens 需要 ARKit 来运行。

A.) 正确

B.) 错误

进一步阅读

posted @ 2025-10-25 10:31  绝不原创的飞龙  阅读(27)  评论(0)    收藏  举报