设置 scnnode 呈现位置

setting scnnode presentation position

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

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

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

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

  2. 使用resetTransform():

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

    什么都不做。文档说 "Updates the position and orientation of a body in the physics simulation to match that of the node to which the body is attached"。但它没有改变。不清楚为什么!

  3. 设置时移除physicsBody:

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

    这将表示变换设置为 newVal ("yea!"),但 Physics 不起作用 ("boo!").也许一个人不能重复使用物理学 body.

  4. 设置后添加新物理body:

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

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

想法?

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

我开始注意到这个问题在 iOS 11 间歇性地发生,当时我的项目中的所有内容在 iOS 10 上运行良好。我没有触及 SCNAnimation 或类似的东西 -我有自己的动画系统,所以我只是每隔 renderer(_:, updateAtTime:).

更新节点的 .position

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

就我个人而言,我正在慢慢努力在我的项目中放弃 SceneKit — 我主要切换到自定义 Metal 着色器,然后我会做我自己的场景渲染循环,最终我会替换场景图和 SCNNode 用法让我对 SceneKit 的错误混乱零依赖。

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

更新: 我最终“修复”了我的演示节点的错误行为,方法是使用一个肮脏的 hack,在每帧节点的位置上添加少量的“摆动”:

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 进行一些 batching/rendering 优化,并且(以我的经验)会导致性能下降。这是一个可怕的 hacky 解决方法,仅用于最坏的情况 (“客户说我们必须在本周上线游戏,否则我们就得不到报酬,现在这个愚蠢的 SceneKit 错误? !”)

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

我在使用 ARKit 时遇到了同样的问题。因为 physicsBody 根据呈现节点而不是节点本身调整自身,并且因为当您更改节点的变换时呈现节点不会立即更新,所以您获得的 physicsBody 可能很奇怪。

我最近找到了一种解决方案:

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

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

综上所述,当改变节点的变换时,运行一个动作,当改变节点的子变换时,直接设置变换。