SceneKitのサンプルにアニメーション付きの3Dモデルを表示させる


## はじめに

デフォルトのSceneKitのサンプルをビルドするとクルクル回る宇宙船が表示される。

![default_sample.gif](https://qiita-image-store.s3.amazonaws.com/0/200963/7a7068c9-bcdf-973c-f066-541dd73aca40.gif "default_sample.gif")

これをこのような自分オリジナルのアニメーション付きの3Dモデルに置き換えたい。
![guy.gif](https://qiita-image-store.s3.amazonaws.com/0/200963/9b22460a-3ed8-95b3-fd48-05ee9e2ef1a5.gif "guy.gif")


## ビルド環境
- macOS 10.12.6
- Blender 2.79
- MakeHuman 1.1.1
- Xcode 8.3.3

注意） BlenderとXcodeのインストールは本投稿では扱わない


## 手順

1. MakeHumanを使って3Dモデリングデータを作成する
2. Blenderのアドオンを使って3Dモデルデータにボーンを埋め込む
3. 3Dモデルデータにrigをつける
4. ボーンにオートIKを設定する
5. アニメーションを設定する
6. 3Dモデルデータをdae形式でエクスポートし、Xcodeで読み込む
7. Xcodeで3Dモデルデータを表示する

## MakeHumanを使って3Dモデリングデータを作成する

3Dモデリングなんてやったことない・・・。安心してください [MakeHuman](http://www.makehuman.org) を使えば簡単に3Dモデリングデータを作ることができます。

1. MakeHumanのサイトにアクセスし、DownloadのリンクよりMakeHumanをダウンロードする
2. Mac版の場合はdmg形式で配布されているためダウンロードしたdmgファイルを開きMakeHuman.appを/Applicationsへコピーする
3. LaunchPadまたはFinderのApplicationsよりMakeHumanを起動する  
**注意）MakeHumanには署名が付いていないので起動に失敗した場合はシステム環境設定＞セキュリティとプライバシーより実行を許可する必要あり**
4. MakeHumanを使い人間のモデリングを行う
画面にタブがあるが、今回使うのはModelingとGeometriesとMaterialsのみでOK
**注意）Pose/AnimeのタブでMakeHuman時点でrigを設定できるが、BlenderでインポートするとオートIK設定をしても上手く動かないため、MakeHumanでモデルだけ作成してBlenderでrigを設定する方をお勧めする**
![makehuman_launch.png](https://qiita-image-store.s3.amazonaws.com/0/200963/75649181-8b6f-3f4a-09ac-dad2c81f8ef8.png "makehuman_launch.png")

5. 作成し終わったら上部のアイコンの左から3番目を押しデータをエクスポートする、このとき出力フォーマットはCollada(dae)を選択しておくこと
![makehuman_save.png](https://qiita-image-store.s3.amazonaws.com/0/200963/4422ad11-9721-9fb9-6aae-a4004f7f4857.png "makehuman_save.png")

## Blenderのアドオンを使って3Dモデルデータにボーンを埋め込む

1. Blenderを起動する
2. デフォルトのプロジェクトではキューブが存在するが、これを右側のアウトライナーのCubeを右クリック＞削除を選択し削除する
![blender_init.png](https://qiita-image-store.s3.amazonaws.com/0/200963/1699951d-cad5-d010-2ed8-749eadbdd2ab.png "blender_init.png")
3. メニューのファイル＞インポート＞Collada(デフォルト)(.dae)を選択し先ほどエクスポートした3Dモデルデータを読み込む
![blender_import.png](https://qiita-image-store.s3.amazonaws.com/0/200963/c65f1fe7-a867-f52c-06c1-f9630c93bfe3.png "blender_import.png")

4. Shift+Aを押してプリセットの人体ボーンを追加する
**注意）事前にプラグインを有効にしている必要があるため、設定していない場合は[BlenderでRigifyを使う方法](https://qiita.com/edo_m18/items/8151d328f42458f9d92a)を参照して設定を行う**
![add_armature.png](https://qiita-image-store.s3.amazonaws.com/0/200963/fcb7dcae-f504-1a2d-ab13-02dbd72dc09b.png "add_armature.png")
![not_set_sleleton.png](https://qiita-image-store.s3.amazonaws.com/0/200963/31546d47-fdf0-a41a-714e-46d74abf56dc.png "not_set_sleleton.png")

5. 初期状態だと3Dメッシュにボーンが埋もれてしまい操作しづらいため、右のプロパティペインでアーマチュアを選択しスケルトンにチェックを入れる
![set_skeleton.png](https://qiita-image-store.s3.amazonaws.com/0/200963/8af471da-d1f1-b506-4ce1-31c24f376408.png "set_skeleton.png")


6. オブジェクトモードの表示になっているのでTabを押して編集モードに切り替え、各ボーンの位置を調整しメッシュの中にボーンが埋まるようにする
この時[Blenderでボーンを設定する時のテクニック](https://qiita.com/noby111/items/8dfef0a42667570b5099)のように対称化を使うと左右対称にボーンを埋め込むことができます
![set_bone.png](https://qiita-image-store.s3.amazonaws.com/0/200963/9b352b69-121b-fe38-d36b-cab187190d0c.png "set_bone.png")

## 3Dモデルデータにrigをつける
rigを付けるのはオートウェイトを使えば簡単です。

1. 編集モードからTabを押してオブジェクトモードに戻す
2. 体のメッシュを右クリックで選択する
3. Shiftを押しながら他のメッシュパーツをクリックして全てのメッシュを選択する  
赤枠で囲っているのが全てのメッシュを選択した状態で逆三角のアイコンが赤くなっている状態であればOK
4. そのままShiftを押したままボーンを右クリックして選択する
5. その状態でCtrl+Pを押して「自動のウェイトで」を選択する  
![auto_weight.png](https://qiita-image-store.s3.amazonaws.com/0/200963/816fd0b2-cb51-170f-93f5-44675b386645.png "auto_weight.png")

オートウェイトが成功すると、ポーズモードで下のようにボーンを動かして3Dモデルに好きなポーズを付けることができる。
![pose.png](https://qiita-image-store.s3.amazonaws.com/0/200963/3126dc35-3d96-d579-5c70-0e11e1267856.png "pose.png")


## ボーンにオートIKを設定する
この状態だとポーズを付けるのに一つ一つのボーンを動かさなければならず、例えば膝を曲げるにも腿からつま先までを動かさなければならず非常に面倒臭い。オートIKを付けると人形のようにあるボーンを動かすと他のボーンが連動して動いてくれるようになりかなり編集が楽になります。

1. ポーズモードに切り替える
2. 左のペインのオプションタグを選択する
3. オートIKにチェックを付ける  
![autoIK.png](https://qiita-image-store.s3.amazonaws.com/0/200963/b3193923-bc09-f22b-6fea-6e20a2aa0a1b.png "autoIK.png")


## アニメーションを設定する
ようやくアニメーションを設定することができます。

1. ポーズモードに切り替える
2. Cを押し範囲選択で全ボーンを選択する
3. 選択した状態でIを押し、キーフレームの挿入 ＞「位置/回転」を選択する
![add_first_frame.png](https://qiita-image-store.s3.amazonaws.com/0/200963/ffea5d6f-b572-851c-93e0-daa810dc0fb6.png "add_first_frame.png")
4. この状態で全ボーンの初期状態のキーフレームが挿入されたので、画面最下部のタイムラインで時間を30に進める
![timeline.png](https://qiita-image-store.s3.amazonaws.com/0/200963/4d039066-893f-c310-f285-3a9df8a5c41d.png "timeline.png")
5. 手足のボーンを適当な位置に動かし、先ほどと同じく範囲選択で動かしたボーンを選択してキーフレームを挿入する
![add_second_frame.png](https://qiita-image-store.s3.amazonaws.com/0/200963/0aef3f60-20ce-390b-28c7-aa57edb86ef8.png "add_second_frame.png")
6. 最初のフレームまでタイムラインを戻し全ボーンを選択し、ポーズツールのコピーボタンを押し、初期状態のポーズをコピーする
![copy_first_frame.png](https://qiita-image-store.s3.amazonaws.com/0/200963/d7ab8679-5ee9-4ab9-43ec-176467704986.png "copy_first_frame.png")
7. 60までタイムラインを進め、ポーズツールの貼り付けボタンを押し、初期状態のポーズをペーストする
![paste_frist_frame.png](https://qiita-image-store.s3.amazonaws.com/0/200963/f4436f25-33f2-dea0-3d1b-0d6f47b3ee48.png "paste_frist_frame.png")
8. ポーズのペーストを駆使して30ごとポーズを決めて、キーフレームを挿入して行く
9. 120までポーズを決めたらタイムラインの終了を120に設定する  
![change_animation_time.png](https://qiita-image-store.s3.amazonaws.com/0/200963/f01b6890-dbc3-df82-c892-2c4aa14edbea.png "change_animation_time.png")

ここまで設定が完了した状態でタイムラインの再生ボタン:arrow_forward:を押すと下記のようなアニメーションになる。
![anime_in_blender.gif](https://qiita-image-store.s3.amazonaws.com/0/200963/d675adc9-934f-c617-3888-f1dc80f8b6a9.gif "anime_in_blender.gif")


## 3Dモデルデータをdae形式でエクスポートし、Xcodeで読み込む
1. Blenderの左上のメニューより ファイル ＞ エクスポート ＞ Collada(デフォルト)(.dae) を選択する
2. 適当な名前をつけて保存する（例ではguy.daeをという名前を付けました）
![export.png](https://qiita-image-store.s3.amazonaws.com/0/200963/20708046-9ba8-c18c-5bb6-cb5d7928f673.png "export.png")
3. Xcodeを起動する
![xcode_start.png](https://qiita-image-store.s3.amazonaws.com/0/200963/70a39e97-a0da-ece4-70c0-a58cf623ec87.png "xcode_start.png")

4. Xcodeのメニューより File ＞ New ＞ Project を選択する
5. iOSアプリケーションのGameを選択する
![xcode_select_project.png](https://qiita-image-store.s3.amazonaws.com/0/200963/741fffc7-62e9-142c-588f-07d0a75c00cf.png "xcode_select_project.png")

6. Game Technology で SceneKitを選択する
![xcode_project_option.png](https://qiita-image-store.s3.amazonaws.com/0/200963/c34eb709-7348-6b73-528a-8c78b475ac2c.png "xcode_project_option.png")

7. Xcodeのプロジェクトが完成したら先ほどのdaeファイルとMakeHumanエクスポート時に作られたtextureディレクトリをart.scnassets配下にコピーする
![add_dae.png](https://qiita-image-store.s3.amazonaws.com/0/200963/3cd0393e-c030-e53d-995e-13a8133933b9.png "add_dae.png")


8. この状態だとテクスチャが何も設定されていない状態なので、guy.daeを選択し左のペインでguy-baseという名前がついたノードを選択し、右ペインのプロパティでMaterialsを選択し、Diffuseでtexture内の皮膚画像を選択する
![set_texture.png](https://qiita-image-store.s3.amazonaws.com/0/200963/73bbd5c7-d6b9-4fea-4363-5a1929695bac.png "set_texture.png")

9. 同様に他のパーツのテクスチャを設定する

## Xcodeで3Dモデルデータを表示する
あとは簡単です。GameViewController.swiftを下記のように修正してください。

``` diff
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // create a new scene
-        let scene = SCNScene(named: "art.scnassets/ship.scn")!
+        let scene = SCNScene(named: "art.scnassets/guy.dae")!
        
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
        
        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        
        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)
        
        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)
        
        // retrieve the ship node
-        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
+       // let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
        
        // animate the 3d object
-        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
+       // ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
        
        // retrieve the SCNView
        let scnView = self.view as! SCNView
        
        // set the scene to the view
        scnView.scene = scene
        
        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true
        
        // show statistics such as fps and timing information
        scnView.showsStatistics = true
        
        // configure the view
        scnView.backgroundColor = UIColor.black
        
        // add a tap gesture recognizer
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
    }

```

この状態で実行すると、最初に紹介したような動く人体モデルが表示されます。
お疲れ様でした。

SceneKitとARKitを使ってARアプリ開発をしたい方向けに情報をまとめていますので、[こちら](https://www.nsunrise.work/p/index.html)もご参照ください。