ARオブジェクトにさわれたらいいと思いませんか?
【ARをさわる】VisionとRealityKitで指が触れたARオブジェクトを反応させられます。
まずはVisionで指先の位置を取得します。
import Vision
import RealityKit
...
var handPoseRequest = VNDetectHumanHandPoseRequest(completionHandler: handDetectionCompletionHandler)
// 手のポイントを取得してくれるリクエスト
// CompletionHandler内で結果を処理します
...
func session(_ session: ARSession, didUpdate frame: ARFrame) {
let pixelBuffer = frame.capturedImage
// ARSessionで取得したフレームでVisionリクエストを実行
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let handler = VNImageRequestHandler(cvPixelBuffer:pixelBuffer, orientation: .up, options: [:])
do {
try handler.perform([(self?.request)!])
} catch let error {
print(error)
}
}
}
取得した指先の位置でヒットテストをし、ARオブジェクトを検出します。
ARViewはView上のポイントの延長線上にあるエンティティを検出できます。
func handDetectionCompletionHandler(request: VNRequest?, error: Error?) {
// リクエストの結果から、人差し指の先の位置を取得する
guard let observation = request?.results?.first as? VNHumanHandPoseObservation else { return }
guard let indexFingerTip = try? observation.recognizedPoints(.all)[.indexTip],
indexFingerTip.confidence > 0.3 else {return}
// Visionの結果は0~1に正規化されているので、ARViewの座標に変換する
let normalizedIndexPoint = VNImagePointForNormalizedPoint(CGPoint(x: indexFingerTip.location.y, y: indexFingerTip.location.x), viewWidth, viewHeight)
// 取得した指先の座標でヒットテストを実施
if let entity = arView.entity(at: normalizedIndexPoint) as? ModelEntity {
// 見つけたボックス・オブジェクトに物理的な力を加える
entity.addForce([0,40,0], relativeTo: nil)
// addForceするには、対象のエンティティにPhysicsBodyComponentを与えてください
}
}
ヒットテストで検出するエンティティにはコリジョン(衝突)シェイプが必要です。
let box = ModelEntity(mesh: .generateBox(size: 0.05), materials: [SimpleMaterial(color: .white, isMetallic: true)])
box.generateCollisionShapes(recursive: false)
GitHubのサンプルコード:RealityKit-Sampler
手のポイントの取得について:VisionでHand Pose Detection 手のトラッキング: MLBoyだいすけ
ARオブジェクトの作り方など、RealityKitの取り扱いについて:RealityKitの参考書