〔研发〕现在开始,开发你的第一款ARCore应用程序
文章相关引用及参考:映维网
本文来自Soumya Kar
(映维网 2018年05月17日)随着计算机视觉和硬件的进步,AR和VR必将成为我们日常生活的一部分。谷歌已经推出了ARCore 1.2.0。面对所有这一切,我都必须进行尝试和实验。
对于本教程,我们需要一些关于使用Unity的基本知识。对于没有接受过正式Unity学习的我来说,我的第一个任务是寻找合适的在线教程。在掌握了这个工具后,我就可以向更高一阶前进。至于ARCore,相关的教程内容似乎非常稀少。似乎有在线学习网站提供课程,但我不确定他们的水平。另外,你需要C#的基本知识。
同时需要注意的是,下面的信息都是基于我个人的理解,知识和经验。我本人也是在不断的学习之中。如果你愿意分享你的想法与经验,我会很高兴。另外,你同时需要一台支持ARCore的设备。我目前正在使用的是Pixel 2。
ARCore主要分为三个部分:
-
理解环境:能够识别现实世界的水平表面。该表面则用于锚定虚拟对象。
-
运动追踪:用于追踪现实世界中的虚拟对象。它提供了将虚拟对象锚定在不同位置的功能。
-
照明估计:提供从现实世界中获取照明信息,并将其应用于虚拟对象的逻辑。
下面我们将开始开发我们的第一款应用程序。但在开始之前,我们先准备相应的工具。即便你没有所需的设备,你同样可以继续阅读本文,只是你无法开始构建和部署应用。
- Unity 2018.1.0f2
- Android SDK 7.0及更高版本
- Google ARCore SDK for Unity(点击前往)
- 支持硬件(我使用的是Pixel 2)
在Unity中创建一个新应用,然后将其命名为ARCoreWorld。
完成后,我们需要导入我们下载的Unity文件。如要导入,请依次选择Assets → Import Package → Custom Package。选择文件并单击导入。
系统应该显示正在导入的项目。在这里,我们将导入所有内容。然后添加预制件(1) ARCore Device和(2) Environmental Light
所有预制件都可以在收藏夹下找到:左下角Project栏中的All Prefabs。
在这种情况下,应用程序属于可构建状态,但要为安卓构建,我们需要切换平台。要访问构建设置,请依次选择从m File → Build Settings。
选择Anroid,然后点击Switch Platform
在完成后,点击Player Settings,在这里我们将做出以下更改:
在这里我们将提供一个有效的包名称。将最低API级别设置为Android API 24,并且将该目标设置为higest installed。另外,请禁用多线程渲染。在XR设置中,我们将启用ARCore支持。
此时,作为骨架的代码已经准备就绪,但现在运行应用程序只会显示摄像头的实际视图:
点云
点云是一个容器,其包含一组关于现实世界的3D数据点信息。它们用于推导关于真实世界的信息和框架的组成,以便通过虚拟对象来进行增强。
对此,我们需要创建一个材质。材质允许我们为3D模型提供纹理或颜色信息。
创建一个名为PointMaterial的材质,并将着色器类型指定为ARCore→PointCloud。我将大小改为15,颜色则是红色。
之后,我们将需要创建一个可以使用这种材质的对象。为此,我们创建一个立方体。然后,我们将材质应用在立方体上。最后,我们需要添加一个名为Pointcloud Visualizer的组件。
当前状态下的应用程序将看起来应该是这样:
我们现在已经准备好了舞台。现在我们要把虚拟对象叠加在现实世界中。这个对象是暗黑破坏神。你可以从这里获取模型(点击前往)。它由另一名开发者创建,我只是将其用于学习交流目的。
下面我们将模型导入Unity。创建一个名为Diablo的文件夹,并将.OBJ文件拖放到这里。导入模型后,你会注意到它只是模型的线框,没有纹理。不用担心。模型的开发者同时提供了所需的纹理,但这是DDS格式。所以我们需要将其转换为TGA。你可以采用任何在线工具执行转换。完成后,将TGA文件拖放到Unity。
要将TGA文件用作纹理,我们需要从中创建一个材质。创建一个新材质,并将着色器选择为“Unlit/Texture(不亮/纹理)”。然后使用TGA文件。
现在将新材质拖放到Diablo模型中,这时你会看到它从灰度模型改变为我们所设想的模型。
为了避免模型过大,我减少了尺寸。你可以选择模型,并将比例因子从1减小到0.15,或者按照你的需求进行缩放。完成后,从Diablo模型创建一个预制件,稍后我们将在渲染器上使用它。
现在我们需要查看绘制虚拟对象的平面。为此,我们可以使用Plane Generator(平面生成器)和Plane Visualiser(平面可视化)组件。
在以后我们将会把点云立方体的大小减少至5个单位。
下面我们来一点编程。我们已经有了平面,应用纹理后的模型。接下来我们需要将暗黑破坏神叠加在现实世界之中。
创建一个空白对象并将其命名为DiabloRenderer。现在添加一个新的C#脚本。更新方法应该看起来像这样:
public Camera FirstPersonCamera;
public
GameObject DetectedPlanePrefab;
public
GameObject DiabloGameObject;
void
Update
()
{
_UpdateApplicationLifecycle();
// Hide snackbar when currently tracking at least one plane.
Session.GetTrackables
bool
showSearchingUI =
true
;
for
(
int
i =
0
; i < m_AllPlanes.Count; i++)
{
if
(m_AllPlanes[i].TrackingState == TrackingState.Tracking)
{
showSearchingUI =
false
;
break
;
}
}
// If the player has not touched the screen, we are done with this update.
Touch touch;
if
(Input.touchCount <
1
|| (touch = Input.GetTouch(
0
)).phase != TouchPhase.Began)
{
return
;
}
// Raycast against the location the player touched to search for planes.
TrackableHit hit;
TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon |
TrackableHitFlags.FeaturePointWithSurfaceNormal;
if
(Frame.Raycast(touch.position.x, touch.position.y, raycastFilter,
out
hit))
{
// Use hit pose and camera pose to check if hittest is from the
// back of the plane, if it is, no need to create the anchor.
if
((hit.Trackable
is
DetectedPlane) &&
Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position,
hit.Pose.rotation * Vector3.up) <
0
)
{
Debug.Log(
"Hit at back of the current DetectedPlane"
);
}
else
{
var
diabloGameObj = Instantiate(DiabloGameObject, hit.Pose.position, hit.Pose.rotation);
diabloGameObj.transform.Rotate(
0
, k_ModelRotation,
0
, Space.Self);
var
anchor = hit.Trackable.CreateAnchor(hit.Pose);
diabloGameObj.transform.parent = anchor.transform;
}
}
}
首先,我们需要公开三个我们需要链接的变量。
- FirstPersonCamera:这是可以在ARCore设备上找到的摄像头,后者则允许我们浏览虚拟对象。
- DetectedPlanePreFab:这将用于渲染虚拟对象的平面检测。
- DiabloGameObject:这是Diablo模型的预制件。
if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began)
该函数将检查我们是否点击了屏幕。如果没有,则无绘制。
if (Frame.Raycast(touch.position.x, touch.position.y, raycastFilter, out hit))
一旦我们触碰了屏幕,上面的函数将从屏幕坐标获取输入,然后将其放到虚拟物体叠加在真实世界上的位置。
var diabloGameObj = Instantiate(DiabloGameObject, hit.Pose.position, hit.Pose.rotation);
diabloGameObj.transform.Rotate(
0
, k_ModelRotation,
0
, Space.Self);
var
anchor
= hit.Trackable.CreateAnchor(hit.Pose);
diabloGameObj.transform.parent =
anchor
.transform;
在现实世界中,暗黑破坏神将放置在由hit.Pose.position定义的位置上。接下来,为了将模型附加到现实世界中的某个位置(即使我们试图环绕模型走动),我们需要确保将虚拟对象锚定到创建该模型的Pose。因此,我们创建一个Anchor,并将其分配给游戏对象的父级。
好,我们已经做出了大量的改动。下面我们看看具体的效果吧:
为了方便截图,我们将大小减少至0.05。
我们可以360度地浏览虚拟对象,详细参见下面的视频。
我们已经通过这个ARCore示例进行了讲解。我将继续努力,并尝试进一步地优化应用。