休日2日を生け贄に青眼の白龍を召喚!


ARで遊んでみる

ARKit2の発表を受けて、久しぶりにARを使って遊んでみたくなり、簡単なアプリを作ってみることにしました。OSのアップデートやXcode10のインストールから始めたので、少し時間のオーバヘッドがありましたが、アプリ自体は画像を認識して3Dオブジェクトを表示するだけなので難易度は低く、実質作業は2日どころか1時間もあれば余裕でできます。
※結局ARKit2固有の機能は使わず。。次回に持ち越しです。

技術/環境

  • Swift4
  • iOS12/Mojave
  • Xcode10(ベータ版)

まずはXcode10をインストール

ARKit2を使用する場合はXcode10をインストールする必要があります。※今回は使用していませんが。。

2018年9月8日時点ではベータ版なので、Appleの公式ページからベータ版をダウンロードしましょう。公式ページはこちら
※iOS12、macOS Mojaveにそれぞれアップデートが必要です。

プロジェクトの作成

今回のプロジェクトを作成していきましょう。Xcode10はブラック対応していてなんだかかっこいいですね。ARViewの記述がすでに準備されている「Augmented Reality App」を選択します。

ここで一度iPhoneを接続して実行してみましょう。左上の再生ボタンを押すとビルドが始まります。ARはSimulatorsだと動作確認できないので、iOS12にアップデートされたiOS端末(私の場合はiPhone)をmacと接続しておきます。

iPhoneで以下のようなオブジェクトが確認できればプロジェクトの作成は成功です。

画像認識する

青眼の白龍(ブルーアイズホワイトドラゴン)を認識できるようにしていきます。ネットに落ちていたいい感じのカードを持ってきます。

これぞTHEブルーアイズという感じですね。

「Assets.xcassets」の中にこのカードを追加します。「New AR Resource Group」を選択して、画像イメージを選択しましょう。

この時、Sizeの値ですが初期値だと怒られる可能性がありますので、少し小さくしてあげることがポイントです。僕は0.065にWidthを調整しました。(Heightは自動調整されます。)

「art.scnassets」に保存されている最初に表示したデフォルトオブジェクトは削除します。
合わせて、デフォルトオブジェクトを表示する以下2行のコードも消しておきましょう。

青眼の白龍と同じ画像を認識することを確認した場合、コンソールに文字列を表示するようにしておきます。認識させるコードは以下です。

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

        // Create a session configuration
//        let configuration = ARWorldTrackingConfiguration()
        let configuration = ARImageTrackingConfiguration()

        if let imageToTrack = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: Bundle.main) {
            configuration.trackingImages = imageToTrack
            configuration.maximumNumberOfTrackedImages = 1
            print("Images...")
        }

        // Run the view's session
        sceneView.session.run(configuration)
    }

ARWorldTrackingConfigurationの代わりに、画像認識のためARImageTrackingConfigurationを使用しています。
ここでスタートボタンを押して動作確認してみましょう。残念ながら僕は青眼の白龍などという立派なカードを持ち合わせていないので、カラーコピーで代用します。

カメラ越しだと本物にしか見えませんね。。

アプリ越しにこの画像を認識し、以下のように「Image...」と出力されていれば画像を認識できています。

3Dオブジェクトの用意

それでは、認識した画像の上に3Dオブジェクトを作成していきます。3Dオブジェクトは以下サイトからダウンロードさせていただきました。

このZipに含まれる「.obj」形式のファイルをダブルクリックすると、XCodeが開きます。

※objファイルはなぜかデフォルトで真っ黒になる場合が多いです。Xcode側の仕様なのか原因は不明ですが、対応法としては右側セレクトボックスの「Shading」を「Physically Based」以外にします。すると、元のカラフルな3Dオブジェクトに戻ります。私は「Lambert」に変更しました。ただし、3Dオブジェクトによっては「Physically Based」以外を選択しても変わらない場合がございますので、その場合は別の3Dオブジェクトをダウンロードすることをおすすめします。

右下の「Show Secondary Editor」をクリックすると下部にエディタが表示されます。適当に左側の「Geometory modifier」をクリックするとポップアップが表示されるため、Convertをクリックします。すると、scnファイルとして先ほどのオブジェクトが変換されているので、これをXcodeの「art.scnassets」下に置いてあげましょう。

デフォルトだと大きすぎるので、Scaleを小さくしてあげることがポイントとなります。今回はxyzそれぞれを「0.003」としました。

3Dオブジェクトの配置

最後に、カードの上に3Dオブジェクトを表示させてあげます。以下のコードを追記してください。

ViewController.swift
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()

        if let imageAnchor = anchor as? ARImageAnchor {
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)
            plane.firstMaterial?.diffuse.contents = UIColor(red: 0, green: 0, blue: 1.0, alpha: 0.5)
            let planeNode = SCNNode(geometry: plane)
            planeNode.eulerAngles.x = -.pi / 2
            node.addChildNode(planeNode)

            if let blueEyesScene = SCNScene(named: "art.scnassets/BlueEyes.scn") {

                if let blueEyesNode = blueEyesScene.rootNode.childNodes.first {
                    blueEyesNode.eulerAngles.x = .pi / 2
                    blueEyesNode.eulerAngles.z = .pi
                    planeNode.addChildNode(blueEyesNode)
                }
            }
        }
        return node
    }

実行し、アプリから以下のように表示されるはずです。

参考資料