首页 文章

当新节点变得可见时,SceneKit 应用程序会断断续续

提问于
浏览
3

即使应用程序在前后 60 fps 平稳运行,当新节点出现在屏幕上时,我的 SceneKit 应用程序(使用 Metal)也会出现问题。

想象一下,游戏中的东西被破坏,有时出现在被破坏的地方。我很确定口吃与 power-ups 的出现有关,因为当事物被摧毁(因此从场景中移除)时它不会发生。

到目前为止我尝试修复口吃:我通过 SceneKit 视图的预加载方法预加载节点,并仅在其完成处理程序中将它们添加到场景中。我需要在它们需要显示之前将它们添加到相机上方,当我将它们移动到正确的位置时。我已经实现了一个排队机制,以确保每帧只进行一次更改(删除被破坏的项目的节点,在其位置移动 power-up)。

但是当 power-ups 出现时,有时(并非总是)出现口吃。我想知道 SceneKit 是否仅在第一次出现节点时才做某事(即使它们已被预加载)。无论发生什么事情似乎都足以导致口吃,但 XCode 性能表太短以至于无法显示。每一帧都有充足的空闲时间,CPU 和 GPU 永远不会接近最大化。

我不认为这个问题与复杂的几何形状或巨大的纹理有关,因为当我使用具有均匀颜色的简单立方体时,它仍然会发生。

知道这里发生了什么,或者我如何追踪它?

1 回答

  • 2

    我自己找到了原因,我想与你们分享,以防你遇到同样的问题。

    SceneKit 在幕后做的神秘任务是重新编译各个节点的着色器。虽然 Apple 没有证实这一点,但我很确定 SceneKit 有一个策略,即始终使用最有效的着色器,这些着色器足够复杂,可以按预期呈现相应的节点。这意味着无论何时添加效果,材质属性或光源,它都会编译更复杂的着色器。当您消除了增加照明计算复杂性的原因时,它将使用更简单的着色器再次替换它。

    虽然这对于始终获得最高性能而言非常好,但它也有一个缺点,这是我所经历的。重新编译着色器需要一些时间,导致 CPU 上的负载并迫使 GPU 等待新版本的着色器。最后,它会导致应用程序断断续续,即使它们在大多数情况下都运行得非常流畅。

    解决这个问题的最简单方法是用你自己的代码(使用 SCNProgram)替换 SceneKit 着色器,但这也会让你失去 SceneKit 提供的大部分舒适感。由于这不是我想要的,我最终采用了以下方法:

    我强制 SceneKit 初始编译所有可能在以后看到的节点的着色器,方法是在开始时用黑色覆盖覆盖场景,在摄像机前面添加所有节点,然后在淡出封面之前将它们移动到正确的位置层。我还避免重新编译,因为永远不会完全关闭我不需要的效果(e.g. 通过将亮度更改为 0.1 而不是 0 来关闭灯光)。这使得 SceneKit 始终保持相同的着色器,从而避免了口吃。

    再说一遍:这还没有得到 Apple 的证实,但到目前为止一直有效,所以我认为我的假设是正确的; -)。

相关问题