繁体   English   中英

Scenekit-PhysicsWorld设置可防止运动学节点相交

[英]Scenekit - physicsWorld setup to prevent kinematic nodes to intersect

我的场景中有几个节点可以旋转和拖动。 我已经建立了physicsWorld委托,将kinematic类型的PhysicsBody添加到我的节点,并检查physicsWorld didBeginContact-至此,一切正常,当我移动节点时,联系人开始/结束触发。

我尝试处理此问题的方法是将布尔变量设置为在接触开始后就更改为true以防止进一步移动,但是我遇到了一些情况(尤其是如果我将节点拖动得太快),则该节点会在另一个对象的内部。

我应该使用其他方法吗? 我真的不想要碰撞,只是另一个节点表现为“实体”,即使在高速接触时也不允许相交。

编辑:

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

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

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

编辑2

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

更新: Xcode指出了另一个死胡同

Error: convexSweep only works with convex shapes

经过数天的猛烈抨击并几乎放弃了,我重新阅读了PhysicsWorld文档,终于找到了我一直无视的东西-contactTest方法,可以随时手动触发,而与渲染循环无关。 我在renderer(_:willRenderScene:atTime :)中使用它,以便在渲染场景之前“修复”重叠。

我的场景比示例中要复杂一些,但是经过几个星期的时间,我几乎可以正常工作了。 我不确定这是否是正确的解决方案,以及它在性能方面的成本有多高,但现在我将对此付诸实践,以便继续进行开发。

万一有人在类似情况下运行时的相关代码:

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;
            }

        }

    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM