三种 Geospatial Anchor 类型详解
Geospatial Anchor 的坐标体系
普通 ARCore Anchor 用的是会话内本地坐标系(Session World Coordinates)——原点在 Session 启动时的手机位置,单位是米。
Geospatial Anchor 用的是全球坐标系(WGS84,World Geodetic System 1984)——也就是 GPS 使用的经纬度和海拔高度。单位是:
| 维度 | 单位 | 范围 |
|---|---|---|
| 纬度(Latitude) | 度 | -90 ~ +90(南 ~ 北) |
| 经度(Longitude) | 度 | -180 ~ +180(西 ~ 东) |
| 海拔(Altitude) | 米 | 相对 WGS84 椭球表面 |
不同类型的 Geospatial Anchor 对"垂直位置"的定义不同——这就是三种 Anchor 的区别所在。
类型一:WGS84 Anchor
最常用的类型。海拔直接用 WGS84 椭球参考高度(不是海平面高度,也不是地面高度)。
// 创建 WGS84 Anchor
val earth = arSession.earth
earth.createAnchor(
latitude = 37.7749, // 旧金山纬度
longitude = -122.4194, // 旧金山经度
altitude = 50.0, // WGS84 椭球以上 50 米
eastUpSouthQTarget = GeospatialAnchorQuatTarget.EQUATORIAL_NORTH
)
特点
- 精度:经纬度精度取决于 VPS 定位精度(亚米级 ~ 5 米);海拔精度相对较低
- 使用难度:开发者需要知道目标位置的准确 WGS84 坐标(可以用 Google Earth、地图 API 查询)
- 适用场景:开发者已经知道精确经纬度坐标的场景——比如"把 AR 内容放在某座雕像的位置"
注意事项:海拔的参考系
WGS84 海拔不是海平面海拔,而是相对于一个椭球(WGS84 椭球)的高度。这个椭球是对地球形状的数学近似,不同地区和真正的海平面/地面之间可能有几十米的差异。这意味着:
用 WGS84 Anchor 放置 AR 内容时,海拔值可能需要根据具体区域做校正——否则 AR 内容可能悬浮在空中或埋入地下。
类型二:Terrain Anchor
最适合大多数场景的类型。海拔相对于当地地形表面(地面或地板),而不是 WGS84 椭球。
// 创建 Terrain Anchor
earth.createAnchor(
latitude = 37.7749,
longitude = -122.4194,
altitudeAboveTerrain = 1.5, // 地面以上 1.5 米(人的视线高度)
eastUpSouthQTarget = ...
)
特点
- 海拔定义:相对于当地地形的高度,开发者不需要知道 WGS84 校正值
- 背后的数据:Google 用 Elevation API 和 LiDAR 地形数据确定每个经纬度对应的地面海拔
- 精度:经纬度和 WGS84 Anchor 一样;地形高度精度约 1~5 米(取决于地形数据的精细程度)
为什么首选 Terrain Anchor
WGS84 Anchor 的海拔定义不直观——开发者需要知道某个位置的 WGS84 椭球海拔才能让 AR 内容刚好放在地面上。Terrain Anchor 直接用"地面以上 X 米"这个人人都懂的概念。
绝大多数场景应该用 Terrain Anchor。
类型三:Rooftop Anchor
专门用于建筑物屋顶的 Anchor 类型。海拔相对于目标建筑的屋顶表面。
// 创建 Rooftop Anchor
earth.createAnchor(
latitude = 37.7749,
longitude = -122.4194,
altitudeAboveRoof = 3.0, // 屋顶以上 3 米
eastUpSouthQTarget = ...
)
特点
- 海拔定义:相对于建筑物屋顶的高度,自动减去了该建筑的屋顶高程
- 背后的数据:需要 Google 有该建筑的 3D 模型(来自街景 LiDAR、建筑数据等)
- 适用场景:在建筑屋顶放置 AR 内容——比如楼顶广告牌、屋顶花园的 AR 装饰
Rooftop Anchor 的限制
不是所有建筑都有 Rooftop 数据。如果你在一个没有 Rooftop 数据的位置创建 Rooftop Anchor,ARCore 会返回一个无效的 Anchor(Anchor.trackingState == STOPPED 或 Anchor.pose 不更新)。
三种 Anchor 对比
| 对比项 | WGS84 | Terrain | Rooftop |
|---|---|---|---|
| 海拔参考系 | WGS84 椭球 | 地形表面 | 建筑屋顶 |
| 开发难度 | 高(需查椭球海拔) | 低(直接地面以上) | 中(需有 Rooftop 数据) |
| 海拔精度 | 中(受椭球差异影响) | 好 | 中 |
| 覆盖范围 | 全球(有街景) | 全球(有 Elevation 数据) | 仅大/中城市主要建筑 |
| 推荐使用 | 开发者有精确 WGS84 坐标 | 绝大多数室外场景 | 屋顶相关场景 |
朝向(Orientation):eastUpSouthQTarget
三种 Geospatial Anchor 都需要一个朝向参数——决定虚拟物体在水平面上的方向(南北朝向):
// 几种常用朝向
GeospatialAnchorQuatTarget.EQUATORIAL_NORTH // 朝北(物体正面朝向正北)
GeospatialAnchorQuatTarget.EQUATORIAL_SOUTH // 朝南
GeospatialAnchorQuatTarget.EQUATORIAL_EAST // 朝东
GeospatialAnchorQuatTarget.EQUATORIAL_WEST // 朝西
自定义朝向:
// 用一个四元数指定朝向
// 从地理北偏东 45 度
val rotation = Quaternion.fromAxisAngle(Vector3.Up(), Math.toRadians(45.0))
val target = GeospatialAnchorQuatTarget(rotation)
在 Unity 中创建 Geospatial Anchor
var anchorManager = GetComponent<ARAnchorManager>();
// Terrain Anchor 示例
var pose = EarthApi.CreateAnchor(
latitude: 37.7749,
longitude: -122.4194,
altitudeAboveTerrain: 1.5f,
orientation: Quaternion.identity // 朝北
);
var anchor = anchorManager.AddAnchor(pose);
// anchor 就是普通的 ARAnchor,可以像其他 Anchor 一样用
验证 Anchor 的实际位置
创建 Geospatial Anchor 后,ARCore 会异步地计算精确位置。你需要等到 Anchor 的 TrackingState 变成 TRACKING 且 Transform 稳定后再使用它:
// 在每帧检查
if (geospatialAnchor.trackingState == TrackingState.TRACKING) {
// Anchor 位置已精确,可以放置虚拟物体了
placeContentAtAnchor(geospatialAnchor)
}
初始时 Anchor 可能会有几秒的位置抖动——这是 VPS 正在迭代求精,属于正常行为。