search
LoginSignup
14

More than 3 years have passed since last update.

posted at

updated at

Organization

ARKit(RealityKit)のはじめかた その4「オブジェクトを配置する(ARKit3版)」

はじめに

こちらの続きです▶︎ ARKitのはじめかた その3「オブジェクトを配置する(ARKit2版)」

こんにちは!
ARKitのまとめ記事 にて書いた実装方法について
最後はARKit3/RealityKitで使えるようになった「オブジェクト配置の方法」をReality ComposerではなくSwiftで書きます。
RealityKitを使う方法は今のところ使う場面が少ないのですが、今後使われるようになっていくと思います。(しかし公開されているナレッジは異常に少ないです。)

ゴール

タッチした場所に飛行機が出てきます。
iOS のファイル.gif

前提

ARKitのはじめかた その1「5分で出来るARアプリ」で作成した環境をベースとしますが、2つの追加対応が必要です。

①Xcodeの最新化

バージョン 備考
Xcode(Mac) 11.0以上 iOS13(ARKit3)対応にする必要があります。
iOS(iPhone/iPad) 13.0以上 iPhoneだと6s,SE以上、iPadだと第5世代以上が対象機。

②USDZファイルの準備
usdzファイルがなければ以下の手順で作成出来ます。

・Xcodeプロジェクト内のship.scnを選択した状態で、MenuのFile→Exportをクリック
・Universal Scene Description(Mobile)ファイル形式で保存
ARKitについて.png

コード

ViewController.swift
import UIKit
import RealityKit
import ARKit

class ViewController: UIViewController,ARSessionDelegate {

    @IBOutlet var arView: ARView!
    let rootAnchor = AnchorEntity()

    override func viewDidLoad() {
        super.viewDidLoad()

        arView.session.delegate = self

        let gesture = UITapGestureRecognizer(target: self, action:#selector(onTap))
        self.arView.addGestureRecognizer(gesture)
    }

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

        let configuration = ARWorldTrackingConfiguration()
        arView.session.run(configuration)
        arView.scene.addAnchor(rootAnchor)
    }

    @objc func onTap(sender: UITapGestureRecognizer) {

        let pos = sender.location(in: arView)
        let results = arView.hitTest(pos, types: .featurePoint)
        if !results.isEmpty {
            let anchor = ARAnchor(name:"shipAnchor",
                                  transform:results.first!.worldTransform)
            arView.session.add(anchor: anchor)
        }
    }


    // MARK: - ARSessionDelegate

     func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        for anchor in anchors {
            if anchor.name == "shipAnchor" {
                guard let shipModel = try? Entity.load(named: "art.scnassets/ship") else {return}
                shipModel.position = simd_make_float3(
                    anchor.transform.columns.3.x,
                    anchor.transform.columns.3.y,
                    anchor.transform.columns.3.z)
                rootAnchor.addChild(shipModel)
            }
        }
    }

}

解説

1.基礎となるViewとrootAnchorを設定します。

    @IBOutlet var arView: ARView!
    //SceneKit対応のARSCNViewではなく、RealityKit用のARViewを使います。
    let rootAnchor = AnchorEntity()
    //rootnodeの代わりにrootとなるAnchorを作成します。(これ以外にも代替する方法はあります。)

2.Session管理をDelegateに渡します。

    override func viewDidLoad() {
        super.viewDidLoad()

        arView.session.delegate = self
        //ARKitのイベントをARViewで検知出来るようにします。

        let gesture = UITapGestureRecognizer(target: self, action:#selector(onTap))
        self.arView.addGestureRecognizer(gesture)
    }

3.現実とカメラ越しの映像を連携させます。(AR機能をONにする)

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

        let configuration = ARWorldTrackingConfiguration()
        arView.session.run(configuration)

        arView.scene.addAnchor(rootAnchor)
        //ARViewのシーンに基盤となるAnchor(rootAnchor)を配置します。
    }

4.タッチした場所にARAnchorを配置します。※ほぼ前回と一緒です

    @objc func onTap(sender: UITapGestureRecognizer) {

        let pos = sender.location(in: arView)
        let results = arView.hitTest(pos, types: .featurePoint)
        if !results.isEmpty {
            let anchor = ARAnchor(name:"shipAnchor",
                                  transform:results.first!.worldTransform)
            arView.session.add(anchor: anchor)
        }
    }

5.ARAnchor上にオブジェクトを表示します。

    // MARK: - ARSessionDelegate

     func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        for anchor in anchors {
            if anchor.name == "shipAnchor" {
                guard let shipModel = try? Entity.load(named: "art.scnassets/ship") else {return}
                //usdzファイルを読み込みshipModel(Entity)として保存します。

                shipModel.position = simd_make_float3(
                    anchor.transform.columns.3.x,
                    anchor.transform.columns.3.y,
                    anchor.transform.columns.3.z)
                //shipModel(Entity)の場所はAnchorと同じにします。

                rootAnchor.addChild(shipModel)
                //shipModel(Entity)をrootAnchor配下に配置します。
            }
        }
    }

■Entityとは?
ModelObject,ARAnchor,アニメーション,物理設定,カメラ/ライトなどを集めたオブジェクトで、SceneKitでいうNode、UnityのGameObject的なものです。
Anchor用とModel用に最適なEntityがあり、それぞれ設定出来る項目が異なります。
BodyTrackingで取得したアニメーションを反映させる際もこのEntityを利用する必要があります。(Unityだと把握し辛いですが、Unity経由でもBodyTrackingはRealtyKitを使っていると思います。)
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3232323337372f33393837393638372d633938662d363137652d653865622d3563336337343435656633662e706e67.png

参考:Entity (Apple Developer)

尚、SwiftだけでなくRealityComposer側を使えば、ほぼGUIで設定しコードは10行程で開発出来ます。こちらの方が一般的な使い方です。
参考:iOS13/Xcode11で登場の新機能「Reality Composer」を紹介するよ
参考:Reality Composer詳細解説〜〜Xcode11時代のARコンテンツ開発

まとめ

ARKit3からはAR用のSceneKitとしてRealityKitが発表されました。
現在のRealityKitで出来る表現はSceneKit程のレベルでないので代替は難しいです。また、View自体が違うので併用は出来ません。
しかしRealtyComposerを使えばUnityのように簡単(もはやUnityより簡単かも)にAR設定が出来ることや、映像表現以外にも長けていることから今後この手法が主流になりそうです。もしかするとARKit3.5的なRealityKit用の中間アップデートがあるかなと思っています。

ここまで読んで頂きありがとうございました!

※ARKitのはじめかたシリーズはこれで終わりです。
ARKitとは何か (ARKit1〜3のまとめ)
ARKitのはじめかた その1「5分で出来るARアプリ」
ARKitのはじめかた その2「オブジェクトを配置する(ARKit1版)」
ARKitのはじめかた その3「オブジェクトを配置する(ARKit2版)」
ARKit(RealityKit)のはじめかた その4「オブジェクトを配置する(ARKit3版)」

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
What you can do with signing up
14