Houdiniと連携したVJのネタ作り

こちらは[TouchDesigner Advent Calendar 2022](https://qiita.com/advent-calendar/2022/touchdesigner)の13日目の記事です。


# MUTEK
2022/12/09に[MUTEK](https://tokyo.mutek.org/)で映像をしてきました。

MUTEKはカナダ発の電子音楽のフェスティバルで、世界中で開催されています。
そちらの日本版が渋谷ストリームホールや渋谷Wombなどで5日間に渡り開催されておりました。

対戦相手のミュージシャンは[Mars89](https://www.mars89.com/)さん。
極太の低音やダークなアンビエントで攻め攻めの音楽を作っている方です。

当日はこんな感じでチケットは完売。
[Santaさん](https://twitter.com/_s4nt4?s=20&t=JDyQXEGCMo1PxbShu8t97A)がたくさん上げてくれたのでお借りします。
リンク先には４本あるよ。

https://twitter.com/_s4nt4/status/1601249251765276672?s=20&t=Ldivq7wYokRjY0TSj4pdEg

今回はソロではなくHEXPIXELSでの映像演出でした。
HEXPIXELSは[比嘉了さん](http://satoruhiga.com/)と一緒に数年やっているユニットで、
色んなDCCツールやプログラミングを駆使したリアルタイム映像を得意としています。

HEXPIXELSのシステムに関してはこちらが詳しいです。
https://www.mouse-jp.co.jp/creator/ss/daiv/case_study/hexpixels.html

ざっくり書くと、

1. オーディオ解析結果の同期
2. ３Dカメラ情報の同期
3. CG上での空間のルールを決めてネタを作る
4. 1,2,3を踏まえて作ったネタを、２台のPCから同時に出してミックスする

という点が重要です。

普通に複数人でVJをすると、様々なネタをVJミキサーで**カチャカチャ切り替えるカット演出**になりますが、
HEXPIXELSでは、２台のコンピュータでお互いが自由なタイミングでネタを出し入れしても、**ワンカメラでの演出が可能に**なります。
初見では１台のPCで普通に出しているように見えると思いますが、
今回は僕はTD、比嘉さんはUE5での制作でした。

# ネタ概要

さて、今回の空間ルールは、半径300メートルの半球の中心に、半径5mの半球がある、というルールでした。
半球ドーム自体の形状を変えたり、そこから何かが広がったり的な感じです。
何故このルールにしたのかは、色々と長くなるので割愛。

僕パートの映像だけ少し置きます。
半球ドームネタを中心に、周りに色々な物がおります。
何かビカビカやビクビクしてるのは内部的には音反応してるからです。

https://www.youtube.com/watch?v=OOJQKvbd5aA

で、終演後にお客さんから、何をどうやって作ってるのか何か書けや、と囲まれたので書きます。

まず、本番の僕のUIですがこんな感じです。汚いねえ。
ボタン１個につき１ネタがオンオフ、下部はポストエフェクト系が刺さっています。

![SnapCrab_NoName_2022-12-12_17-14-59_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/29df6a5f-8a32-785b-19a6-7a2b424a8b3f.png)

というような感じでしたが、全部解説したら疲れてしまうのでピックアップして書きます。

# ワークフロー

ざっくり説明すると、

1. Houdiniでモデリング
2. 必要なアトリビュートを仕込んだモデルをbhclassicで書き出し
3. TouchDesignerで2を動かす

みたいな感じです。

まずはHoudiniで、300mと5mの球体を置きます。
その際に空間を何となく仕切った方がネタが作りやすいので、
ガイド線を引きます。これが無いと何をして良いかわからなくなりがちです。

![SnapCrab_NoName_2022-12-12_17-50-28_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/5ba64a8c-8f17-923f-d01d-76084cfe5d32.png)

また、人のモデルも置いておきます。
これがこの世界の物の大きさの指標になります。
商品説明とかだと良くタバコとか置いてますよね。あれと同じで良く知っているものが画面にあると各物体のスケールがわかります。
**これがないと、どれだけ大きいものを置いても大きく見えない。**

![SnapCrab_NoName_2022-12-12_17-52-5_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/9735b5ec-80c2-6c38-4cc2-77677bde7254.png)

あとはガイド線に沿ってネタを配置していきます。
半球を支えるおじさんなどのクライマックスネタもここで位置と大きさを決めます。

![SnapCrab_NoName_2022-12-12_17-58-49_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/7e0ccd38-f55a-93aa-ae55-9eeeb8f7296b.png)

カメラの位置を変えながらネタを作っていきます。

![SnapCrab_NoName_2022-12-12_18-3-2_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/341f60c5-dde1-cdab-8ef5-dc09dad02bfb.png)

# Houdiniからの書き出し

ここでレイアウトしたものをTDに持っていくわけですが、円上に同じものを配置、とかだと
１個だけ書き出して、TDでインスタンシングした方がデータが軽くて良いです。
**Houdiniでアニメーション付けとレイアウトスケッチ、物量はTDで増やす**
というのを最近良くやってます。

例えば、関節系のアニメーションは、HoudiniのKineFXというリグ回りのツールで動かします。
リグを入れるだけではなく、関節を適当にノイズで動かしてね、みたいなことも可能です。
これをある程度の長さのループモーションにしてVertex Animation Texture(VAT)で書き出します。
Vertex Animation TextureとTDに関しては星野さんの[こちらの記事](https://qiita.com/yasuhiro0122/items/563463069ebafc5ea766)が詳しいです。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/8549ed47-ff1b-c4c1-e8be-2b095f902148.gif)



TDではアニメーションの再生位置を少しずらしながら、円上に配置し直してます。

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/ce86748c-4173-217e-ce60-77b584ba8cb2.gif)

よく見ると輪郭が光っています。
これは音楽の低域に反応させています。
また、色も常に変わっているのですが、
これは中域が入った時だけ少し早く変わるようにしています。
VATの再生処理+上記の処理をシェーダーで書きます。

シェーダー書きは比嘉さんの[Shader Builder](http://satoruhiga.com/post/next-level-shading-in-td/)を使います。
ShaderBuilderは、いわゆるメタルラフネス式のPBRマテリアルを実現すると共に、
シェーダーステージ毎にブロック分けして書いたコード(CodeBlock)を組み合わせて使うので、
シェーダーの再利用が容易になります。
皆もっと使いましょう。

![SnapCrab_NoName_2022-12-12_20-3-26_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/10a8bbcf-c434-7a95-d7dc-af8bb336812c.png)

# 余談

こういう感じで、音に対する即時的な動きと、間接的な動き、指先などの自動的な動きなど、
**動きのレイヤー**を意識して作ると楽しいです。

また、一度、VATや音反応、色替えのコードを仕込んでしまえば、
CodeBlockを**コピペしたら大体動くので楽です。**
もちろん色替えの速度やら、追加で挿すディティールようのノイズやらはネタごとに変えてチューニングします。

VJはネタの消耗戦なので、
動きに限らず、インスタンシング用のCHOPなども、
**コピペで色んな仕組みを転写できるようにしとくと良いです。**
大事なことなので2回言いました。

使い回せるtoxにしろや、というツッコミも予想されますが、
ノイズ関数などの汎用的なもの以外は全ネタで変わるので、
コピペしたものをベースに編集していく、というのがまあまあ楽です。

# もう少しネタの話 + 疑似コード

上記みたいな感じでたくさんネタを作っていくのですが、
反響のあった頭の煮凝りの作り方。

まず頭をHoudiniのVellumでギュっとします。
VellumはHoudiniで布とかソフトボディを作る時の仕組みです。

![ezgif.com-gif-maker (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/342017e8-8539-e137-04b0-e22c2f6e2bea.gif)

次にフレームの23フレ目と24フレ目だけ抜き出します。
![ezgif.com-gif-maker (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/4310b1f1-0f87-4b90-89b1-e3f93604fe70.gif)

23フレ目のメッシュだけをTDに持っていくんですが、この時24フレ目の頂点座標と法線をrestP, rnmlというアトリビュートで23フレ目のメッシュに入れておきます。
何がしたいかというと、この後TDで2つの形状をリアルタイムに行ったり来たりするためです。

ついでに各頭ごとの重心をcenter、そのメッシュが目かどうかを判定する用にeyeを作っておきます。

![2022-12-12 18-48-35.mp4_snapshot_00.09.200.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/32936849-c83a-4ec5-a830-54842a1cd2ac.jpeg)

**bhclassic形式**で書き出すと、fbxと違って何でもTDに持っていけて便利です。

TDではPとrestP、Nとrnmlを音に合わせて行ったり来たりするシェーダーを書きます。
ただ、そのままオーディオのピークに合わせて一気に動かすと、単に頭全体が膨らむだけで面白くないので、
行ったり来たりするための補間の値を、centerをシード値に使ったノイズを入れて、各頭ごとにタイミングをずらす、ということをします。

```
// vertx shader
//uSpeedは中域が入ると早く動くような値

float l = TDSimplexNoise(uSpeed * 1 + geom.center * 100) * 0.5 + 0.5;

geom.P = mix(geom.P, geom.restP, l);
geom.N = mix(geom.N, geom.rnml, l);

// 先ほどの手と同じアプローチ。頭ごとの色をアニメーションさせたい
float c = TDSimplexNoise(uTime.y * 0.1 + geom.center * 100) * 0.5 + 0.5;
c = pow(c, 3.0);
geom.Cd.rgb = vec3(c);
```

```
//fragment shader

// 低域の値でスケールしたフレネルの値をbaseColorに足して輪郭を光らせる
float f = fresnel(geom, 2);
mat.baseColor.rgb *= 1 + f * uLowValue * 10;

// 眼だけ光らせる
mat.baseColor.rgb += geom.eye * uHighValue * 10;

```

輪郭は低域、目は高域に反応して光る、という実装をします。
これで低高域に反応した時に光りながら、中域でギュムギュムと動く頭の塊になります。

![ezgif.com-gif-maker (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100022/f4d9bf30-77c0-3917-9fe2-6d4173b77e40.gif)

頂点数多めで全部違う形で違うタイミング、とかになるとVATだと無理なので、
こういうアプローチで作ります。
**リアルタイムでどう実装できるかを常に考える**
というのが重要だと思います。

ちなみにfbx向けにアトリビュートをいじる必要がありますが、
**UEでもUnityでも全く同じ考え方で動かすことが可能**なので、
シェーダー芸ベースで考えることで、ソフトウェアを覚えなおす苦痛から少し解放されます。

# 終わり

ほとんどHoudiniの記事になってしまいました。
あと、フクロウの書き方みたいな手順すっ飛ばし系の記事でもありますが、
何かの参考になったら幸いです。

# 追記

頭の煮凝りを作るときに、23フレ目と24フレ目を抜いてると書いてましたが、
自分で貼ったgifを見直したら、フレームを止めるノードが１個だけで、え？？となり

**シミュレーションをかけたローポリメッシュでハイポリを動かすノードのパラメータをいじる。
フレームは同じで、ギュムギュム感を変えたものを２つ用意する**

**つまりPoint Deformのパラメータを変えたものを2つ作る**

でした。

やってることあまり変わらず、話がわかりにくいのでそのままにします。