【问题标题】:Scenekit - physicsWorld setup to prevent kinematic nodes to intersectScenekit - 物理世界设置以防止运动学节点相交
【发布时间】:2023-03-05 22:45:01
【问题描述】:

我的场景中有几个节点可以旋转和拖动。我已经设置了一个physicsWorld 委托,将类型为kinematic 的physicsBody 添加到我的节点并检查physicsWorld didBeginContact - 到目前为止一切正常,当我移动节点时,接触开始/结束触发。

我试图处理这个问题的方法是设置一个 bool var,一旦联系人开始阻止进一步移动,它就会变为 true,但我遇到了一些情况(特别是如果我将节点拖得太快),那该节点在另一个对象内部有点。

我应该使用不同的方法吗?我真的不想要碰撞,只是让另一个节点“稳定”地行动,即使在高速接触时也不允许交叉。

编辑:

一些示例图像以进一步阐明问题:

为简单起见,我只添加了 2 个节点来演示该问题。第一个图像是初始位置,第二个和第三个(侧视图)是在一个非常快速的向右平移之后。只有在节点已经相交后才会触发接触检测。

我尝试过的一种方法是在触发接触之前抓取最后一个位置,并在检测到接触后重置节点位置,但结果非常不稳定且不稳定,有时您有时会看到之前的对象相交跳到最后一个“好”的位置。我觉得必须有一些更简单的方法来实现这一点,但是在花费数小时浏览可用资源之后,我无法弄清楚。

编辑 2

进一步的研究指出了扫描测试的路线,从技术上讲,如果我可以在移动节点之前检测到可能的碰撞,我应该能够在交叉发生之前限制移动停止

更新:另一个死胡同,正如 Xcode 指出的那样

Error: convexSweep only works with convex shapes

【问题讨论】:

    标签: ios swift scenekit


    【解决方案1】:

    经过很多天的头撞和几乎放弃,我重新重新阅读了physicsWorld文档,终于找到了我一直忽略的东西 - 可以随时手动触发的contactTest方法,独立于渲染环形。我在渲染器(_:willRenderScene:atTime:) 中使用它,以便在渲染场景之前“修复”重叠。

    我的场景比示例复杂一些,但是我几乎可以在几个额外的 tweek 中使用它。我不确定这是否是正确的解决方案,以及它在性能方面的成本会有多高,但现在我会安定下来,这样我就可以继续开发了。

    如果有人在类似情况下运行的相关代码:

    func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
    
        // make sure we have active node and pan direction
        if(selectedBrickNode != nil && self.panDirection != nil){
    
            // contactTest
            let pw = scnScene.physicsWorld
            let node = selectedBrickNode.node!
            let contacts = pw.contactTest(with: node.physicsBody!, options: nil)
    
            var axisVector:SCNVector3
            // specify which axis we want to correct
            switch self.panDirection!{
                case "right","left": axisVector = SCNVector3Make(1,0,0)
                default: axisVector = SCNVector3Make(0,1,0);
            }
    
            for contact in contacts {
                // round contact normal to get a unit vector
                let cn = SCNVector3( round(contact.contactNormal.x),
                                     round(contact.contactNormal.y),
                                     round(contact.contactNormal.z))
    
                // fix only for pan direction axis
                if abs(cn.x) == axisVector.x && abs(cn.y)==axisVector.y  {
                    let normal = contact.contactNormal
                    let transform = SCNMatrix4MakeTranslation( round(normal.x) * -Float(contact.penetrationDistance),
                                                round(normal.y) * -Float(contact.penetrationDistance),
                                                round(normal.z) * -Float(contact.penetrationDistance))
                    node.transform = SCNMatrix4Mult(node.transform, transform)
                    // break to prevent repeated contacts 
                    break;
                }
    
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-21
      • 1970-01-01
      • 2018-06-04
      • 2018-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-30
      • 1970-01-01
      相关资源
      最近更新 更多