【发布时间】:2022-01-23 20:49:11
【问题描述】:
我需要使用 ARKit 检测虚拟对象何时与现实世界对象接触。
有什么办法可以查到吗?
【问题讨论】:
标签: swift augmented-reality scenekit arkit
我需要使用 ARKit 检测虚拟对象何时与现实世界对象接触。
有什么办法可以查到吗?
【问题讨论】:
标签: swift augmented-reality scenekit arkit
首先你需要创建一个符合OptionSet协议并且具有bitset类型的属性的碰撞类别结构体:
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)
}
在此之后为球体对撞机定义categoryBitMask 和collisionBitMask:
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
}
只有当您将 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!")
}
}
【讨论】:
working 或 not working?