ARCore 中文文档 下载 App

掉帧卡顿排查清单

现象分类

AR 应用的性能问题表现各异,不同根因:

现象可能根因排查方向
全局 FPS 低于 30整体渲染管线太重Draw Call、分辨率、材质
偶尔 FPS 掉到个位数主线程有阻塞操作GC、IO、后台任务
AR 物体抖动SLAM 跟踪质量差环境特征点、光照
只有遮挡开启时掉帧遮挡渲染管线开销深度缓冲、Shader 复杂度
游戏场景大量物体时掉帧单帧 Draw Call 过多Instancing、批处理
特定设备才掉帧设备性能差异GPU 型号、是否支持 Vulkan

排查流程

掉帧现象出现
    ↓
第一步:用 Android Profiler / Unity Profiler 定位瓶颈阶段
    ↓ 瓶颈在 CPU          ↓ 瓶颈在 GPU          ↓ 瓶颈在 IO
第二步:分析 CPU 耗时      第三步:分析 GPU 耗时     第四步:检查后台阻塞
    ↓                       ↓                       ↓
定位到具体函数             定位到 Pass              定位到具体 IO 操作
    ↓                       ↓                       ↓
针对性优化                 针对性优化                移到后台线程

第一步:定位瓶颈阶段

Android Profiler

Android Studio → Profiler → 选择你的进程 → 查看 Call Chart(CPU) 和 Memory:

Unity Profiler

Window → Analysis → Profiler:

快速判断:CPU-bound vs GPU-bound

判断CPU-boundGPU-bound
开启/关闭遮挡渲染不影响 FPS影响明显
降低渲染分辨率到 50%影响不大FPS 大幅提升
减少 Draw Call影响不大FPS 提升
复杂 CPU 逻辑(物理、AI)关闭后 FPS 提升不影响

第二步:CPU 侧优化

最常见的瓶颈来源

来源特征优化手段
Session.update() 后重计算update() 之后你的代码做了重逻辑移到后台线程或协程
GC 频繁FPS 周期性掉帧(每几秒一次)减少每帧 new 对象,用对象池
每帧遍历大量 Trackable有几百个 Trackable 时 slow只在需要时遍历,缓存引用
物理引擎(如 Unity Physics)复杂碰撞场景降低碰撞检测精度,用 Layer 过滤
Cloud Anchors 托管/解析Host Resolve 时卡一下完全后台,不阻塞渲染线程

GC 专项治理

// 错误:每帧 new 对象
fun onDrawFrame() {
    val list = mutableListOf<Anchor>()  // 每帧创建新 List → GC 频繁
    session.getAllAnchors(list)  // 其实可以传入复用的 List
}

// 正确:复用对象
private val anchorList = mutableListOf<Anchor>()  // 类成员变量

fun onDrawFrame() {
    anchorList.clear()
    session.getAllAnchors(anchorList)  // 复用同一个 List
}

Unity 中的 GC Alloc 治理

// 每帧不能分配新内存!
void Update()
{
    // 错误
    var hits = new List<ARRaycastHit>();  // 每帧 new → GC Alloc
    raycastManager.Raycast(Input.GetTouch(0).position, hits);

    // 正确:在类定义中分配一次
    // private List<ARRaycastHit> hits = new List<ARRaycastHit>();
    hits.Clear();
    raycastManager.Raycast(Input.GetTouch(0).position, hits);
}

Profiler 中 GC Allocation 在绿色区域每帧都有意味着泄漏型分配——必须全部清掉。

第三步:GPU 侧优化

Draw Call 过多

优化手段:
1. Static Batching:勾选静态物体,Unity 自动合并(GPU 优化)
2. GPU Instancing:同类物体用 Instanced Rendering
3. Texture Atlas:多张小贴图合并成大图集,减少 Material 切换
4. 减少透明物体(透明物体不能被批处理)

材质 Shader 过重

检查清单:
- Shader 有几个 Pass?每个 Pass 都是一次额外渲染
- 开了 Shadow 吗?AR 场景中阴影开销巨大
- 开了实时反射吗?Reflection Probe 开销大
- 用的 Shader 是移动端兼容的吗?
- 有没有在 Shader 中做复杂计算(如 Fresnel、SSAO)?

Unity URP 渲染路径优化

// URP Asset 设置
URPAsset.renderScale = 0.75f;     // 降低分辨率
URPAsset.msaaSampleCount = 0;      // 关闭 MSAA(AR 不需要)
URPAsset.supportsCameraDepthTexture = true;  // 深度贴图开启(遮挡需要)

第四步:特殊场景优化

遮挡渲染优化

// 低端设备降级策略
if (IsLowEndDevice())
{
    // 关闭遮挡(省了整个深度缓冲写入 + 遮挡 Pass)
    occlusionManager.environmentOcclusionMode = EnvironmentOcclusionMode.Disabled;
}
else
{
    // 简化遮挡(只用 Depth 模式,不用 Human Stencil)
    occlusionManager.environmentOcclusionMode = EnvironmentOcclusionMode.Automatic;
}

Depth API 处理优化

// 不要在每帧用 acquireDepthImage() 然后在 CPU 端遍历
// 正确做法:
// - 渲染管线直接用深度纹理(GPU 处理)
// - 只有特殊计算(如尺寸测量)才在 CPU 端读深度值
// - 读深度值时只读必要区域,不要遍历整张图

多人 AR 场景优化

Cloud Anchors 场景的额外开销:
1. 接收/发送虚拟物体位置数据(如果有实时同步)
   → 用频率限制(比如每 100ms 同步一次,而不是每帧)

2. 同时渲染多个用户的虚拟物体
   → 远处物体用 LOD(Level of Detail)简化
   → 完全不渲染离相机太远的物体(Frustum Culling)

3. Cloud Anchors Resolve 时的回调
   → Resolve 回调不在渲染线程执行,不要做重操作

设备特定问题

问题:某款手机上 FPS 特别低

手机型号可能原因解决
三星 S22/S23 系列默认开启 Vulkan,但 ARCore 不支持Unity Build Settings → Graphics APIs → 移除 Vulkan
小米/红米系列MIUI 可能限制后台进程不在后台创建新进程就行
华为/荣耀AREngine 可能抢占摄像头确保使用 ARCore 而不是 AREngine
iPhone(老机型)硬件性能不足自动降低渲染分辨率
Google Pixel通常是最优适配参考 Pixel 系列做兼容性测试

自动检测设备能力分级

enum class DeviceTier { HIGH_END, MID_RANGE, LOW_END }

fun getDeviceTier(context: Context): DeviceTier {
    // GPU 性能
    val gl = EGLContext.getCurrent().gl as GLES20
    val gpuMemory = getGpuMemorySize()  // 需要实现

    // 屏幕分辨率
    val displayMetrics = context.resources.displayMetrics
    val resolution = displayMetrics.widthPixels * displayMetrics.heightPixels

    return when {
        gpuMemory >= 800 && resolution >= 2000000 -> DeviceTier.HIGH_END
        gpuMemory >= 400 && resolution >= 1000000 -> DeviceTier.MID_RANGE
        else -> DeviceTier.LOW_END
    }
}

然后根据设备 Tier 自动调整: