ARCore 中文文档 下载 App

Streetscape Geometry 获取建筑地形几何数据

Streetscape Geometry 是什么

Streetscape Geometry(街景几何)是 Geospatial API 的附加能力——它让应用不仅知道"手机在哪里",还知道周围有什么东西:建筑物的 3D 形状、地形的起伏、路面的高度变化等。这些数据来自 Google 街景采集时同步获取的 LiDAR 扫描和立体视觉点云。

获取到的几何数据以多边形网格(Mesh)的形式返回,可以直接用于:

启用 Streetscape Geometry

Streetscape Geometry 需要 Geospatial API 先启用,再单独开启:

session.configure(
    Session.Config(context).apply {
        setGeospatialMode(Session.Config.GeospatialMode.ENABLED)

        // 启用 Streetscape Geometry
        setStreetscapeGeometryMode(
            Session.Config.StreetscapeGeometryMode.ENABLED
        )
    }
)

// 检查是否支持
val supported = session.isStreetscapeGeometryModeSupported(
    Session.Config.StreetscapeGeometryMode.ENABLED
)

Streetscape Geometry 对设备和网络的要求比单纯 Geospatial API 更高——它需要下载并处理更大的几何数据集。

获取 Streetscape 数据

Streetscape Geometry 作为一种特殊的 Trackable 存在——StreetscapeGeometry:

session.update(frame)

// 获取当前所有可跟踪的 Streetscape 几何
val geometries = session.getAllTrackables<StreetscapeGeometry>()

geometries.forEach { geometry ->
    // geometry 有两种类型
    when (geometry.type) {
        StreetscapeGeometry.Type.BUILDING -> {
            // 建筑物几何(通常是规则的 Box 或 Mesh)
            val mesh = geometry.mesh
        }
        StreetscapeGeometry.Type.TERRAIN -> {
            // 地形几何(起伏的 Mesh)
            val mesh = geometry.mesh
        }
    }

    // mesh.vertices: FloatArray,每个顶点 3 个浮点 (x, y, z) 世界坐标
    // mesh.triangles: IntArray,三角形索引,每 3 个索引定义一个三角形面
    // mesh.vertexNormals: FloatArray,每个顶点的法线方向
}

返回的 Mesh 数据是三角形网格——和 OpenGL/Unity/Mesh 引擎的 mesh 格式兼容,可以直接用来创建 Collider 或 MeshFilter。

在 Unity 中使用 Streetscape

Unity AR Foundation 需要 Geospatial API 的扩展包(Unity.XR.ARFoundation + Unity.XR.ARCoreExtensions):

// 订阅 Streetscape 更新
ARStreetscapeGeometryManager.Subsystem.frameReceived += OnFrameReceived;

void OnFrameReceived(ARStreetscapeGeoFrameEventArgs args)
{
    foreach (var geo in args.geometries)
    {
        // geo.type = Building 或 Terrain
        // geo.mesh 的顶点、三角形数组
        CreateMeshCollider(geo);
    }
}

创建 Collider 做碰撞检测

void CreateMeshCollider(ARStreetscapeGeometry geo)
{
    var go = new GameObject($"Streetscape_{geo.id}");
    var meshFilter = go.AddComponent<MeshFilter>();
    var meshCollider = go.AddComponent<MeshCollider>();

    var mesh = new Mesh();
    mesh.vertices = geo.mesh.vertices;
    mesh.triangles = geo.mesh.triangles;
    mesh.RecalculateNormals();
    mesh.RecalculateBounds();

    meshFilter.mesh = mesh;
    meshCollider.sharedMesh = mesh;
}

这样你的虚拟物体(比如虚拟球)就能和真实建筑物做物理碰撞了。

遮挡渲染集成

Streetscape Geometry 配合 Depth API 可以实现室外遮挡——普通 Depth API 在远距离的遮挡精度有限,Streetscape Geometry 的建筑 Mesh 提供了额外的深度参考:

渲染流程:
1. 把 Streetscape Geometry 的所有 Mesh 渲染到深度缓冲(不写颜色)
2. 叠加 Depth API 的深度数据(作为补充)
3. 渲染虚拟物体时用这个合并的深度缓冲做遮挡测试

Unity 中可以用 AROcclusionManager + 自定义 RenderFeature 实现。

数据质量与限制

因素说明
覆盖范围有 Street View + 建筑数据的区域才返回 BUILDING 类型;几乎所有区域都有 TERRAIN 类型
几何精度建筑物几何精度通常在 1~3 米(来自街景 LiDAR)
更新频率Google 街景更新时同步更新几何;新建筑可能要等下次街景拍摄
资源消耗Mesh 数据量大——一个街区的建筑 Mesh 可能有数十万顶点
内存管理注意只处理 VPS 定位附近的几何,远离后丢弃

Geospatial Depth:更进一步

Geospatial Depth 是 Streetscape Geometry + 本地 Depth API 的融合:

Geospatial Depth = Streetscape 几何 + 设备本地深度传感器

对于设备支持的区域,Geospatial Depth 能输出比单纯 Depth API 更精确的室外深度数据——因为 Streetscape Geometry 弥补了被动深度在远距离的精度下降。

session.configure(
    Session.Config(context).apply {
        setDepthMode(Session.Config.DepthMode.AUTOMATIC)
        setGeospatialDepthMode(
            Session.Config.GeospatialDepthMode.DISABLED
            // 某些版本还在实验中
        )
    }
)

实际案例:Balloon Pop

Google 自家的 Balloon Pop(开源 AR 游戏)用 Geospatial API + Streetscape Geometry 实现了:

这个项目是理解 Streetscape Geometry 用法的最佳参考。