iPhoneのAR Quick Look用の3DアニメーションをHoudiniから書き出す手順

## はじめに

![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/80453ce9-b663-6a3b-8e58-0b7da7e84900.gif)

### 大量のAR用モデルのバリエーションを作成したい！

個人的に大量のiOSのAR用モデルのバリエーションを作成しなければいけないシチュエーションがあり、これまではPythonを利用してやっていたのですが、ワークフロー的に色々手作業がはさまっていてそれがストレスでした。一連の流れをHoudiniで全部できたらいいなぁと思ったのがこの記事で説明している内容を作ったきっかけです。

### iOSのAR Quick Look機能

iPhoneにはUSDZというファイルフォーマットで記述された3DシーンをARのオブジェクトとして画面上に簡単に表示することができる機能があります。これをAR Quick LookとAppleは呼んでいます。

iOSから以下のURLに飛ぶといくつかのサンプルを見ることができます。

https://developer.apple.com/augmented-reality/quick-look/

いくつかはアニメーション付きのモデルなどもあり、iOSデバイスであれば簡単にARとして見ることができるというのは魅力的です（Androidデバイスの場合はGLBフォーマットを代わりに使うことで同じような機能を利用することができます）

### 一般的なUSDZシーンの作り方

現状このAR Quick Lookという機能によって利用できるUSDZというフォーマットのファイルの作り方としては、Appleでは大きく以下の三通りの方法を紹介されています。

https://developer.apple.com/augmented-reality/tools/

 - Reality Composerを使ったUSDZシーンの作成
 - Reality Converterを使った既存の３DモデルのUSDZへの変換
 - Pythonのライブラリ（USDZ Tools）を使ってプログラマブルにUSDZを作成・変換

どれも一長一短があるのですが、Macを持っている人にとっては、すでにARに表示したいモデルを持っていたりする場合は、上に挙げている最初の２つの方法を使うのが一番手軽です。また、Pythonを使いたい人は３つ目の方法を使うことで複雑なシーンを作ることも可能です。

### Apple公式のUSDZの作り方のメリット・デメリット

実際個人的にすべての方法を試しましたが、非常に手軽にAR用の3Dシーンを作ることができます。ただ、３つめのPythonを使う方法が曲者で、大元となるUSDのコンパイル・インストールに始まり、FBXを扱いたい場合はFBXのSDKのインストールなど、一気にハードルが上がります。USDのコンパイルなどは何回も失敗したりして、MacがApple Siliconに移行していく過程でさらにコンパイルが難しくなることが考えられ、正直環境を整えるだけで時間が溶けていくのが想像できげんなりします。

ということでここ最近考えていたのは、どうすれば複雑なシーン・アニメーションをもっと手軽にプログラマブルに（あるいはプロシージャルに）、かつOSに依存せずに作成することができるかという点でした。

### Houdiniでも作れた

結果、たどり着いた一つの方法として、Houdiniを使う方法があることに気づきました。以前からROPノードのひとつにUSDZと書かれているものがあって、これを使えばAR Quick Look用のモデルを書き出せるんだろうと思っていたのですが、使い方がいまいちわからずスルーしていましたが、ちょっと調べてみると案外簡単に使えたので、その方法をこの記事では伝えようと思います。

Houdiniを使うことによるメリットには以下のものがあります。

 - OSに依存しない（Mac, Win, Linuxで実行可能）
 - LOPを使うことによって複雑なシーンを視覚的に管理・作成できる
 - PDG（TOP）を使うことによっていくつかある書き出しの手順を自動化できる
 - 移動・回転・スケール、ボーンアニメーションの他に、頂点アニメーションも作成・書き出しできる

デメリットとしては以下のものがあります。

 - USDZの元となるUSDのコンセプトを多少理解しておく必要がある　(https://graphics.pixar.com/usd/release/index.html)
 - Houdini Indie以上のライセンスがないと書き出したシーンファイルに制限がつく

利用難易度（柔軟性とも言える）でいうと、

Reality Converter < Reality Composer << Houdini <<< USDZ Tools (Python)

というところでしょうか。Houdiniをちょっと触ったことがある人であれば比較的簡単かもです。

### できないこと

 - トポロジーが変わるアニメーション（流体シミュレーションの結果等、メッシュの頂点数や順番が変わるアニメーション）は書き出せません。（VAT的な手法を使って工夫次第でそのハードルを乗り越えることも可能、でも割にあわない）

## Houdiniファイルの構成

まずはHoudiniのプロジェクトの中身を俯瞰で見ておきます。どこで何をやって、どういう順番で処理が走るのかというイメージは持っておいたほうが後から自分なりに応用できると思います。

![2021-12-19_02-05-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/c079558f-7826-1492-1392-fcd2febff9fb.png)

1. Nullノードで全体で使えるパラメータの設定（今回は書き出すファイル名だけ設定）
2. Geometryノード内でUSDZに書き出す対象のアニメーション付きモデルの作成
3. LOPネットワークでアニメーション付きモデルを含んだUSDシーンの作成
4. ROPネットワークでUSDファイルをUSDZに変換（圧縮）
5. ステップ3で作ったUSDの書き出しと、ステップ4を自動化

## Houdiniでアニメーション付きモデルを作る

何はともあれ、書き出したいモデルがないと何も始まらないので、Geometryノード内に書き出したい３Dモデルを作ります。先に述べた通り、トポロジーが変わる（頂点数・面の数が変わったり、順番が変わったり）するモデルはエクスポートできないので、頂点数・面の数は保ったままアニメーションを作ります。

![2021-12-19_02-07-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/87400bce-3718-f543-9023-741a214412e6.png)

今回は簡単な、ボックスが周期的にねじれるようなアニメーションを作りたいと思います。

2.1. ボックスを作る
2.2. UVを設定する
2.3. Point Wrangleで頂点の高さに応じてサイン関数で回転するアニメーションを作る
2.4. 法線を設定する


![2021-12-19_02-19-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/045fd691-99aa-9da1-a8a9-c8abf25808c4.png)

この中で今回特別な処理をしているのは、TOPからのWedgeのパラメータをWrangleで使っている2.3の部分です。TOPのWedgeでは、一つだけパラメータを設定していて、@durという名前で最終的に書き出されるアニメーションの秒数となっています（TOPで$FEND/$FPSというエクスプレッションで現在のフレーム数とFPSで自動で算出）。

Wrangleでは、TOPが走ったときだけこの@durという値が0以外の値になるので、その時だけ$FENDを@durに入れ替えるような処理になっています。なぜこうする必要があるかというと、最終的にUSDZで書き出されるモデルの時間が、フレーム数=秒数になってしまうというちょっと不思議な仕様になっていて、それを回避するためにやっています。試行錯誤の上こうしないとうまくいかなかったため、そういうものなんだと思ってください（バグ？）。将来的にはこういった迂回処理をしなくてもするのかもしれません。

## アニメーション付きモデルが入ったUSDのシーンを作る

LOPネットワークを作り、先につくったアニメーション付きモデルを含んだUSDのシーンを作ります。

![2021-12-19_02-10-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/0d2187a0-23b8-8e27-f165-715e1d70cf1c.png)

3.1. SOPジオメトリのインポート
3.2. マテリアルの作成と反映
3.3. エクスポートされるUSDのレイヤー設定

![2021-12-19_02-19-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/aa176e07-13a9-5cae-bfcb-4139c31db1cd.png)

3.1 では、SOPで作ったジオメトリをインポートします。このときに、Import Path PrefixとLayer Save Pathのパラメータを設定しておきます。Layer Save Pathは、インポートしたSOPジオメトリを焼き込んだUSDを書き出すためのファイルパスです。最終的なUSDZに埋め込まれることになります。

3.2 ではインポートしたモデルに貼り付けるマテリアルを作成・設定します。

3.3 ではデフォルトのレイヤーを設定します。

![2021-12-19_02-13-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/9d37dd51-e1cc-5458-fad7-fbbdcae2357c.png)


3.2のmateriallibraryネットワークの中に入り、USDZで使えるマテリアルを作ります。USDZで使えるマテリアルを作る場合、基本的にUSDという名前がついたノードしか使えません。試した感じ、Addみたいな基本的なノードもUSDZでは使えないようです（要検証？）

今回はとてもシンプルな、テクスチャをdiffuseColorに設定するだけのマテリアルを作っていますusdprimvarreaderノードを使ってvertexアトリビュートに入ったuvの値を取得しています。


## USDシーンをUSDZシーンに変換（圧縮）する

ステップ3で作ったUSDが書き出されたと想定して、その書き出されたUSDファイルをUSDZに変換します。

![2021-12-19_02-16-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/b4fa8d43-50fe-e059-0d9d-11a010287e50.png)

ROPネットワーク内で、usdzipノードを利用して既存のUSDファイルをUSDZに変換できるようにします。

## TOP（PDG）でUSD書き出し・変換を自動化する

このままだと、手動でUSDの書き出しとUSDZへの変換を別々に行わないといけないので、その一連の流れをTOPで自動化しましょう。TOPネットワークを作り、その中に自動化の処理を行います。

![2021-12-19_02-18-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/a5f3dc69-9e30-1ad2-ed83-8b279d63c265.png)

5.1. Wedgeパラメータを設定する
5.2. ステップ3で作ったUSDを書き出す
5.3. ステップ4で作ったusdzipを呼び出しUSDをUSDZに変換する
5.4. 要らなくなった変換元のUSDファイルを削除する

![2021-12-19_02-18-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/4b2c1060-5cdf-bf59-41d2-c0e143642d54.png)

5.1 では先にも言ったSOPで使われるWedgeパラメータを作ります。@durという名前で、アニメーションとして書き出す際の秒数を$FEND/$FPSというエクスプレッションで設定しておきます。

5.2 ではステップ3で作ったUSDのシーンをropusdというノードでファイルに書き出します。書き出すとき、.usdaという拡張子を設定していますが、.usdでも大丈夫です。.usdaにすると良いのは、書き出した後にテキストエディタでファイルを開いて構成を見ることができるので、デバッグに良いです。

5.3 では、ステップ4で作った書き出されたUSDファイルをUSDZに変換するためのROPノードを呼び出します。

5.4 ではいらなくなった変換元のusda（あるいはusd）ファイルを削除します。デバッグ用に残して起きたい場合はこの処理はなくてもいいです。

![2021-12-19_03-12-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/bb5fd9eb-da58-0aed-9a5d-404fe98c9ff5.png)

最後にTOPをCookしてUSDZが書き出されば成功です。あとはメールなりAirDropなりでiPhoneにUSDZを送って確認してみてください。

![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42909/80453ce9-b663-6a3b-8e58-0b7da7e84900.gif)


## ダウンロード

上で説明しているものをパッケージとしてまとめたHoudiniファイルを以下のURLよりダウンロードできます。ご参考までに。

https://github.com/jhorikawa/HoudiniHowtos/tree/master/Snippet-0016%20Export%20Animation%20to%20USDZ

## おわりに

HoudiniのUIに慣れている人であれば、そんなに難しいことはなかったかと思います。HoudiniでプロシージャルにAR用のモデルを生成できるのは、ARモデルのバリエーションを大量生成したいときに便利かもしれません。もしこのセットアップを実際に使ってみた方がいたら、ぜひ [@jhorikawa_err](https://twitter.com/jhorikawa_err) まで教えてください。想像ではゲームに限らず建築とかプロダクトの業種とも使いみちがあるのじゃないかなと思っていたりします。ぜひほかの人の使用例を見てみたいです。