LoginSignup
2
0

【iOS】初心者が公式Sample AppをながらARKitとかMetalを理解する①

Posted at

はじめに

こんにちは、プログラミングを始めて約3年のエンジニアのkeitaMaxです。

今回はポイントクラウドのサンプルアプリと、公式を見ながらARKitとかMetalとか、ついでにSwift UIとかをふんわりと理解していこうと思います。

このサンプルアプリで色々学びたいと思います。

ダウンロードから実機にいれる

まずサイトに行ってダウンロードします。

ダウンロードが完了したら、xcodeで開いて、チームを自分のものに設定します。

これでビルドボタンを押せば、実機に入れられます。

すると、カメラが起動して自分の周りのものが点群としてスキャンされています。

なんかぐあんぐあん動いています。

表示するところを見てみる

MetalViewSample.swiftどうやらここで表示する処理をしていそうです。

MetalDepthViewこの中のbodyが起動した時に表示されるところっぽいです。

じっさいに点群を表示しているところはMetalPointCloudここのようです。

デバイスが対応している機種かどうか

デバイスがシーンの深度にアクセスするには、LiDAR スキャナーが必要です。深度視覚化ビューのbody定義では、アプリはデバイスがシーンの深度をサポートしているかどうかを確認することで、サポートされていない構成の実行を防ぎます。

if !ARWorldTrackingConfiguration.supportsFrameSemantics([.sceneDepth, .smoothedSceneDepth]) {
            Text("Unsupported Device: This app requires the LiDAR Scanner to access the scene's depth.")
        } 

そして、上記の部分で点群をスキャンできるデバイスかどうかを判定していて、ダメな時は文言を表示する、大丈夫だったら点群スキャンの画面を表示する処理をしています。

ARProviderを見てみる

データの取得と表示を分離するために、サンプル アプリは ARKit 呼び出しをそのARProviderクラスにラップします。

var arProvider: ARProvider = ARProvider()

ここでARKitの呼び出しをしていて、ARProviderの中で実際に点群データを取得しているらしいです。

ARProvider関数の中を未定見ると、arReceiverをの制御をしていました。

init()

ここでMetalを使用して、GPU側に処理を渡しているっぽいです。
まだ詳しくは調べていないので、今後ゆっくり調べて理解していきたいです。

ARReceiverを見てみる

ここは実際にARSessionを開始して点群を取得している処理が書かれていました。

init()
    override init() {
        super.init()
        arSession.delegate = self
        start()
    }

初期化処理の時にstart()関数を読み込んでいます。

start()
    func start() {
        guard ARWorldTrackingConfiguration.supportsFrameSemantics([.sceneDepth, .smoothedSceneDepth]) else { return }
        // Enable both the `sceneDepth` and `smoothedSceneDepth` frame semantics.
        let config = ARWorldTrackingConfiguration()
        config.frameSemantics = [.sceneDepth, .smoothedSceneDepth]
        arSession.run(config)
    }

ここでARSessionをrunしています。

[.sceneDepth, .smoothedSceneDepth]これってなんだ?と思ったので調べてみました。

公式には以下のように書かれていました。

.sceneDepth

AR エクスペリエンスにおけるデバイスの背面カメラと現実世界のオブジェクトの間の距離に関するデータ。

.smoothedSceneDepth

AR エクスペリエンスでよりスムーズなビジュアルを作成する、デバイスの背面カメラと現実世界のオブジェクト間の距離測定の平均。

.sceneDepthは撮影した物体とスマホとの距離だということはわかったのですが、
.smoothedSceneDepthは平均化しているため、.sceneDepthよりも精度が良いもの?というように捉えておけば良いような気がしました。

session
    func session(_ session: ARSession, didUpdate frame: ARFrame) {
        if(frame.sceneDepth != nil) && (frame.smoothedSceneDepth != nil) {
            arData.depthImage = frame.sceneDepth?.depthMap
            arData.depthSmoothImage = frame.smoothedSceneDepth?.depthMap
            arData.confidenceImage = frame.sceneDepth?.confidenceMap
            arData.confidenceSmoothImage = frame.smoothedSceneDepth?.confidenceMap
            arData.colorImage = frame.capturedImage
            arData.cameraIntrinsics = frame.camera.intrinsics
            arData.cameraResolution = frame.camera.imageResolution
            delegate?.onNewARData(arData: arData)
        }
    }

新しくキャプチャされたカメラ画像と付随する AR 情報をデリゲートに提供します。

didUpdateはどうやら点群が新しく取得できた時に呼ばれるもののようです。

frameというものに、カメラの情報や点群の情報が記載されていそうです。

そして、arDataに点群情報をまとめて入れているようです、

そしてまとめて入れたものを、

delegate?.onNewARData(arData: arData)

この処理でARProviderに渡しています。

おわりに

今回は疲れたのでここまでにします。

ARの処理は予想以上に難しくてなかなか理解が進みません。。。

初心者にはすこしレベルが高かったかなあと思うところもありますが、諦めずにみていこうと思います。

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。(公式みて自分なりに理解しているだけなので、少しでも「ん?」と思うことがあったら教えていただけると助かります。)

最後まで読んでいただきありがとうございました!

参考文献

次の記事

2
0
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
2
0