サクッとARkitでミニチュアキズナアイを現実世界に召喚させる


はい、どうもー!!

Unite Tokyo 2018にも登場した、最近話題のバーチャルユーチューバー、キズナアイを現実世界に召喚させたい!!!
って思いで、メモがてら記事を書きました

実装環境

MacOS 10.13.4
IOS 11.4 (beta)
Xcode 9.4 (beta)
blender 2.79

手順

キズナアイのモデルをswiftで読み込めるように変換してから、実装します

環境構築

(xcode,blender)のダウンロードは省略します


まずは、キズナアイのモデルをダウンロードしましょう!
https://kizunaai.com/download-page/
解凍してどっかに置いてください!


ウェブサイトやファイルを見て気づいた方もいるかもしれませんが、キズナアイのモデルの形式はPMXです
ってことで、ブレンダーでPMXを開けるようにする必要があります

https://github.com/sugiany/blender_mmd_tools
こちらからBlenderのMMDのアドオンをダウンロードしましょう(zipダウンロードで構いません)
どっかに保存しておいてください

次にBlenderにアドオンをぶち込みます
のblenderを右クリックしてパッケージの内容を表示してください

そこから、Contents -> Resources -> 2.79(著者の環境では) -> scripts -> addonsに移動します
今さっきダウンロードしたMMDアドオンをフォルダ(解凍した中のmmd_tools)ごと入れます

完了したらBlenderを起動しましょう!
Blenderは日本語設定で解説します(やり方は各自ggりでお願いします)

左上から
ファイル -> ユーザ設定を開きます。
その中のアドオンタブを開いて、mmdで検索し、チェックを入れて有効化します


作業が終わったらこのウィンドウは閉じて構いません

実装

まず初期画面ではいらないオブジェクトがあります。全部消しましょう(右クリックでそれぞれ選択して、Xキーを押す)

全部消えたら、左側にmmd_toolsというタブがあると思うので選択します!(下図①)
そして、import modelから、今さっきダウンロードしたモデルを読み込みます(下図②)

Downloads/KizunaAI_ver1.01/KizunaAI_ver1.01/kizunaai/kizunaai.pmxを読み込みます(読み込みボタンは赤枠)

テクスチャを適用した姿で見るために左下の白いまるポチからマテリアルを選択します。
色が乗りました。世界一可愛いキズナアイちゃんです!!!
(目がなくても大丈夫です)

とりあえずここでBlenderは放置してXcodeのプロジェクトを作りましょう

Augmented Reality App を選択したください
project nameとかは適当にしましょう

Blenderに戻って、ファイル -> エクスポート -> Colladaを選択します
XcodeプロジェクトファイルのAssets.xcassets下にCOLLADAのエクスポートをします
なおエクスポートする時の設定は絶対に以下のようにしてください
ファイル名は任意のもので構いません。

Xcodeに戻って、

ViewController.swift
let scene = SCNScene(named: "art.scnassets/ship.scn")!

ViewController.swift
let scene = SCNScene(named: "art.scnassets/kizunaai.dae")!

みたいに書き出したファイル名にします
これで実行するとキズナアイちゃんがリアリワールドに現れます!!!(部屋を晒したくないので画像ありません!すいません!)

ミニチュアに

完成し、実行したら
あれ???キズナアイちゃんでかくね????
となると思います。(上を向いちゃだめですよ!!)
そうです、サイズがおかしいですし宙に浮いてます
ViewController.swiftを編集しましょう。

今さっき編集したここらへん

を以下のように編集します。

ViewController.swift
let scene = SCNScene(named: "art.scnassets/kizunaai.dae")!
scene.rootNode.name = "ai"
scene.rootNode.scale = SCNVector3(0.05, 0.05, 0.05)
sceneView.scene.rootNode.addChildNode(scene.rootNode)
//sceneView.scene = scene <----コメントアウトしてください

そしてViewController.swift内に以下のコードを追記します。

ViewController.swift
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        let results = sceneView.hitTest(
            sceneView.center,
            types: .estimatedHorizontalPlane
        )

        if let result = results.first {
            self.sceneView.scene.rootNode.childNode(withName: "ai", recursively: false)?.position = SCNVector3(
                result.worldTransform.columns.3.x,
                result.worldTransform.columns.3.y,
                result.worldTransform.columns.3.z
            )
        }
    }

これで、実行!!!!!して!!!!!!!!召喚したい場所をタップすると!!!
かわえええええええええええ


終わりに

ってことで、見事に自己満足を達成させました
次はモーションを付けたいです!!!
またねーー!

ViewController.swift
import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {
    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView.delegate = self
        sceneView.showsStatistics = true
        let scene = SCNScene(named: "art.scnassets/kizunaai.dae")!
        scene.rootNode.name = "ai"
        scene.rootNode.scale = SCNVector3(0.05, 0.05, 0.05)
        sceneView.scene.rootNode.addChildNode(scene.rootNode)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        sceneView.session.pause()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let results = sceneView.hitTest(
            sceneView.center,
            types: .estimatedHorizontalPlane
        )
        if let result = results.first {
            self.sceneView.scene.rootNode.childNode(withName: "ai", recursively: false)?.position = SCNVector3(
                result.worldTransform.columns.3.x,
                result.worldTransform.columns.3.y,
                result.worldTransform.columns.3.z
            )
        }
    }
}