Apple Engine

Apple, iPhone, iOS, その周辺のことについて

iPhone と Reality Composer で始める簡単 AR その25 - RealityKit とやりとりする通知 編

今回はトリガー / アクションの通知について。

本来、Reality Composer は AR アプリ用のリソース作成用のツールであり、
RealityKit と連携して AR アプリを作成するためにある。

AR アプリを作成する際、Reality Composer は .rcproject でファイルが保存され、ビルド時に .reality へ変換され内部のリソースとして実行される。

そのためコードからアクセスすると面倒なことがあるため、iOS アプリでよく使用されている通知という機能を使っている。

トリガーを説明しアクションの方はさらっと説明する。
いつか RealityKit の解説を書く機会があれば、アクションの通知もちゃんと書こうかなと。

 

RealityKit から Reality Composer のファイルが動くまでの流れ

Xcode 11 以降で ARKit のテンプレートを選択すると RealityKit のテンプレートが選択できる。
このテンプレートは Reality Composer のファイルで設定されている水平方向のアンカーから現実空間で認識後、立方体を表示するという簡単な AR 体験を行うというものだ。

Reality Composer のファイルを扱い AR 体験を行うということは、 まず RealityKit で ARView という UIView を継承したクラスを使いここに表示するための設定があり、
今までの ARKit でいう SceneKit の ARSCNView や SpriteKit の ARSKView と同じ様なものを使用する。

ARView から Reality Composer のファイルを使用する場合、以下の様なコードでファイルを読み込む。

let boxAnchor = try! Experience.loadBox()

 

Experience.rcproject というファイルで Box という名のシーンでのものを読み込んでおり、
SceneKit などとは異なり try を使用してファイルの有無を調べる。

.rcproject を抜いた Experience でファイルを読み、load を付加したローワーキャメルケースでのシーン名 loadBox() で読み込むことができる。
rcproject やシーンに空白文字がある場合は空白部を埋めて読み込む様になっている。

SceneKit ではリソースがあることが前提だったが、RealityKit では多くの try を使用した例外処理が多用されている。

 

通知の呼び出し方

通知のトリガーからの呼び出しは以下の様な感じ。
トリガーで設定した名称はローワーキャメルケースとなり空白は詰められる。

boxAnchor.notifications.トリガーで設定した名称.post()

 

アクションからの呼び出しは以下の様な形。

boxAnchor.actions.アクションで設定した名称.onAction = { _ in 
    ...
}

 

試してみる

今回はトリガーからの通知。

Xcode から「Augmented Reality App」を選択して、

f:id:x67x6fx74x6f:20200322105434p:plain

 

Language を Swift、Content Technology を RealityKit、
UserInterface を SWiftUI 設定しプロジェクトを作成。

f:id:x67x6fx74x6f:20200322105539p:plain

 

Experience.rcproject を開き、新規のビヘイビアで、 トリガーを通知、アクションを強調で反転を設定する。 今回はトリガーの通知の識別子を”TriggerFlip” と設定した。

f:id:x67x6fx74x6f:20200322105632p:plain

 

ContentView.swift を開き修正していく。
今回は ContentView 側で通知の操作を修正する。

そのため、カスタムで作成している VeiwContorller 側の rcproject を読み込む定数をグローバルでもアクセスできるようにしている。

struct ARViewContainer: UIViewRepresentable {

    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)
        let boxAnchor = try! Experience.loadBox()

        ...
    }
    ...
}
struct ARViewContainer: UIViewRepresentable {

let boxAnchor = try! Experience.loadBox()

    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)

        ...
    }
    ...
}

 

そして、SwiftUI が使用されている ContentView の修正をする。
ARViewContainer をグローバルで読み込める様に修正し、実行部分である Body で通知の部分を修正する。

struct ContentView : View {
    var body: some View {
        return ARViewContainer().edgesIgnoringSafeArea(.all)
    }
}
struct ContentView : View {
    
    let arView = ARViewContainer()
    
    var body: some View {
        
        ZStack {
            
            arView.edgesIgnoringSafeArea(.all)
            
            Button(action:{
                self.arView.boxAnchor.notifications.triggerFlip.post()
            }){
                ...
            }
            
        }
        
    }
}

 

ビルドすると中央にボタンが現れ、タップすると立方体が跳ねる。

(今回、アニメーションが終わるままでボタンを押せない様にしていないため、連打すると立方体の位置がおかしくなる)

 

サンプルファイル

今回は Xcode のプロジェクトファイルのため注意

github.com

 

注意点

現状、どの段階で起きるか不明だが、複雑なアクションを設定していると、トリガーやアクションからの通知が上手く処理されないことがある。
原因不明。

 

まとめ

RealtiKit からアクションの通知による Reality Composer 操作や Reality Composer からアクションによる通知からの RealtiKit への呼び出しがわかったと思われる。
実は Reality Composer では操作できない機能が RealtiKit にはあるので試してみると良いかもしれない。

とりあえず、一通りの機能は紹介できたと思われる。
紹介し忘れているものがあったら随時追加してく。