找出 SCNNode 何时从 SCNScene 中消失
Find out when SCNNode disappears from SCNScene
从场景中移除 SCNNode 时是否会调用特定方法?
-(void)removeFromParentNode;
不会在 SCNNode 对象上调用。
设置场景
我正在利用重力向下拉一个物体。当一个对象向下移动太远时,它会自动消失并且绘制调用和多边形计数会减少。所以 SCNNode 肯定被销毁了,但是有什么方法可以挂钩销毁吗?
如果你的物体比你的活动相机的 ZFar 属性 更远,它就会消失。 (默认值为 100.0)
正如 David Rönnqvist 在评论中所说,您的节点没有被破坏,您仍然可以修改它的 属性.
如果你想连接到你的节点的几何消失,你可以计算你的活动相机和你的节点之间的距离,并在你的渲染循环中检查它的每一帧,如果它大于 100 就会触发一个动作。
如果你想在更远的距离渲染你的节点,你可以只修改你的相机的ZFar 属性。
其他答案已经很好地涵盖了这一点,但更进一步:
首先,您的节点并没有从场景中移除——它的内容正在传递到相机的视锥之外,这意味着 SceneKit 知道它不需要向 GPU 发出绘制调用来渲染它。如果您 enumerate the child nodes 场景(或包含您正在谈论的节点的任何父级),您会看到它们仍然存在。您失去了一些 渲染 性能成本,因为 SceneKit 不需要为它知道在帧中不可见的东西发出绘制调用。
(如 Tanguy 的回答所述,这可能是因为您的 zFar
设置。也可能不是——这取决于节点从相机中掉出的方向。)
但是,如果您继续添加节点并让物理将它们从屏幕上删除,您将累积 预渲染 性能成本,因为 SceneKit 必须每隔一段时间遍历场景图框架并找出需要为哪些节点发出绘图调用。这个成本对于每个节点来说都非常小,但它最终可能会增加一些你不想处理的东西。
并且由于您无论如何都希望在节点脱离框架时发生某些事情,因此您只需要找到一个很好的机会来处理它并清理消失的节点。
那么在哪里做呢?嗯,你有几个选择。如前所述,您可以在渲染循环中放入一些东西来检查每个节点在每一帧上的可见性:
- (void)renderer:(id<SCNSceneRenderer>)renderer didSimulatePhysicsAtTime:(NSTimeInterval)time {
if (![renderer isNodeInsideFrustum:myNode withPointOfView:renderer.pointOfView]) {
// it's gone, remove it from scene
}
}
但是在每一帧上进行 运行 的检查有点昂贵(请记住,您在这里的目标是 30 或 60 fps)。更好的方法可能是让物理系统帮助你:
- 创建一个具有
SCNBox
几何体的节点,该几何体足以 "catch" 从屏幕上掉下来的所有东西。
- 给该节点一个静态物理体,并设置类别和碰撞位掩码,以便您的下落节点与其发生碰撞。
- 将该节点放置在视锥之外,以便您的坠落物体在从视野中掉落后立即撞击它。
实现一个联系人委托方法来销毁掉落的节点:
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact {
if (/* sort out which node is which */) {
[fallingNode removeFromParentNode];
// ... and do whatever else you want to do when it falls offscreen.
}
}
从场景中移除 SCNNode 时是否会调用特定方法?
-(void)removeFromParentNode;
不会在 SCNNode 对象上调用。
设置场景
我正在利用重力向下拉一个物体。当一个对象向下移动太远时,它会自动消失并且绘制调用和多边形计数会减少。所以 SCNNode 肯定被销毁了,但是有什么方法可以挂钩销毁吗?
如果你的物体比你的活动相机的 ZFar 属性 更远,它就会消失。 (默认值为 100.0) 正如 David Rönnqvist 在评论中所说,您的节点没有被破坏,您仍然可以修改它的 属性.
如果你想连接到你的节点的几何消失,你可以计算你的活动相机和你的节点之间的距离,并在你的渲染循环中检查它的每一帧,如果它大于 100 就会触发一个动作。
如果你想在更远的距离渲染你的节点,你可以只修改你的相机的ZFar 属性。
其他答案已经很好地涵盖了这一点,但更进一步:
首先,您的节点并没有从场景中移除——它的内容正在传递到相机的视锥之外,这意味着 SceneKit 知道它不需要向 GPU 发出绘制调用来渲染它。如果您 enumerate the child nodes 场景(或包含您正在谈论的节点的任何父级),您会看到它们仍然存在。您失去了一些 渲染 性能成本,因为 SceneKit 不需要为它知道在帧中不可见的东西发出绘制调用。
(如 Tanguy 的回答所述,这可能是因为您的 zFar
设置。也可能不是——这取决于节点从相机中掉出的方向。)
但是,如果您继续添加节点并让物理将它们从屏幕上删除,您将累积 预渲染 性能成本,因为 SceneKit 必须每隔一段时间遍历场景图框架并找出需要为哪些节点发出绘图调用。这个成本对于每个节点来说都非常小,但它最终可能会增加一些你不想处理的东西。
并且由于您无论如何都希望在节点脱离框架时发生某些事情,因此您只需要找到一个很好的机会来处理它并清理消失的节点。
那么在哪里做呢?嗯,你有几个选择。如前所述,您可以在渲染循环中放入一些东西来检查每个节点在每一帧上的可见性:
- (void)renderer:(id<SCNSceneRenderer>)renderer didSimulatePhysicsAtTime:(NSTimeInterval)time {
if (![renderer isNodeInsideFrustum:myNode withPointOfView:renderer.pointOfView]) {
// it's gone, remove it from scene
}
}
但是在每一帧上进行 运行 的检查有点昂贵(请记住,您在这里的目标是 30 或 60 fps)。更好的方法可能是让物理系统帮助你:
- 创建一个具有
SCNBox
几何体的节点,该几何体足以 "catch" 从屏幕上掉下来的所有东西。 - 给该节点一个静态物理体,并设置类别和碰撞位掩码,以便您的下落节点与其发生碰撞。
- 将该节点放置在视锥之外,以便您的坠落物体在从视野中掉落后立即撞击它。
实现一个联系人委托方法来销毁掉落的节点:
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact { if (/* sort out which node is which */) { [fallingNode removeFromParentNode]; // ... and do whatever else you want to do when it falls offscreen. } }