【ARKit】childNode(withName:recursively:)でThread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

# はじめに

こちらを参考にARKitで3Dモデルを表示しようとしたところ、「 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value」のエラーが出たので、その対処を備忘録として。

- [【ARKit入門】平面にアイテムを配置する](https://qiita.com/yyokii/items/ff5b69f7e2c7b93a68ce)

# 実行環境
- Xcode 11.2.1
- MagicaVoxel 0.99.4
- [Mixamo](https://www.mixamo.com)

# コード
上記リンクのサンプルはボタンで使うscnを切り替えていたのですが、簡単にテストするために変数を「swing」固定としました。また SceneKit Catalog の名前も変更（art.scnassets）してあります。

```Swift:ViewController.swift
var selectedItem: String? = "swing"
//（中略）
let scene = SCNScene(named: "art.scnassets/\(selectedItem).scn")
```

# エラーになった箇所
以下のfunctionの childNode(withName:recursively:) で 「 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value」のエラーが出ました。

```Swift:addItem
func addItem(hitTestResult: ARHitTestResult) {
        if let selectedItem = self.selectedItem {

            // アセットのより、シーンを作成
            let scene = SCNScene(named: "art.scnassets/\(selectedItem).scn")

            // ノード作成
            let node = (scene?.rootNode.childNode(withName: selectedItem, recursively: false))!

            // 現実世界の座標を取得
            let transform = hitTestResult.worldTransform
            let thirdColumn = transform.columns.3

            // アイテムの配置
            node.position = SCNVector3(thirdColumn.x, thirdColumn.y, thirdColumn.z)
            self.mainSceneView.scene.rootNode.addChildNode(node)
        }
    }
```

# 原因
[SCNScene.childNode(withName:recursively:)](https://developer.apple.com/documentation/scenekit/scnnode/1407951-childnode) は、SCNScene から withNname で指定した名前のノードを取得するメソッドですが、swing.scnに "swing" というノードが存在しないためでした。
![cap00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106624/aacbeb4c-3ba9-9828-5b12-02fc7214c851.png)

# 対処
swing.scnを開いて、Scene graphパネルの左下の「+」ボタンでノードを追加して「swing」に名前を変更して、元々あったノードを「swing」ノードの配下にドラッグして移動します。
![cap01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106624/1004bdec-5a12-6061-fb80-f3596678c69e.png)


# 3Dオブジェクトのサイズ調整
3Dオブジェクトのサイズが大きすぎたので、サイズ変更のコードを追加してあります。
`node.scale = SCNVector3(0.05, 0.05, 0.05)`

```Swift:addItem
    /// アイテム配置メソッド
    func addItem(hitTestResult: ARHitTestResult) {
        if let selectedItem = self.selectedItem {

            // アセットのより、シーンを作成
            let scene = SCNScene(named: "art.scnassets/\(selectedItem).scn")

            // ノード作成
            let node = (scene?.rootNode.childNode(withName: selectedItem, recursively: false))!

            // 現実世界の座標を取得
            let transform = hitTestResult.worldTransform
            let thirdColumn = transform.columns.3

            // アイテムの配置
            node.position = SCNVector3(thirdColumn.x, thirdColumn.y, thirdColumn.z)
            
            // アイテムのサイズを変更
            node.scale = SCNVector3(0.05, 0.05, 0.05)
            
            self.mainSceneView.scene.rootNode.addChildNode(node)
        }
    }
```

ちなみに MagicaVoxelで作ったときのサイズは、21 21 21 でした。
![cap02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106624/bbdd3ec3-2509-234d-c490-d90135d4d452.png)

この辺の適正サイズや,sncファイルのscale値で変更した方がいいのかは、現時点ではちょっとわからず。。。

# まとめ
前提の知識（3Dモデルとか）が乏しいのでいろいろ躓いています。他の3Dアプリで作ったモデルはちゃんとノード名がつくんですかね。。。

MagicaVoexlについてはこちらを参考にしました。やはり公開することを考えると、オリジナルのモデルが必要になるので、簡単でいいです。

- [【無料 3Dドットモデリングツール】Magica Voxelを使ってみた](https://styly.cc/ja/tips/3d_software_magica-voxel/)

MagicaVoexlにアニメーションをつけるのには、Maximoを使いました。こちらもモデルをアップロードしてアニメーション選ぶだけなので、これまた簡単です。こちらを参考にしました（モデルをMagicaVoexlで作る場合は、Blender部分はすっ飛ばして大丈夫です）。


- [mixamoで3Dキャラクターにアニメーションをつける](https://styly.cc/ja/tips/mixamo_3d/)