首页 文章

iOS ARKit SceneKit物理接触检测缩放问题

提问于
浏览
2

我有一个简单的三维区域,包含4个墙,每个区域都是一个SCNNode,具有简单的SCNBox几何形状,矩形形状,并附有匹配的SCNPhysicsBody . SCNPhysicsBody使用SCNPhysicsShape.ShapeType.boundingBox,并设置为静态类型 . 这是一段代码:

let size = (self.levelNode.boundingBox.max - self.levelNode.boundingBox.min) * self.levelNode.scale

        //x //z
        let geometryA = SCNBox(width: CGFloat(size.x), height: CGFloat(1 * self.levelNode.scale.x), length: 0.01, chamferRadius: 0)
        let geometryB = SCNBox(width: CGFloat(size.z), height: CGFloat(1 * self.levelNode.scale.x), length: 0.01, chamferRadius: 0)

        geometryA.firstMaterial?.diffuse.contents = UIColor(red: 0.0, green: 0.2, blue: 1.0, alpha: 0.65)
        geometryB.firstMaterial?.diffuse.contents = UIColor(red: 0.0, green: 0.2, blue: 1.0, alpha: 0.65)


        let nodeA = SCNNode(geometry: geometryA)
        nodeA.position += self.levelNode.position
        nodeA.position += SCNVector3(0, 0.25 * self.levelNode.scale.y, -size.z/2)
        nodeA.name = "Boundary-01"

        let nodeB = SCNNode(geometry: geometryA)
        nodeB.position += self.levelNode.position
        nodeB.position += SCNVector3(0, 0.25 * self.levelNode.scale.y, size.z/2)
        nodeB.name = "Boundary-03"

        let nodeC = SCNNode(geometry: geometryB)
        nodeC.position += self.levelNode.position
        nodeC.position += SCNVector3(-size.x/2, 0.25 * self.levelNode.scale.y, 0)
        nodeC.eulerAngles = SCNVector3(0, -Float.pi/2, 0)
        nodeC.name = "Boundary-02"

        let nodeD = SCNNode(geometry: geometryB)
        nodeD.position += self.levelNode.position
        nodeD.position += SCNVector3(size.x/2, 0.25 * self.levelNode.scale.y, 0)
        nodeD.eulerAngles = SCNVector3(0, Float.pi/2, 0)
        nodeD.name = "Boundary-04"

        let nodes = [nodeA, nodeB, nodeC, nodeD]

        for node in nodes {
            //
            let shape = SCNPhysicsShape(geometry: node.geometry!, options: [
                SCNPhysicsShape.Option.type : SCNPhysicsShape.ShapeType.boundingBox])
            let body = SCNPhysicsBody(type: .static, shape: shape)
            node.physicsBody = body
            node.physicsBody?.isAffectedByGravity = false
            node.physicsBody?.categoryBitMask = Bitmask.boundary.rawValue
            node.physicsBody?.contactTestBitMask = Bitmask.edge.rawValue
            node.physicsBody?.collisionBitMask = 0

            scene.rootNode.addChildNode(node)
            node.physicsBody?.resetTransform()
        }

在这个区域内,我以固定的时间间隔产生实体 . 每个都有一个SCNBox几何体,这次是立方体形状,小于墙壁,并且物理体的参数与上面相同 .

为了简化我在这个游戏区域内的实体的行为,我正在计算他们的旅行路径,然后将SCNAction应用到相关节点来移动它们 . SCNAction移动连接到它的节点和物理主体 .

我正在使用SCNPhysicsWorld联系委托来检测实体到达其中一个边界墙的时间 . 然后,我从另一个方向的墙上计算出它的随机轨迹,清除它的动作,并应用新的SCNAction移动 .

这是有趣的地方......

当这个'世界'是1:1的比例 . 在标准SCNScene和使用ARKit投影的场景中检测到联系人正常 . 可见接触,即实体方向的可见变化似乎如预期的那样接近边界 . 当我检查每个联系人的contact.penetrationDistance时,他们的值是例如0.00294602662324905 .

但是,当我将这个'世界'的比例改为更小的东西,比如相当于10厘米宽,在ARKit中,模拟就会崩溃 .

当检测到接触时,实体和边界节点之间的接触在它们之间具有相对大的可见间隙 . 然而,contact.penetrationDistance与之前的幅度相同 .

我打开ARSCNView调试选项以在渲染中显示物理形状,它们看起来都是正确的比例,与其节点的边界框相匹配 .

从上面的代码示例中可以看出,在我的AR用户设置期间,在我缩放级别之后生成边界节点 . 它们被添加到场景的根节点,而不是作为级别节点的子节点 . 正在使用相同的代码生成实体 .

以前我曾尝试在物理主体上使用resetTransform()函数,但是在我缩放了水平之后,这并没有产生物理实体的可靠缩放,所以我决定在关卡后生成边界和实体的节点已经缩放 .

在Apple的文档中,它确实声明如果SCNPhysicsBody不是自定义形状,它将采用应用于它的节点几何的比例 . 在将缩放应用到关卡之后,我正在生成几何体及其各自的节点,因此我不受此影响 .

目前的一个假设是物理模拟在如此小的范围内分崩离析 . 但我并不是依靠模拟力来移动身体......

有没有更合适的方法来扩展物理世界?

或者,我正在盯着SCNPhysicsWorld中的一个错误,这是我无法控制的错误 .

我想到的一个解决方案是以1:1比例运行整个模拟但隐藏,然后将这些运动应用于较小的实体 . 可以想象,这会影响整个场景的表现......

1 回答

  • 0

    第一次接触的穿透距离是负值,表明存在间隙 . 当您缩小模拟的大小时,此间隙似乎不会按比例缩放 .

    作为解决上述问题的方法,我对联系代表中的联系人执行了额外检查,以便不对特定类别检测到第一个联系人,而是确保渗透距离值为正,从而确保两者之间存在重叠在触发与边界连接的实体的方向改变之前,这两个对象 .

相关问题