[Unity,AR]Unityを使って超簡単にiOS向けARファイルを作成する

## はじめに

皆さんはUSDZファイルをご存じでしょうか？
簡単にいってしまうと3Dシーン(モデル等)を保存したファイルです。
このファイルの特徴の一つに**iOS12以上のiPhoneであれば追加でアプリをインストールすることなくARプレビュー可能**というものがあります。[^1]
追加でアプリをインストールする必要がなく、ブラウザさえあればプレビュー可能なのでお手軽にAR体験が可能です。


参考:[Quick Lookギャラリー - 拡張現実 - Apple Developer](https://developer.apple.com/jp/augmented-reality/quick-look/)

昨年[USDZファイルを作成する記事](https://qiita.com/yaegaki/items/e9e5922f428e7016ad65)を書いたのですが、このときはまだ情報やツールが出そろっておらず大変面倒でした。
今年になって**Unityを使用すれば超簡単にUSDZファイルを作成することができる**ということが分かったのでその方法をご紹介します。

この記事を読めば以下のようなものを作成することができます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">家に帰ってきたらシロちゃんが椅子に座ってた<br>©App Land ©KLabGames<a href="https://twitter.com/hashtag/SiroTalk?src=hash&amp;ref_src=twsrc%5Etfw">#SiroTalk</a> <a href="https://t.co/tQQ7mTOHtW">pic.twitter.com/tQQ7mTOHtW</a></p>&mdash; fino (@fi_n_o) <a href="https://twitter.com/fi_n_o/status/1201501988753526784?ref_src=twsrc%5Etfw">December 2, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**注:以下の内容はWindowsでのみ動作確認を行っております。**

## モデルの準備(Unityインポートまで)

AR化するためのモデルを用意します。
今回は[『禍つヴァールハイト』バージョンのシロちゃん](https://www.magatsu-wahrheit.com/news/387/)を使用させていただきました。

> ![siro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/1cf52e41-2dfc-a2d6-a3c8-d010aed69112.jpeg)
>
> https://www.magatsu-wahrheit.com/news/387/ より引用

©App Land ©KLabGames

**!!必ず使用するモデルの利用規約に目を通してください。また、詳細なインポート方法については解説しません。!!**

FBXをエクスポートする際には以下の点に気を付けてください。
(基本的にBlenderベースの解説です。)

1. Unityにインポートしたときにスケルトンの回転が0になるようにする
2. 1メッシュ1マテリアルになるようにする
3. 頂点数を抑える
4. ブレンドシェイプを焼き付ける
5. テクスチャを同梱する

### 1. Unityにインポートしたときにスケルトンの回転が0になるようにする

これをしておかないとアニメーションをつける際に面倒なことになります。[^2]
アニメーションをつけない場合は特に問題はありません。



<details><summary>Blenderの場合は以下の操作で実行できます。</summary><div>


1.ArmatureをObjectModeでX-90度に回転する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/a415975c-5d00-3105-2b89-d26650843ad4.png)

2.Ctrl-Aで出てくるメニューからApply Rotationを実行する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/29e4f382-7abb-fa66-dc5b-31dc4443aaaf.png)

実行後にArmatureのRotationが0,0,0になっていることを確認してください。

3.ArmatureをObjectModeでX90度に回転する

前回の操作でRotationが0,0,0になっているはずなので90,0,0になるように回転します。
このときにApply Rotationを実行してはいけません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/64a57f55-42b3-776b-df0d-5a22ed0550fe.png)


4.キャラクタのすべてのメッシュを選択しApply Rotationを実行する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/a22ced9b-1e03-d4e8-218c-cb400a3cd828.png)


この状態でFBXエクスポートを行うとArmatureの回転が0になっています。
参考:[Blender to Unity with Correct Scale and Rotation](https://www.youtube.com/watch?v=bpH5ZfonExo)
</div></details>


### 2. 1メッシュ1マテリアルになるようにする

これについてはよくわかりませんが1メッシュに複数のマテリアルが付いていると表示されません。
1メッシュ1マテリアルになるように分割しましょう。

### 3. 頂点数を抑える

特に説明することはありませんが、あまりにも頂点数が多いと古い端末ではモデルが表示されないことがあります。


### 4.ブレンドシェイプを焼き付ける

iOSのAR表示ではブレンドシェイプが適用されません。[^3]
表情をつけたい場合はエクスポートする段階でブレンドシェイプの情報をモデルに焼き付けておく必要があります。

<details><summary>Blenderの場合は以下の操作で実行できます。</summary><div>

**この操作はモデルを直接編集するので実行する前にバックアップを取っておいてください**

1.オブジェクトモードでシェイプキーの値を変更する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/33f6f8ed-9b66-2f92-f85c-9c398513a105.png)


2.Mixキーを作る

複数のシェイプキーを使用する場合はMixキーを作成する必要があります。
複数のシェイプキーの値を設定した後、右側のボタンから`New Shape From Mix`を実行してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/6e73e257-ed90-dc7f-0fb4-af1076a0d371.png)


その後、最初に設定したシェイプキーの値を0に戻しMixキーの値を1にします。
そうすると最初に設定した状態の頂点になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/836039bf-bb74-1898-2f03-ca58dc5d13bd.png)

3.Mixキー以外のキーを削除する

この状態でMixキー以外のすべてのキーを削除します。
するとFBX書き出しの際にデフォルトの頂点情報がMixキーで設定した状態になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/49c815bb-91da-c223-0f6a-e680cfd37acb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/6197373f-7f3f-1da7-23e3-dff65028c295.png)



</div></details>

### 5.テクスチャを同梱する

これは必須ではありませんがやっておくとテクスチャの設定が楽になります。

<details><summary>Blenderの場合は以下の操作で実行できます。</summary><div>


* FBXをエクスポートする際のオプションでPathModeをCopyにして右のアイコンが以下の画像の状態になるようにする。
* 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/e9c05b55-791e-2ad8-323e-12a95f78c707.png" width="300">

</div></details>

## モデルの準備(Unity上での操作)

Unity上では以下の操作を行います。

1. テクスチャの設定
2. マテリアルの設定
3. メッシュの設定
4. スケルトンの確認
5. Transformの確認
6. (必要に応じて)DynamicBoneの設定

### 1. テクスチャの設定

FBXにテクスチャを同梱している場合、以下のボタンからテクスチャをアセットとしてUnityに取り込むことができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/c4a2e4b0-b2e5-1876-79da-1dd8539bdfb4.png" width="300">

取り込んだテクスチャの名前は**必ずアルファベットのみ**で構成されるようにしてください。
日本語が使用されているとうまく表示されない可能性があります。[^4]

### 2. マテリアルの設定

今回紹介する方法では基本的には**Standardシェーダー**を使う必要があります。
それ以外のシェーダを使用している場合はStandardシェーダーでうまく見えるように調整してください。

### 3. メッシュの設定

モデルのメッシュは必ず**Read/Write Enabled**にしておく必要があります。

### 4. スケルトンの確認

ヒエラルキー上にモデルを配置し、スケルトンのRotationが`0,0,0`になっていることを確認してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/1b147675-b5dd-f58d-bef7-7d8eecd4833d.png" width="300">

**必ずUnityにインポートした時点で既にRotationが`0,0,0`になるようにしてください。**
ヒエラルキーやプレハブのRotationをあとから編集した場合はアニメーションを行った際に正しく表示されない可能性があります。
`0,0,0`になっていない場合は[Unityにインポートしたときにスケルトンの回転が0になるようにする](#1-unityにインポートしたときにスケルトンの回転が0になるようにする)を参考に設定してください。

### 5. Transformの確認

Transformの名前がすべてアルファベットのみで構成されるようにしてください。
日本語が使用されている場合うまく表示されない可能性があります。

### 6. (必要に応じて)DynamicBoneの設定

アニメーションをつける場合はDynamicBoneがあるかないかで見栄えの差が大きくなります。
DynamicBoneは以下のページから購入できます。

[Dynamic Bone - Asset Store](https://assetstore.unity.com/packages/tools/animation/dynamic-bone-16743)

どうしても無料がいい場合はSpringBoneを使用するという選択肢もあります。
DynamicBone/SpringBoneの設定についてはWebに素晴らしい記事がありますので検索してみてください。

スカートをいい感じに見せるためには以下の記事が参考になります。

[[VRChat]ふわっとしたスカートで座っても安心のDynamicBone吊りスカート](https://qiita.com/hoke946/items/c868329ee15fb91a890d)

## アニメーションしないUSDZファイル出力

まずはアニメーションしないバージョンのUSDZファイルを作成します。
UnityのパッケージマネージャーからUSDをインストールしてください。
(2019/12/1時点では)USDはプレビューパッケージなので**Show preview packages**にチェックを入れていないと出てこないので注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/bdb1b800-1b69-8682-886c-aefdcbf6fe50.png)

インストールが完了するとUnityのメニューにUSDが追加されます。
ヒエラルキー上に配置したモデルを選択した状態で`USD > Export Selected as USDZ`を実行します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/99a5dfc2-052f-0369-d57e-ab0984d1de5d.png" width="300">

するとファイルの保存先が聞かれるので適当な場所に保存します。
これで完了です:rocket:
すごく簡単ですね:relaxed:

保存したファイルをiPhoneでダウンロードすればプレビューすることができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/118260d8-2036-f7c8-a544-15738235b0a4.png" width="300">

サムネイルの状態で前後が逆になっている場合、
以下のようなヒエラルキーにした状態でRootを選択してエクスポートを実行します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/9fef01b5-b181-24bb-68d8-2254ce76254e.png" width="300">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/d92335dc-abf5-a669-b820-91bebe2b129e.png" width="300">

もしテクスチャが貼られていない場合や一部のメッシュが表示されていない場合はテクスチャ名、Transform名に日本語が使用されていないかどうかチェックしてください。


PCにpythonがインストールされている場合は以下のコマンドで簡単にHTTPサーバーを立てることができます。

```python
cd path/to/usdz/directory
# python2系
python -m SimpleHTTPServer
# python3系
python -m http.server
```

## アニメーションするUSDZファイル出力

アニメーションするUSDZファイルを出力するのはしないものに比べて多少面倒になります。
また、USDパッケージだけでもやろうと思えばできますが簡単にするためのユーティリティを作成したのでそちらを使用します。

[yaegaki/UnityUsdzUtil](https://github.com/yaegaki/UnityUsdzUtil)


[リリースのページ](https://github.com/yaegaki/UnityUsdzUtil/releases/tag/0.1)から**UnityUsdzUtil.unitypackage**をダウンロードしてください。

**UnityUsdzUtil.unitypackage**には以下のファイルが入っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/f2439878-18c3-ddea-bd83-f294b05f3f8e.png)

パッケージをインポートしたら**UsdzRecordStand.prefab**をシーンに配置してください。
そしてエクスポートしたい対象を`UsdzRecordStand > Root`の子オブジェクトとしに設定してください。
以下の画像のような状態になれば大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/7db70d99-143a-f70a-8fb7-88cd1a1faf5d.png)

その後、Unityを実行状態にしてモデルにアニメーションを適用します。
エクスポートしたい場所で**UsdzRecordStand**の**Recordボタン**をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/584a94f3-1eab-30a4-b6c1-242fc481e1f6.png)

すると**Recordボタン**を押してから既定では約5秒後にusdzファイルの出力が完了します。
このファイルをiPhoneでダウンロードすれば作業は完了です:point_up:

### おまけ1 - UsdzRecordStandのインスペクタ項目について

| 項目 | 説明 |
|:--|:--|
| ExportDirectory | usdzファイルを作成するディレクトリ |
| ExportFileName | usdzファイルの名前。空白の場合Rootの最初の子の名前になる。 |
| CreateUsdaFile | 中間ファイルとしてusdaを作成する。主にデバッグ用。 |
| ThumbnailCamera | サムネイルを撮影するカメラ |
| ExportRoot | エクスポートするルート |
| FrameRate | 出力するアニメーションのフレームレート |
| RecordSec | 出力するアニメーションの時間 |
| FlipZ | 出力時にY+180度回転する。 |
| PauseWhenFinished | Recordが終わった時にエディタを一時停止する。 |
| CurrentFrame | 現在記録中のフレーム |
| Snapshot/Record | 出力ボタン。プレイ中かそうでないかでSnapshotかRecordが変わる。 |
| ExportFromFile | CreateUsdaFileで作成したファイルを使ってusdzファイルを作成する。主にデバッグ用。 |
### おまけ2 - UsdzHttpServer

**UsdzRecordStand.prefab**にはもう一つ**UsdzHttpServer**というスクリプトが付いています。
これはその名の通りHttpサーバースクリプトです。

**Startボタン**をクリックするとUsdzファイルの配信サーバーが立ち上がります。
`http://Unityを起動しているマシンのIP:19900`にiPhoneでアクセスすると以下のようにサムネイル付きでUsdzファイルを確認することができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/9de6833c-e433-53ae-770f-726237621eed.png" width=300>

## トラブルシューティング

### USDZファイルの中身がおかしい

USDZファイルの中にモデルが出力されない場合以下の原因が考えられます。

* テクスチャ名に日本語を使用している
* Transform名に日本語を使用している
* モデルのRead/Write Enabledがオンになっていない
* 1メッシュに複数のマテリアルが使用されている

これらの設定を確認してみてください。

アニメーションを適用したモデルが90度倒れて表示される場合はスケルトンに回転が掛かっている可能性があります。
スケルトン(Armature)の回転が`0,0,0`になっていることを確認してください。

iPhoneで表示する際にエラーが発生する場合はモデルの頂点数が多すぎる、長すぎるアニメーション時間などが考えられます。
頂点数の削減や記録時間を短くするなどの対策をしてください。

どうしても原因が分からない場合は[USD Toolset](https://graphics.pixar.com/usd/docs/USD-Toolset.html)を使って原因を調査します。
ただし、**USD Toolset**はソースでしか配布されていないのでビルドする必要があるので少し手間です。

### USDZのファイルサイズが大きすぎる

usdzファイルのファイルサイズが大きすぎる場合、テクスチャの設定を見直すことで改善される可能性があります。
テクスチャのサイズやフォーマットを変更してみてください。
少しでもファイルサイズを小さくしたい場合はモデルの頂点数を削減する、アニメーションの時間を短くするなどを行ってください。

### DynamicBoneが暴れる

Unityを普通に実行したときとアニメーション付きUSDZを出力しながら再生したときでDynamicBoneの挙動に差がある場合があります。
アニメーション付きUSDZファイルの出力にはそこそこマシンパワーが必要なため、
1フレームの時間が長くなることによってDynamicBoneが暴れます。
その場合はDynamicBoneのUpdateRateを調節してみてください。
それでもうまくいかない場合はUnityのTimestepを変更するという最終手段があります。
Timestepを以下のように設定すると1フレームにかかる現実の時間は長くなりますが、いい感じに出力できる可能性があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/e099b1af-66f4-2d4b-bccb-3d294aad0098.png)

### UsdzHttpServerにアクセスできない

一度Stopしてからもう一度Startしてみてください。
それでもアクセスできない場合はPCのファイアーウォールの設定を確認してください。

### 出力時にエラーが出て失敗する

エラーメッセージを見て対処してください。
エラーメッセージが解決の参考にならない、どうしても解決できない場合は**PCを再起動**してみてください。
解決する可能性があります。

## おわりに

モデルやアニメーションの設定が少し手間ですが、設定してしまえばすごく手軽にAR表示までもっていくことができます。
アニメーション付きのモデルをAR表示させると思っていた以上に良いので皆さんもぜひ試してみてください。



[^1]: iPhone6sより前の端末では使用できません。またiPhoneX系の端末とそれ以前の端末で多少機能に違いがあります。
[^2]: iOSで表示する際にスケルトンの回転情報が無視されます。usdviewで見ると正常なのでおそらくバグです。iOSのバージョンが上がることで問題なくなるかもしれません。
[^3]: usdの仕様上は存在していますがunity-usdが対応しておらず、iOS側も対応していません。将来的には対応されるかもしれません。
[^4]: Windowsで作業している場合は反映されません。Macで作業した場合は反映されるかもしれませんが未確認です。