OGeek|极客世界-中国程序员成长平台

标题: iOS ARKit + SceneKit 物理接触检测缩放问题 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-11 20:00
标题: iOS ARKit + SceneKit 物理接触检测缩放问题

我有一个简单的 3d 区域,其中包含 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 联系人代理来检测实体何时到达边界墙之一。然后我从那堵墙上计算出它在另一个方向上的随机轨迹,清除它的 Action ,并应用一个新的移动 SCNAction。

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

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

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

实体和边界节点之间的接触在检测到接触时,它们之间存在较大的可见间隙。然而,contact.penetrationDistance 的大小与以前相同。

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

从上面的代码示例中可以看出,边界节点是在我缩放关卡后生成的,在我的 AR 用户设置过程中。它们被添加到场景的根节点,而不是作为关卡节点的子节点。相同的代码被用于生成实体。

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

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

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

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

或者,我是否正在盯着 SCNPhysicsWorld 中的错误,目前这是我无法控制的。

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



Best Answer-推荐答案


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

作为解决上述过量问题的一种方法,我在 Contact Delegate 中对联系人进行了额外检查,以不获取为特定类别检测到的第一个联系人,而是确保穿透距离值为正,因此确保存在是两个对象之间的重叠,然后触发与边界连接的实体的方向变化。

关于iOS ARKit + SceneKit 物理接触检测缩放问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49771646/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://ogeek.cn/) Powered by Discuz! X3.4