我需要用ARKit检测虚拟物体与现实世界物体接触的时间。
有什么方法可以检测出来吗?
首先,你需要创建一个符合以下条件的碰撞类别结构。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.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)
}
在这之后定义 categoryBitMask
和 collisionBitMask
为球体对撞机。
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!")
}
}