执行点击测试,以确定 3D 对象在场景中的正确放置位置。正确的放置位置可确保 AR 内容以适当的(表观)尺寸呈现。
命中结果类型
点击测试可以产生四种不同类型的点击结果,如下表所示。
命中结果类型 | 说明 | 方向 | 使用场景 | 方法调用 |
---|---|---|---|---|
厚度 (DepthPoint ) |
使用整个场景中的深度信息来确定点的正确深度和方向 | 垂直于 3D 表面 | 将虚拟对象放置在任意表面(不仅仅是地面和墙壁) |
必须启用 ArDepthMode 才能使用此功能。Frame.hitTest(…) ,检查返回列表中是否有 DepthPoint
|
Plane |
检测水平和/或垂直表面,以确定点的正确深度和方向 | 垂直于 3D 表面 | 使用平面的完整几何图形将对象放置在平面(地板或墙壁)上。需要立即调整比例。Depth 点击测试的后备 |
Frame.hitTest(…) ,检查返回列表中是否有 Plane
|
特征点 (Point ) |
依赖用户点按点周围的视觉特征来确定点的正确位置和方向 | 垂直于 3D 表面 | 将物体放在任意表面(不仅仅是地面和墙壁) |
Frame.hitTest(…) ,检查返回列表中是否有 Point
|
即时展示位置 (InstantPlacementPoint ) |
使用屏幕空间放置内容。最初使用应用提供的估算深度。可立即使用,但当 ARCore 能够确定实际场景几何图形后,姿态和实际深度将会发生变化 | +Y 指向上,与重力相反 | 使用平面的完整几何图形将对象放置在平面(地板或墙壁)上,此时快速放置至关重要,并且体验可以容忍未知的初始深度和缩放 |
Frame.hitTestInstantPlacement(float, float, float)
|
执行标准的点击测试
调用 Frame.hitTest()
以执行点击测试,并使用 TapHelper
实用程序从 AR 视图中获取 MotionEvent
。
MotionEvent tap = tapHelper.poll();
if (tap == null) {
return;
}
if (usingInstantPlacement) {
// When using Instant Placement, the value in APPROXIMATE_DISTANCE_METERS will determine
// how far away the anchor will be placed, relative to the camera's view.
List<HitResult> hitResultList =
frame.hitTestInstantPlacement(tap.getX(), tap.getY(), APPROXIMATE_DISTANCE_METERS);
// Hit-test results using Instant Placement will only have one result of type
// InstantPlacementResult.
} else {
List<HitResult> hitResultList = frame.hitTest(tap);
// TODO: Filter hitResultList to find a hit result of interest.
}
val tap = tapHelper.poll() ?: return
val hitResultList =
if (usingInstantPlacement) {
// When using Instant Placement, the value in APPROXIMATE_DISTANCE_METERS will determine
// how far away the anchor will be placed, relative to the camera's view.
frame.hitTestInstantPlacement(tap.x, tap.y, APPROXIMATE_DISTANCE_METERS)
// Hit-test results using Instant Placement will only have one result of type
// InstantPlacementResult.
} else {
frame.hitTest(tap)
}
根据您感兴趣的类型过滤匹配结果。例如,如果您想关注 DepthPoint
:
// Returned hit-test results are sorted by increasing distance from the camera or virtual ray's
// origin.
// The first hit result is often the most relevant when responding to user input.
for (HitResult hit : hitResultList) {
Trackable trackable = hit.getTrackable();
if (trackable instanceof DepthPoint) { // Replace with any type of trackable type
// Do something with this hit result. For example, create an anchor at this point of
// interest.
Anchor anchor = hit.createAnchor();
// TODO: Use this anchor in your AR experience.
break;
}
}
// Returned hit-test results are sorted by increasing distance from the camera or virtual ray's
// origin.
// The first hit result is often the most relevant when responding to user input.
val firstHitResult =
hitResultList.firstOrNull { hit ->
when (val trackable = hit.trackable!!) {
is DepthPoint -> true // Replace with any type of trackable type
else -> false
}
}
if (firstHitResult != null) {
// Do something with this hit result. For example, create an anchor at this point of interest.
val anchor = firstHitResult.createAnchor()
// TODO: Use this anchor in your AR experience.
}
使用任意光线和方向执行点击测试
点击测试通常被视为来自设备或设备相机的射线,但您可以使用 Frame.hitTest(float[], int, float[], int)
通过现实世界空间坐标中的任意射线(而不是屏幕空间点)执行点击测试。
使用命中结果创建锚点
获得命中结果后,您可以使用其姿势作为输入,在场景中放置 AR 内容。使用 HitResult.createAnchor()
创建新的 Anchor
,确保内容附加到命中结果的底层 Trackable
。例如,锚点将保持连接到检测到的平面,从而获得平面命中结果,因此看起来像现实世界的一部分。
后续步骤
- 查看 GitHub 上的
hello_ar_java
和hello_ar_kotlin
示例应用。