【问题标题】:Dispatch queue to animate SCNNode in ARKit调度队列以在 ARKit 中为 SCNNode 设置动画
【发布时间】:2018-05-11 09:41:22
【问题描述】:

我在尝试定期为 ARSession 上的节点设置动画时遇到问题。我每 5 秒从 Internet 获取数据,然后使用该数据更新此节点(缩小或放大)。 我的代码如下所示:

Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { timer in
    fetchDataFromServer() {
        let fetchedData = $0
        DispatchQueue.main.async {
            node1.update(fetchedData)
            node2.update(fetchedData)
            node3.update(fetchedData)
        }
        if stopCondition { timer.invalidate() }
    }
}

问题是,在调用更新时,我看到一个故障,其中相机似乎冻结了几分之一秒,并且我在控制台中看到以下消息:[Technique] World tracking performance is being affected by resource constraints [1] 更新发生正确,但如果每 5 秒我得到这些“短暂的冻结”,用户体验真的很笨拙

我也尝试过创建一个并发队列: let animationQueue = DispatchQueue(label: "animationQueue", attributes: DispatchQueue.Attributes.concurrent) 并调用animationQueue.async 而不是主队列,但问题仍然存在。 如有任何建议,我将不胜感激。

编辑:update 方法上的每个子节点看起来像这样

private func growingGeometryAnimation(newHeight height: Float) -> CAAnimation{
    // Change height
    let grow = CABasicAnimation(keyPath: "geometry.height")
    grow.toValue = height
    grow.fromValue = prevValue

    // .... and the position
    let move = CABasicAnimation(keyPath: "position.y")
    let newPosition = getNewPosition(height: height)
    move.toValue = newPosition.y + (yOffset ?? 0)

    let growGroup = CAAnimationGroup()
    growGroup.animations = [grow, move]
    growGroup.duration = 0.5
    growGroup.beginTime = CACurrentMediaTime()
    growGroup.timingFunction = CAMediaTimingFunction(
        name: kCAMediaTimingFunctionEaseInEaseOut)
    growGroup.fillMode = kCAFillModeForwards
    growGroup.isRemovedOnCompletion = false

    growGroup.delegate = self

    return growGroup
}
self.addAnimation(growingGeometryAnimation(newHeight: self.value), forKey: "bar_grow_animation")

【问题讨论】:

    标签: swift grand-central-dispatch scenekit arkit


    【解决方案1】:

    要对场景进行任何更新,请使用SCNTransaction,它确保所有更改都在适当的线程上进行。

    Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { timer in
        fetchDataFromServer() {
            let fetchedData = $0
    
            SCNTransaction.begin()
            node1.update(fetchedData)
            node2.update(fetchedData)
            node3.update(fetchedData)
            SCNTransaction.commit()
    
            if stopCondition { timer.invalidate() }
        }
    }
    

    【讨论】:

    • 感谢@Lësha Turkowski 的建议。事情是关于每个节点1、节点2、节点3的更新方法,我正在使用CAAnimation并将其添加到节点中。如果我理解正确的话,如果我只是设置节点的动画属性,SCNTransaction 方法会起作用吗?
    • @leandrodemarco SCNTransaction 用于以原子方式对场景进行更改。它不必对可动画属性做任何事情(据我所知),例如,Apple 使用它从示例游戏中的父节点中删除节点。我还没有尝试将它与CAAnimations 一起使用,但我不明白为什么它不起作用。
    猜你喜欢
    • 2019-01-30
    • 1970-01-01
    • 2018-08-24
    • 2018-01-12
    • 2014-10-07
    • 2018-09-01
    • 2018-08-03
    • 2017-11-27
    • 2018-08-04
    相关资源
    最近更新 更多