ARKit - 与真实世界对象的碰撞

问题描述 投票:3回答:1

我需要用ARKit检测虚拟物体与现实世界物体接触的时间。

有什么方法可以检测出来吗?

swift augmented-reality scenekit arkit
1个回答
2
投票

首先,你需要创建一个符合以下条件的碰撞类别结构。OptionSet 协议,并具有比特组类型的属性。

import ARKit

struct Category: OptionSet {

    let rawValue: Int

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

然后设置一个 physics delegateSCNPhysicsContactDelegate 生命周期方法里面的协议。

class ViewController: UIViewController, SCNPhysicsContactDelegate {

    @IBOutlet var sceneView: ARSCNView!

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

        sceneView.scene.physicsWorld.contactDelegate = self

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

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

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 = SCNPhysicsBody(type: .dynamic, shape: nil)
    sphere.physicsBody?.isAffectedByGravity = true

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

    return sphere
}

...并为真实世界检测到的平面定义相反顺序的位面具。

fileprivate func visualizeDetectedPlane() -> SCNNode {

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

    plane.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
    plane.physicsBody?.isAffectedByGravity = false

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

    return plane
}

只有当你把你的SCNPlanes添加到现实世界的检测平面上 并把一个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!")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.