Instant Placement API 让用户立即放置物体
为什么需要 Instant Placement
传统的 ARCore 流程有一个体验问题:
- 用户打开 AR 应用
- 应用引导用户"缓慢扫一下周围"
- 用户扫了几秒,ARCore 检测出几个平面
- 用户再点屏幕放置虚拟物体
- 物体才出现
这个流程在早期 AR 应用(比如 IKEA Place 的早期版本)中很常见,用户经常在等待平面检测时就关掉了应用。
Instant Placement(即时放置)API 的目标是:用户点屏幕的瞬间就放一个物体,不用等平面检测。ARCore 会用屏幕点击坐标 + 一个"估计距离"(默认 1 米)来先给出一个近似位置,然后在后续跟踪中不断修正,最终当精确位置确定后,虚拟物体的位置会自动对齐到真实表面上。
工作原理
Instant Placement 的返回值经历两个阶段:
| 阶段 | TrackingMethod | 精度 | 含义 |
|---|---|---|---|
| 初始估计 | SCREENSPACE_WITH_APPROXIMATE_DISTANCE | 低 | 基于屏幕点击 + 用户传入的 approximateDistanceMeters 计算的近似位置 |
| 精确跟踪 | FULL_TRACKING | 高 | ARCore 检测到了该区域的特征点/平面后,自动更新为精确位置 |
关键是这两个阶段的切换对开发者是透明的——你只需要在初始帧创建一个 Anchor,后续 ARCore 会自动更新这个 Anchor 的 Pose,你的虚拟物体渲染位置会自然跟着修正。
Android API 使用
步骤一:检查设备支持
Instant Placement 是较新的 API,需要确认设备支持:
// 检查设备是否支持 Instant Placement
val instantPlacementSupported = session.isInstantPlacementModeSupported()
步骤二:配置 Session
session.configure(
Session.Config(context).apply {
setInstantPlacementMode(Session.Config.InstantPlacementMode.LOCAL_Y_UP)
}
)
两种模式:
LOCAL_Y_UP:虚拟物体始终保持 Y 轴朝上(推荐,最符合直觉)SESSION_Y_UP:跟随 Session 的 Y 轴(当设备倾斜很大时物体也会倾斜)
步骤三:Instant Placement Hit Test
// 用户点击屏幕时
val approximateDistanceMeters = 1.0f // 假设虚拟物体在 1 米外
val hitResults = frame.hitTestInstantPlacement(tapX, tapY, approximateDistanceMeters)
// 解析结果
val firstHit = hitResults.firstOrNull() ?: return
// InstantPlacementPoint 是 HitResult 的具体类型
val point = firstHit as InstantPlacementPoint
// 创建锚点
val anchor = session.createAnchor(point.pose)
// 此时 point.trackingMethod 是 SCREENSPACE_WITH_APPROXIMATE_DISTANCE
// 后续帧会变成 FULL_TRACKING,锚点 Pose 也会自动修正
步骤四:监听 TrackingMethod 变化(可选)
如果你想在物体位置从"近似"变为"精确"时给用户一个视觉反馈:
// 在每帧更新后检查
if (point.trackingMethodChangedSinceLastFrame) {
when (point.trackingMethod) {
InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE -> {
// 物体处于近似位置,可以显示半透明或阴影效果提示"还在对齐中"
}
InstantPlacementPoint.TrackingMethod.FULL_TRACKING -> {
// 物体已对齐到精确位置,可以切换到正常渲染
fadeOutPlacementGuide()
}
}
}
Unity AR Foundation 中使用 Instant Placement
using UnityEngine.XR.ARFoundation;
public class InstantPlacementExample : MonoBehaviour
{
public ARRaycastManager raycastManager;
public GameObject virtualPrefab;
void Update()
{
if (Input.touchCount < 1) return;
var touch = Input.GetTouch(0);
if (touch.phase != TouchPhase.Began) return;
// 使用 Instant Placement Raycast(Unity 2021+)
var hit = raycastManager.RaycastInstantPlacement(
touch.position,
approximateDistanceFallback: 1f,
hit: out ARRaycastHit hitResult
);
if (hit)
{
// hitResult.pose 初始可能是近似位置
// AR Foundation 会自动处理后续的跟踪修正
var placed = Instantiate(virtualPrefab, hitResult.pose.position, hitResult.pose.rotation);
// 注意:Instant Placement 创建的锚点不是立即稳定的
// 你可以监听 ARSession 的跟踪状态变化
}
}
}
用户体验设计建议
Instant Placement 能让应用"秒响应",但物体位置会在几帧内跳变——给用户的视觉提示很重要:
- 初始状态用半透明渲染:让用户知道"物体位置还在对齐中"
- 对齐完成后淡化提示:比如位置固定时播放一个微小的缩放动画(从半透明 → 正常)
- 鼓励用户移动设备:"慢慢移动一下手机让物体更精确"——ARCore 在用户移动时能更快积累特征点完成对齐
- approximateDistanceMeters 参数:根据你的应用场景合理设置——比如家具预览可以设置 1.5-2.0 米,桌面小游戏设置 0.5-1.0 米
与传统 Hit Test 的关系
| 对比项 | 传统 Hit Test | Instant Placement |
|---|---|---|
| 必须检测到 Plane/Point 才能用 | 是 | 否,随时可用 |
| 初始位置精度 | 高 | 低(近似距离) |
| 后续是否自动修正 | 否,位置固定 | 是,跟踪变好后自动对齐 |
| 对用户的引导需求 | 需"先扫一下房间" | 直接点就行 |
| 适用场景 | 精确放置家具 | 即时放置 + 后期调整 |
实际应用中两者经常组合使用:Instant Placement 让用户秒放,ARCore 在后台同时尝试做传统 Hit Test,成功后 Anchor 自动切换到精确位置。