Edited at

開発初心者がARKitでグラフィティアート出来るSNSを作ってみた


はじめに

はじめまして、drama(@1901drama)です!

ARを勉強するにあたり日本語ドキュメントが少なくて苦戦したので、

誰かの助けになれば...と思い、Qiitaデビューしました。少しでもARが普及すると嬉しいです。

※記載間違い等あれば教えてください。


ARkit 2.0の発表

もう5ヶ月程前ですが、2018/9にARKit2.0(iOS12)がリリースされましたね。



https://www.moguravr.com/arkit-2-0/

~追加された機能達~

・ARのマルチプレイが可能に

・ARオブジェクトの再利用が可能に

・イメージ認識やトラッキングサポートが拡大

・AR向けフォーマット「USDZ」に対応 など

つまり、AR体験を

・他人と同時に見れる(共有出来る)

・過去の情報を再現出来る

・専用アプリ以外(safariや他のデバイス)でも見れる ということに。

以前unityでARをやってたときよりも、めちゃくちゃ出来ることが増えていて驚きです。

これはもう電脳コイルのようなAR時代も近いのではないか!!? と思い ARを始めました。

今回はAR開発を初めて 一つ目に作ったものを紹介します。


出来たもの

グラフィティーアートをどこでも出来れば楽しそう!という考えから、ARでラクガキするSNSを作りました。

3Dオブジェクトを置いたり描いたり、つくったものを共有/評価 出来ます。

・置いたり、書いたり



・共有したり、評価したり、上書きしたり



手こずった点は山ほどある...のですが、

一先ず、このアプリの肝であるAR共有機能についてのみ解説します。


ARの共有方法

ARKitのARWorldMapを使っています。

https://developer.apple.com/documentation/arkit/arworldmap

ARWorldMapには、物理的な空間情報と空間の特徴点を記録したARanchorが含まれています。

ざっくりいうと、ARworldMap≒取得した空間内の位置情報群 と思って頂ければいいです。

このARWorldMapを利用し下図のような形で、空間情報の共有を実装しました。


・作成ユーザーを識別する為に、Authenticationを利用。

・空間情報(ARWorldMap)とオブジェクトの情報はサイズが大きいのでCloudStorageを利用。

・その他の情報は、Firestoreを利用。

 ※図のRealtime DBは、Firestoreに変更しました。


【処理の順番】

1.空間に置いたり描いたりしたオブジェクトと、空間情報(ARWorldMap)を紐づけて表示させます。

//空間にオブジェクトを置く時の処理

//SCNodeを作成し名前をつける。(細かい設定等は省略します)
let testNode= SCNNode()
testNode.name = "testNode"

//アンカーにSCNNodeと同じ名前をつけて、タッチした場所(空間)に追加する。
let Anchor = ARAnchor(name: "testNode", transform: hitTestResult.worldTransform)
sceneView.session.add(anchor: Anchor)
self.testNodes.append(testNode)

//空間にanchorが追加された時の処理

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//anchorと同じ名前のSCNNodeを空間に追加する。
for testNode in testNodes{
if anchor.name == testNode.name {
sceneView.scene.rootNode.addChildNode(testNode)
}
}
}

2.空間情報(ARworldMap)と 置いたり描いたりしたオブジェクトの情報を アーカイブし、共有したい人がアップロードします。

//Apple公式

func writeWorldMap(_ worldMap: ARWorldMap, to url: URL) throws {
let data = try NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true) try data.write(to: url)
}
//①ARachor(ARworldMap)を取得→②ARachor(ARworldMap)をアーカイブ(シリアライズ)してdata化 →③dataをURLにアップロードの流れ

//アプリ内に記載したコード

func dataExport(){
//AR_DATA(ARworldMap) Export
self.sceneView.session.getCurrentWorldMap { (worldMap, error) in
guard let worldMap = worldMap else { print("Error getting current world map."); return }
do {
self.ar_data = try NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true)
} catch let error as NSError { print("failed to write: \(error)")}
}

//OBJECT_DATA(オブジェクト) Export
let objectData = self.testNodes
do {
self.object_data = try NSKeyedArchiver.archivedData(withRootObject: objectData, requiringSecureCoding: true)
} catch let error as NSError { print("failed to write: \(error)") }
}

//この後 FirebaseのFirestoreにアップロードしてます。

3.最後に、共有されたい人がインポートすることで、空間を再現します。

//Apple公式

func loadWorldMap(from url: URL) -> ARWorldMap throws {
let mapData = try Data(contentsOf: mapURL) guard let worldMap = try NSKeyedUnarchiver.unarchivedObject(of: ARWorldMap.classForKeyedUnarchiver(), from: mapData) as? ARWorldMap else { throw ARError.invalidWorldMap } return worldMap
}
//④dataをURLからダウンロード→⑤dataをアンアーカイブ(デシリアライズ)してARachor(ARworldMap)化→⑥現在の環境にARachor(ARworldMap)を反映

//アプリ内に記載したコード

//この前に FirebaseのFirestoreからダウンロードしてます。(downloadsPath_AR_DATA,downloadsPath_OBJECT_DATA)
func dataImport(){
//OBJECT_DATA(オブジェクト) Import
let unarchievedOBJECT_DATA = try? NSKeyedUnarchiver.unarchiveObject(with:Data(contentsOf:downloadsPath_OBJECT_DATA))
guard let downloadtestNodes:[SCNNode] = unarchievedOBJECT_DATA as? [SCNNode] else { return }
for testNode in downloadtestNodes {
self.testNodes.append(testNode)
}

//AR_DATA(ARworldMap) Import
let unarchievedAR_DATA = try? NSKeyedUnarchiver.unarchiveObject(with:Data(contentsOf:downloadsPath_AR_DATA))
guard let newWorldMap = unarchievedAR_DATA as? ARWorldMap else {return}

//downloadしたARWorldMapを反映
self.configuration.initialWorldMap = newWorldMap
self.sceneView.session.run(self.configuration)
}


まとめ

AR開発は成果物が空間に目に見えて現れるのが面白いです。

普段はディレクションやサービス設計がメインなので、アプリ開発自体も楽しいです。

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

※今回のアプリは、ちゃんとしたキャラクターが完成すればリリースする予定です。