ARKit设置preferredFramesPerSecond锁30fps无效如何解决
ARKit固定帧率与稳定截图方案
一、恒定锁定30fps(或更低帧率)的实现
你设置sceneView.preferredFramesPerSecond = 30未生效的核心原因是:ARSCNView的渲染帧率同时受AR会话本身的帧输出速率约束,仅修改SceneKit视图层的帧率配置不会干预ARSession的原生帧推送逻辑,需要同时完成两层配置才能强制锁帧:
- 配置AR会话的帧率范围(iOS 13及以上版本支持),从帧输出源头限制速率:
let config = ARWorldTrackingConfiguration() if #available(iOS 13.0, *) { config.preferredFrameRateRange = CAFrameRateRange( minimum: 30, maximum: 30, preferred: 30 ) } sceneView.session.run(config)
- 补全视图层的帧率配置,关闭系统自动帧率调节:
sceneView.preferredFramesPerSecond = 30 sceneView.preferredFrameRateRange = CAFrameRateRange( minimum: 30, maximum: 30, preferred: 30 ) sceneView.rendersContinuously = false
注意:如果需要锁定更低帧率,直接替换上述代码里的数值即可,但不建议将帧率设置到15fps以下,会直接导致AR世界跟踪精度下降甚至失准。iOS 13以下系统没有提供强制锁帧的公开API,直接使用下文的动态适配方案即可。
二、动态适配帧率的截图逻辑
不需要专门在启动前1-2秒做帧率探测,直接在session(_:didUpdate:)回调内做简单的计数+时间戳兜底判断,就能在任意运行帧率下稳定保持每秒30次截图,还能自动适配运行过程中的帧率波动:
- 先在控制器内定义两个辅助变量:
// 帧计数器 private var frameCounter: Int = 0 // 上一次执行截图的时间戳 private var lastSnapshotTime: TimeInterval = 0
- 在ARSession的帧更新回调内加入判断逻辑:
func session(_ session: ARSession, didUpdate frame: ARFrame) { frameCounter += 1 // 60fps时隔一帧截一次,30fps时每帧都触发,时间戳兜底适配非整数帧率/掉帧场景 let shouldSnapshot = frameCounter % 2 == 1 || (frame.timestamp - lastSnapshotTime) >= 1.0/30.0 guard shouldSnapshot else { return } // 此处写入你的截图逻辑 // 优先取frame.capturedImage做处理,比调用view.snapshot()的CPU开销低80%以上 lastSnapshotTime = frame.timestamp }
这个逻辑不需要提前采样帧率,启动后立刻生效,哪怕运行过程中因为CPU负载变化帧率在30-60fps之间波动,截图频率都会自动调整,始终稳定在每秒30次左右,不会出现重复采样或者采样间隔过长的问题。
内容的提问来源于stack exchange,提问作者martin wotterman
相关产品推荐
相关产品推荐

