【问题标题】:setting scnnode presentation position设置scnnode展示位置
【发布时间】:2018-12-29 14:41:15
【问题描述】:

我想将给定的scn:SCNNode 其当前表示节点的转换设置为新值。但是,我在设置演示节点时遇到了麻烦。我尝试了四种方法:

  1. 设置表示节点的变换:

    scn.position              = newVal
    scn.presentation.position = newVal
    

    scn.presentation.transform只读 -- 不能设置。 (顺便说一句,设置表示节点的转换编译没有错误,也许需要清理)

  2. 使用resetTransform():

    scn.position              = newVal
    scn.physicsBody.resetTransform()
    

    什么都不做。文档说它“更新物理模拟中身体的位置和方向以匹配身体所连接的节点的位置和方向”。但它没有改变。不清楚为什么!

  3. 设置时移除physicsBody:

    let pb                  = scn.physicsBody
    scn.physicsBody         = nil
    scn.position            = newVal
    scn.physicsBody         = pb
    

    这会将演示转换设置为 newVal(“是的!”),但物理不起作用(“嘘!”)。也许不能重复使用物理体。

  4. 设置后添加新的物理体:

    scn.position            = newVal
    scn.physicsBody         = SCNPhysicsBody(type:.dynamic, shape:nil)
    

    可惜,scn.presentation.position 没有 newVal。

想法?

【问题讨论】:

  • 我已经了解了一个基本事实,即您不应该更改演示节点中的任何内容。根据第 2 项:resetTransform() 似乎只有在当前线程退出后才会生效。

标签: swift core-animation scenekit


【解决方案1】:

我在使用 SceneKit 的项目中也注意到了这一点。您的问题的直接答案是:“表示节点会自动更新其变换以匹配场景节点的变换。如果它似乎没有更新,请确保场景节点的 isPaused 设置为 false。” 但是,您的场景节点可能未暂停和/或您没有使用动画,但是这个问题发生了。

当我的项目在 iOS 10 上运行良好时,我开始注意到这个问题在 iOS 11 上间歇性发生。我没有接触过SCNAnimations 或类似的东西——我有自己的动画系统,所以我只是更新了我的节点的.position 每个renderer(_:, updateAtTime:)

所以 AFAICT,这里的问题不是你正在做的任何事情——问题是 SceneKit 一直有问题并且写得不好(API 的某些部分还没有针对 Swift 完全更新) ,并且可能仍然存在错误和编写不佳,因为 SceneKit 团队似乎已经完全转向了 ARKit 的工作。因此,您的问题的解决方案似乎是“只是尝试一堆东西,设置.position 的频率比必要的频率更高,或者在更新循环中的不同时间,或者似乎有效的真正hack-y 解决方案 -围绕 SceneKit 中的问题”

就我个人而言,我正在慢慢努力在我的项目中放弃 SceneKit — 我主要切换到自定义金属着色器,然后我将执行我自己的场景渲染循环,最终我将替换场景图表和SCNNode 的使用让我对SceneKit 的混乱局面零依赖。

我希望我有更好的消息告诉你,但我已经处理 SceneKit 的怪异已经 2 年了。这是未完成的垃圾。

更新:我最终“修复”了我的演示节点行为不端,使用了一种肮脏的技巧,每帧都会在节点的位置上添加少量的“摆动”:

public func updateNode()
{
    let wigglePositionValue = SCNVector3(
        x: Float.random(in: -0.00001...0.0001),
        y: Float.random(in: -0.00001...0.0001),
        z: Float.random(in: -0.00001...0.0001)
    )
    self.scnNode.position = _locationModel.value + wigglePositionValue
}

旁注:正如预期的那样,像这样“抖动”节点位置也不允许 SceneKit 进行一些批处理/渲染优化,并且(根据我的经验)会导致性能下降。这是一个可怕的 hacky 解决方法,仅适用于最坏的情况(“客户说我们必须在本周上线游戏,否则我们不会得到报酬,现在这个愚蠢的 SceneKit 错误?!” )

所以是的……这里真正的解决方案是“不要使用 SceneKit”。

【讨论】:

  • 您关于“只是尝试一堆东西”的评论是我所做的。我想我在查看演示文稿之前欺骗了它进行另一个渲染周期并且做到了。您对转向 ARKit 的团队很伤心,但不幸的是,课程标准。swizzy 演示优先于去年套件的持续支持。:( 也是。
  • @AllenKing 我很好奇你的解决方案(“欺骗它通过另一个渲染周期”)需要什么。由于这个原因和其他原因,我目前正在逐步淘汰对 SceneKit 的使用,但我希望能够一次替换一个功能(首先,自定义着色器,下一个自定义渲染管道,然后是场景图和更新/渲染循环),所以暂时能够欺骗 SceneKit 的更新系统对我很有用。
  • 那段时间我有几个 SceneKit 的 bug 同时在咬我,而且我的速度很快,所以我的内存有限:在重新定位例程中,我设置了 scn.position,做了一个resetTransform,并在日志中打印它没有占用。然后,在外循环中,我再次执行了整个重新定位程序,并且完成了。有趣的是,这两个重新定位都是在创建 SCNScene 之后立即完成的,它是 rootNode、physicsWorld 和physicsBodies,在通过我的 SCNSceneRenderer 委托之前进行。
【解决方案2】:

我在使用 ARKit 时遇到了同样的问题。因为physicsBody是根据presentation node而不是node自身来调整自己的,并且因为presentation node在你改变node的transform时不会立即更新,所以你得到的physicsBody可能会很奇怪。

我最近找到了一个解决方案

要更改表示节点的变换,请使用 SCNAction。例如,如果要设置位置,请使用node.runAction(SCNAction.move(by: SCNVector3, duration: 0)) 而不是简单的node.position = SCNVector3。这样一来,表示节点会立即更新,您会得到正确的物理结果。

此外,这种方法仅适用于节点本身(不适用于子节点)。所以如果您对节点的子节点运行操作,您仍然无法获得正确的表示节点和物理。要更改子节点的变换和表示变换,请使用node.position = SCNVector3 方法。

总结一下,当改变节点的transform时,运行一个动作,当改变节点的children的transform时,直接设置transform。

【讨论】:

    猜你喜欢
    • 2019-05-02
    • 2018-09-24
    • 1970-01-01
    • 2018-05-18
    • 2017-04-15
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    相关资源
    最近更新 更多