ARKit - 与现实世界物体的碰撞

3

我需要使用ARKit检测虚拟物体何时与实际世界物体接触。

有什么方法能够找出来吗?

1个回答

3

首先,您需要创建一个碰撞类别结构体,符合 OptionSet 协议,并具有位集类型的属性:

import ARKit

struct Category: OptionSet {

    let rawValue: Int
    
    static let sphereCategory = Category(rawValue: 1 << 0)
    static let targetCategory = Category(rawValue: 1 << 1)
}

然后在生命周期方法中设置一个 物理代理(Physics Delegate)SCNPhysicsContactDelegate 协议:

class ViewController: UIViewController, SCNPhysicsContactDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        sceneView.scene = SCNScene()
        sceneView.scene.physicsWorld.contactDelegate = self

        let config = ARWorldTrackingConfiguration()
        config.planeDetection = [.horizontal]
        sceneView.session.run(config)
    }
}

SCNPhysicsContactDelegate 包含 3 个可选的 physicsWorld() 方法(稍后我们将使用第一个):

public protocol SCNPhysicsContactDelegate: NSObjectProtocol {
        
    optional func physicsWorld(_ world: SCNPhysicsWorld, 
                      didBegin contact: SCNPhysicsContact)

    optional func physicsWorld(_ world: SCNPhysicsWorld, 
                     didUpdate contact: SCNPhysicsContact)

    optional func physicsWorld(_ world: SCNPhysicsWorld, 
                        didEnd contact: SCNPhysicsContact)
}

接下来为球形碰撞器定义 categoryBitMaskcollisionBitMask

fileprivate func createSphere() -> SCNNode {

    var sphere = SCNNode()
    sphere.geometry = SCNSphere(radius: 0.1)

    sphere.physicsBody =  .init(type: .kinematic, 
                               shape: .init(geometry: sphere.geometry!, 
                                             options: nil))

    sphere.physicsBody?.isAffectedByGravity = true

    sphere.physicsBody?.categoryBitMask = Category.sphereCategory.rawValue
    sphere.physicsBody?.collisionBitMask = Category.targetCategory.rawValue
    sphere.physicsBody?.contactTestBitMask = Category.targetCategory.rawValue

    return sphere
}

...并且为实际检测到的平面定义反向位掩码:

fileprivate func visualizeDetectedPlane() -> SCNNode {

    var plane = SCNNode()
    plane.geometry = SCNPlane(width: 0.7, height: 0.7)

    plane.physicsBody =  .init(type: .kinematic, 
                              shape: .init(geometry: plane.geometry!, 
                                            options: nil))

    plane.physicsBody?.isAffectedByGravity = false

    plane.physicsBody?.categoryBitMask = Category.targetCategory.rawValue
    plane.physicsBody?.collisionBitMask = Category.sphereCategory.rawValue
    plane.physicsBody?.contactTestBitMask = Category.sphereCategory.rawValue

    return plane
}

只有当你将检测到的现实世界平面添加到SCN场景中,并将一个SCNSphere附加到SCNScene中时,才能使用physicsWorld(_:didBegin:)实例方法来检测碰撞。
func physicsWorld(_ world: SCNPhysicsWorld, 
         didBegin contact: SCNPhysicsContact) {

    if contact.nodeA.physicsBody?.categoryBitMask == 
                                          Category.targetCategory.rawValue |
       contact.nodeB.physicsBody?.categoryBitMask == 
                                          Category.targetCategory.rawValue {

        print("BOOM!")
    }
}

@KeyhanKamangar,看看这篇帖子-https://stackoverflow.com/questions/60191009/reality-composer-custom-collision-between-entities-of-different-scenes/60192226#60192226 - Andy Jazz
1
@AndyFedoroff 非常感谢。我检查了两个答案,但是我无法获得所需的结果。 我正在加载一个实体(.usdz),并尝试添加碰撞,以便它与现实世界中的物体(如墙壁或沙发)发生碰撞。 - Kawe
1
我检查了一下,但它仍然无法正常工作,模型可以穿过墙壁或其他物体。 - Kawe
1
不明白:是“工作中”还是“未工作”? - Andy Jazz
1
当然,你可以把这个作为一个问题发布,但是我目前没有时间回答任何问题。我的日程非常忙碌。 - Andy Jazz
显示剩余7条评论

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