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

3

我有一个简单的3D区域,包含4面墙,每一面墙都是一个带有简单SCNBox几何体的SCNNode,呈矩形形状,并附加匹配的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接触代理来检测实体何时到达边界墙之一。然后,我从那面墙计算出一个随机轨迹,清除其动作,并应用新的move SCNAction。
这就是事情变得有趣的地方......
当此“世界”处于1:1比例时,在标准SCNScene和使用ARKit投影的场景中都可以正常检测到接触。即预期的实体方向可见接触点非常靠近边界。当我检查每个接触的contact.penetrationDistance值时,它们的值为例如0.00294602662324905。
但是当我将此“世界”的比例更改为更小的尺寸,例如在ARKit中相当于10cm宽度时,模拟就会崩溃。
实体与边界节点之间的接触在检测到时具有相对巨大的可见间隙。然而,contact.penetrationDistance的数量级与之前相同。
我打开了ARSCNView的调试选项以在渲染中显示物理形状,它们看起来都是正确的比例,与其节点的边界框相匹配。
从上面的代码示例中可以看出,在我缩放级别期间,边界节点是在我的AR用户设置之后生成的。它们添加到场景的根节点中,而不是级别节点的子节点。使用相同的代码来生成实体。
以前,我尝试在物理体上使用resetTransform()函数,但这并没有产生可靠的物理体缩放效果,因此我决定在缩放级别之后生成边界和实体的节点。
在苹果的文档中,确实指出如果SCNPhysicsBody不是自定义形状,则它将采用应用于它的节点几何体的比例。我不受此影响,因为我是在缩放应用于级别之后生成几何体及其各自的节点。
目前的假设之一是物理模拟在如此小的比例下崩溃。但是,我不依赖于力的模拟来移动物体......
是否有更适合缩放物理世界的方法?
或者,我正在面对SCNPhysicsWorld中的一个错误,这是目前无法控制的Bug。
我曾经想过的一个解决方案是以1:1比例运行整个模拟,但隐藏它,然后将那些动作应用到较小的实体上。正如您可以想象的那样,这将影响整个场景的性能...

你的意思是在节点已经创建并附加了SCNPhysicsBody后改变其比例尺度吗? - drewster
@drewster 我正在创建我想要的节点比例,然后将物理体应用于它们,最后将它们添加到场景中。在上面的代码中,对于我的边界,我正在使用其边界框最小值和最大值计算级别的大小,并应用其比例,因为它在场景中。 - nightbird
1个回答

1

第一个接触的穿透距离为负值,表明存在间隙。这个间隙似乎不会随着模拟尺寸的缩小而缩小。

为了解决上述问题,我在联系代表中实施了额外的检查,以确保不是针对特定类别检测到的第一个接触,而是确保穿透距离值为正,从而确保两个对象之间存在重叠,然后才触发与边界连接的实体方向的改变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接