4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Swift, ARKit]非推奨になったhitTestからraycastQueryに移行する

Posted at

iOS14が正式にリリースされました。
これに伴いARKitも3.5から4.0に移行しましたが、その中でARSCNViewに存在していた

open func hitTest(_ point: CGPoint, types: ARHitTestResult.ResultType) -> [ARHitTestResult]

という関数が非推奨(deprecated)となりました。

この関数の使いどころとしては、ARSCNView内に設置した3Dオブジェクトを移動させる時に、指先でなぞった場所の位置を取得することだと思います。
例えば以下のようなコードです。

@IBOutlet var scnView: ARSCNView!

override func viewDidLoad() {
    super.viewDidLoad()

    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(pan))
    self.scnView.addGestureRecognizer(panGesture)
}

@objc
func pan(_ sender: UIPanGestureRecognizer) {
    //こちらのhitTestは[SCNHitTestResult]を返すもので非推奨となった関数とは別もの
    guard let node = scnView.hitTest(sender.location(in: scnView), options: nil).first?.node else {
        return
    }
    //こちらが非推奨となった関数
    guard let transform = scnView.hitTest(sender.location(in: scnView), types: .existingPlaneUsingExtent).first?.worldTransform else {
        return
    }
    node.setWorldTransform(SCNMatrix4(transform))
}

コードによってはsenderのstateによってswitchしたり、guardではなくif letを使っていたりと多少の違いはあるかと思います。

これをraycastQueryに書き直すと以下のような形になります。

//変数宣言とviewDidLoad()は省略

@objc
func pan(_ sender: UIPanGestureRecognizer) {
    guard let node = scnView.hitTest(sender.location(in: scnView), options: nil).first?.node else {
        return
    }
    //変更したところ
    guard let raycast = scnView.raycastQuery(from: sender.location(in: scnView),
                                                  allowing: .estimatedPlane,
                                                  alignment: .any),
          let result = scnView.session.raycast(raycast).first? else {
        return
    }
    node.setWorldTransform(SCNMatrix4(result.transform))
}

ARSCNView本体から取得したARRaycastQueryを、今度はARSCNViewのsessionに送って、そこから[ARRaycastResult]を改めて取得しています。
ARSCNViewのタップ箇所をそのまま使うのではなく、間にsessionを挟んでいますね。

ARRaycastResult自体は変更は無いので、hitTestで取得した時と同じ使い方で問題ありません。

次にraycastQueryの中身を確認していきます。

open func raycastQuery(from point: CGPoint, allowing target: ARRaycastQuery.Target, alignment: ARRaycastQuery.TargetAlignment) -> ARRaycastQuery?

第一引数はそのままですね。
第二引数と第三引数はどちらもARRaycastQueryにあるenumです。

第二引数のenumはこちら。

public enum Target : Int {
    case existingPlaneGeometry = 0
    case existingPlaneInfinite = 1
    case estimatedPlane = 2
}

ポイントに存在するものが何なのかを判断するためのものです。
大きさの確定したPlaneが欲しい場合はexistingPlaneInfiniteを、大雑把でいいのならestimatedPlaneを選択します。

次は第三引数のenumについて。

public enum TargetAlignment : Int {
    case horizontal = 0
    case vertical = 1
    case any = 2
}

こちらは該当箇所が垂直なのか、水平なのか、どちらでも構わないのかという3つの選択肢を列挙しているものです。

第二引数と第三引数はどちらも新しく登場したものですが、hitTestで使っていたARHitTestResult.ResultTypeを分解し、組み合わせを自由にできるようになったと考えていいのではと思います。

hitTestは非推奨というだけなので使えるには使えるのですが、折を見て変更していきたいところです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?