SCENekit:未隐藏节点的问题

Posted

技术标签:

【中文标题】SCENekit:未隐藏节点的问题【英文标题】:SCNkit: Issues with unhidden nodes 【发布时间】:2020-06-03 05:49:04 【问题描述】:

我正在创建一个以洞穴为主要环境的 3-D 游戏。洞穴由大量环形段组成,一个连接另一个,因此形成了一个目前很小的隧道系统。

如果玩家在洞穴内,则只有一小部分片段可见。我认为实际上隐藏不可见的部分可以节省大量的 gpu 时间,我需要其他对象,如建筑物或敌人。

所以我首先尝试做的是隐藏整个洞穴,然后通过将“node.isHidden”设置为真和假来取消隐藏可见部分。 通过它们的名称找到和访问特定的节点:“Node.childnode (withName: „XYZ003“, recursively: false).isHidden = true”(或 false)。

它可以在段不隐藏的情况下工作,但是一旦我尝试隐藏以前未隐藏的段,渲染器就会崩溃并出现 EXC_BAD_ACCESS。

对隐藏的对象进行隐藏(当然没用,但有助于理解问题)很好,取消隐藏未隐藏的片段也是如此。

根据另一个线程的提示,我将例程移到渲染器委托中,因此不会在错误的时间进行切换,而是在应该发生此类更改的阶段进行,但这没有帮助。 作为替代方案,我通过 SCNActions 进行了隐藏(和取消隐藏),但我收到了相同的结果,这真的让我感到困惑,因为这将是一种“官方方式”......

我还使用了“递归”布尔值,得到了相同的结果(适用于取消隐藏,在 isHidden = true 时崩溃)。

然后我尝试更改节点的不透明度或其他属性——效果很好。另一方面,尝试从父节点中删除节点也会导致上述崩溃。

我需要它来工作,因为旧硬件永远无法处理数千个节点(尝试这个,帧速率下降到 10fps,即使周围没有敌人)。一旦敌人出现,更新的硬件可能会崩溃......

我的想法是指针在某种程度上被第一次取消隐藏(以及因此 BAD_ACCESS 错误)弄乱了,所以可能是额外的绑定(通常在 spritekit-routines 中看到)或其他获取节点指针的方法可能是解决方案。另一方面,如果指针坏了,为什么我仍然可以访问所有其他属性?也许是子节点导致了问题 - 每个节点都有 20 个子节点,它们也应该改变可见性。

在我之前有没有人遇到过这种行为?我在谷歌搜索期间找不到任何东西......

【问题讨论】:

【参考方案1】:

经常隐藏和取消隐藏节点本身通常不是问题。您可以隐藏一个主节点,主节点的任何子节点都会自动隐藏,因此您不必单独循环它们。

我不是调试专家,也不知道您的技能水平,但 BAD_ACCESS 可能意味着您尝试将消息发送到无法执行消息的内存块,或者应用程序尝试延迟损坏的指针。搜索“什么是 EXC_BAD_ACCESS 以及如何调试它”以获取有关处理它的一些选项的体面教程。

我也在渲染委托中进行更改,但根据更改的数量和所需的时间,我有时会使用计时器来控制在一定时间内可以进行的更改量。这样一来,经过一些调整,我很确定我不会让它陷入失控的地步。

结构可能很重要 - 个人喜好,但我尝试设置一组类来创建单个节点(和子节点),因此可以直接访问它们。这样我就不会遍历整个节点结构或按名称查找节点。有时在我真的必须对节点本身进行修改之前发生了很多事情,因此我可以在采取涉及显示的操作之前遍历我的类数组、检查值、比较等。这也让我有机会在需要移除节点时移除粒子系统、移除动作、设置 geometry = nil 并更新逻辑计数器。

我确信意见会有所不同,但这对我来说效果很好。一旦我标准化了结构,我就会不断重复这个模式。

希望有帮助

【讨论】:

感谢您的快速回答。我描述的环段实际上由 1 个父节点和另外 20 个子节点组成,正如您提到的,当父节点切换时,它们应该关闭和打开。关于更改的持续时间 - 我尝试在渲染器委托阶段的一开始就关闭,没有其他事情可以遵循,所以时间不应该是问题。但又一次,应用程序崩溃了。 另外,我昨天已经尝试了你顺便引用的参考,我遇到了一些奇怪的行为 - 似乎我必须做比我想象的更多的调试 - 但我找不到解决方案.只有我了解可能损坏的指针或内存块。但那应该怎么做?环形显示并在几秒钟后再次隐藏,中间没有任何事情发生 - 节点没有其他变化...... 是的,不看代码就很难说。您可能会尝试查看泄漏,只是为了看看是否有大的东西伸出来。如果没有,请尝试移动节点——让它静置几秒钟,然后移动它一次——不要隐藏它,让它运行一会儿。如果移动仍然崩溃,请添加一个不同的节点并获取洞穴的东西 - 只是一个没有结构的不可见节点,以确保它不在您的子节点或图形内容中。是的,到达这里,但有时只是采用最简单的模式并建立备份。 我想我会试试你的建议。但更重要的是,我对将洞穴固定到特定数组而不是按名称搜索的想法感兴趣。我从来没有非常喜欢以这种相对的方式来做这件事的想法。还应该节省一些处理时间 - 不必创建要查找的名称字符串并避免搜索......另一方面,这将是一个巨大的数组...... 所以我将洞穴数据存储在一个数组中,现在更好了。它确实有效!但我认为这不是因为节点的直接访问......而是我发现之前,我在添加其他子节点(很多)之前隐藏了父节点。然后,关闭和打开它们可能对引擎来说太多了......当我将数组作为存储时,我将父隐藏的位置更改为子组的末尾。

以上是关于SCENekit:未隐藏节点的问题的主要内容,如果未能解决你的问题,请参考以下文章

SceneKit:关于定位相机节点的数学问题

SceneKit 节点的交集

在 SceneKit 节点周围添加边框

未检测到 SceneKit 碰撞检测

Scenekit:如何获取节点的所有材质?

在 viewDidLoad 期间应用的 SceneKit 节点旋转无效