この記事は、Houdiniアドベントカレンダー2021 18日目の記事です。
はじめに
タイトルが不正確ですいません、、ちゃんとしたタイトルはこんな感じです。
「Keijiro神のGeometry Shaderを使用した作例を、HoudiniのSOPで再現してみる」
Keijiro神は、Unityをメインに様々なVFXを作成されている方で、色々な作品制作や技術検証をしながら、それらをほとんど無料で公開してくれています。
こちらに作っているものが挙げられているので、ぜひ覗いてみてください。
Geometry Shaderについてはここでは詳しく説明しませんが、簡潔に言うと、描画パイプラインの中でVertex ShaderとFragment Shaderの間にあるステージで、shaderを書いて、頂点を移動させたり、増やしたりすることができます。
これを使うと色々面白い表現ができるのですが、全てのプラットフォームで動作するわけではなく、DirectXやOpenGLとかでは大丈夫ですが、Metalだと対応してないということもあり、やや扱いづらいところもあります。
過去に、Keijiro神の作例を参考にしながら、Unity上で再現をしてみたりしましたが、あまり実務で使う機会に恵まれずに深堀せずにいました。
https://github.com/YoHana19/VoxelSizeAnimation
https://github.com/YoHana19/VoxelTeleporter
https://github.com/YoHana19/VoxelTeleporter2
https://github.com/YoHana19/Bandlizer
最近はHoudiniを使うことが多くなってきて、頂点色々弄るのはHoudiniの十八番なので、過去Geomeotry Shaderで作ったものをHoudiniで再現してみようと思い至り、やってみた次第です。
一番最後に、Hipファイルも配布しているので、詳しく内容を知りたい方は参照してみてください。
今回作るもの
前置きが長くなりましたが、今回作成したものは上で挙げたものの最初の3つです(本当は4つともやろうと思っていたのですが間に合いませんでした…)。
概要
作り方のコンセプトはどの作例も同じで、Geometryを構成する三角ポリゴンをforeachで一つずつ、四角形や立方体等に変形させる処理をします。
その際に、サイズや中心の位置、変形のタイミング等を外からPrimitive毎に変えられるようにして、バリエーションを作ります。
ということで、一旦三角ポリゴン一つのGeometryに対して、共通の変形処理に関する説明を先にしていきます。
変形処理
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-152852.png)
変形処理は、三角変形・四角変形・立方体変形の3つです。三角変形は、三角系のサイズを変えるだけの変形で、今回の作例では、処理するポリゴンの90%ぐらいはそのままポリゴンを小さく/大きくして、消す/出すをしています。全部を四角形や立方体にするとごちゃごちゃで全然見えなくなるからです。
これらの変形処理は、実際の作例でも使うのでSubnetwork化しています。
三角変形
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-15-45-46_1.gif)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-153409.png)
まず、必要なattributeが揃っているかをチェックします。tri_morphというattributeで各頂点のポリゴンの中心からの距離を制御することで、三角ポリゴンの大きさを制御します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-153531.png)
Extract Centroidで、ポリゴンの中心をcentroidという名前のattributeに格納します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-153555.png)
あとは、tri_morphの値を、ポリゴンの中心から各頂点へのベクトルに乗算することで大きさを制御します。tri_morphの値が0の時は、ただの点になるので、削除してしまいます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-153625.png)
四角変形
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-16-02-15_1.gif)
この処理は、実際の作例に少し寄せた内容になっていて、完全に汎用化はしていません。具体的には、常にy軸に平行な四角形で、かつpivotとcenterの位置を指定して面の向きを制御するようにしています。詳しくは後述します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-154714.png)
まずは、必要なattributeのチェックです。今回制御に使うattributeは以下の4つです。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-154809.png)
quad_size:四角形の大きさ
quad_pivot:面の向きのベクトルの開始点
quad_center:四角形の中心の位置
次に、点を一点追加し、ポリゴンのvertexに加えて四角ポリゴンにします。
位置やuvなどは、任意に選んで問題ないです。今回は、2番目のvertexの位置に追加し、uvは四角形になった時に対角になる1番目のvertexのuvを入れています。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-162355.png)
tan_dirに、各頂点が中心からどの方向にあるか(タンジェント空間)を決めて、格納しておきます。
これも任意に選んで問題ないですが、ポリゴンの向きは頂点の並びが時計回りの方向になるので、そこだけ注意してください。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-161436.png)
変形の処理をしていきます。まず、ワールド空間での四角形の中心から各頂点への方向を求めます。(タンジェント空間のxyz方向をワールド空間に変換)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-162649.png)
タンジェントy方向(wld_tan_y)は、前述したようにy軸に平行なので、(0, 1, 0)になります。
タンジェントz方向(wld_tan_z)は、外から指定できるpivotからcenterへのベクトルになります。ただし、y軸に平行にするので、yの値は無視します。これで、pivotに対して外側を四角形が向くようになります。
タンジェントx方向(wld_tan_x)は、wld_tan_xとwld_tan_zの外積から求めます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-163238.png)
以上で求めたものを、先に決めておいたtan_dirに乗算してcenterと足せば、ワールド空間での各頂点の位置が出ます。その際に外から制御できるsizeをベクトルに乗算しておけば、四角形の大きさを制御できます。
あとは、元の位置とその四角形の位置とでlerpさせれば、変形具合を制御できます。
最後に重なった点をfuseでくっつけておきます。
立方体変形
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-17-46-16_1.gif)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-164907.png)
ちょいと長めですね。少し面倒なのは、生成した頂点と元の頂点との対応付け当たりです。
まずは例のごとく、必要なattributeのチェックをします。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165254.png)
cube_morph:立方体への変形具合(0=三角、1=立方体)
cube_offset:元のポリゴンの中心位置からのオフセット
これらのattributeをdetailに移し、また、今回は元のポリゴンの大きさを変形後の立方体の大きさに反映させるため、中心から各頂点への距離の平均をdetailのattributeに格納しておきます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165309.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165325.png)
次に、Addで8つのポイントを追加して、それらのポイントの元の位置(元の三角ポリゴンのいずれかの頂点)及び変形後の位置の設定、立方体の各面のポリゴン化を行います。ただし、この時注意しなけらばならない点として2つあります。
① 頂点の順番:時計回りの向きがポリゴンの向きになるので、ポリゴン化の際に順番に注意する
② 元の位置との対応:立方体の各面の頂点に元の三角形の3つの頂点が全て含まれる形で対応させておく
今回は、下の写真になるように各種設定しました。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-173022.png)
赤:元のポリゴンの頂点番号
新規に作成した8つのポイントに対し、対応させる元の三角ポリゴンの頂点の位置をorigin attributeに格納します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165344.png)
元のポリゴンの中心位置に、外から制御できるcube_offsetを足して、立方体の中心位置にします。
サイズは、外から制御するcube_scaleと、先ほど求めた元のポリゴンの大きさを乗算して立方体の大きさを出します。
後は、各点について中心からの方向を設定し、大きさをかけたものを中心位置に足して、立方体変形後の位置を計算、goal attributeに格納します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165357.png)
最後に、頂点を選択して、立方体の各面をポリゴン化します。この時に、頂点の順番が、表面について時計回りになるように注意してください。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165416.png)
作例で使うので、立方体各面のuv2も貼っておきます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165451.png)
元のポリゴンの各種attributeを引き継ぐため、一旦originの位置に各頂点を移動させてから、attribute transferで、attributeを移します。(この辺は任意です)
最後に、設定したoriginとgoalの位置をcube_morphでlerpさせて、変形具合を制御します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-165538.png)
立方体変形については、このやり方だとそこまで綺麗な変形にならないので、もう少し良い方法があると思います。もし、お気づきの方がいればぜひ教えて頂ければと思います。
これで、共通部分の変形処理の説明が終わったので、各作例の説明に入ります。
内容は、変形処理で外から制御可能にしたパラメータをどうアニメーションさせて作例のようにするかになります。
作例① Quad Teleport
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-17-57-10.gif)
まずは下準備です。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-180823.png)
まず、rubbertoyをDivideして三角ポリゴンにします。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-180232.png)
次に、後に変形処理で変形度合いを制御するパラメータの元となるmorph attributeを作ります。
大した内容ではないので詳しくは説明しませんが、2つの平面を上から下にアニメーションさせ、各primitiveのyの位置が、下の平面と上の平面の間にある時に、morphの値が0→1に変化します。
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-20-29-11.gif)
なので、下の平面が通過した時からエフェクトが開始(morph=0)され、上の平面が通過するときに終了(morph=1)するようになります。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-181622.png)
set_groupでは、単純に三角ポリゴンを小さくして消失させるポリゴンと、四角変形させるポリゴンをグループ分けし、三角変形の方をvanishというグループにします。今回は96%のポリゴンがそのまま小さくなって消失します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-180450.png)
後で、Colorなどを付ける時に便利なので、primnumをidに入れておきます。
さて、ここから各変形のパラメータ制御の説明に入ります。
まずは、三角変形から説明しますが、こちらは至って単純です。先ほど作ったmorphの値を、1から引いてtri_morphに入れて、プリミティブ毎に変形処理を行うだけです。
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-17-58-58.gif)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-182051.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-182124.png)
続いて四角変形ですが、こちらの方も変形の冒頭で三角ポリを拡大する演出を入れているので、三角変形も少し使っています。それも含めて、順に説明していきます。
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-17-59-14.gif)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-182727.png)
まずは、quad_pivotの制御です。
今回の作例では、quad_pivotは、四角形が回転する中心点として使用しています。使っているrubbertoyが、上部分とした部分でxz平面での中心がだいぶ異なるので、morph用にアニメーションさせていた平面でrubbertoyを切り取り、各フレームでの中心点をとってつなげたラインを使っています。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-183355.png)
このラインに対し、各primitiveでnearpointをして、一番近いポイントの位置を、quad_pivotに指定しています。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-183426.png)
次に、冒頭での三角ポリゴンの拡大をさせるために、inflation_morphで、tri_morphに値を設定します。rampの値を制御することで、冒頭に演出が入るようにします。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-183445.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-225534.png)
set_quad_centerで、四角形の中心位置となるquad_centerの値を設定します。
quad_pivotの位置を中心に、各primitiveまでのベクトルを出し、それをmorphの値をrampで制御して回転させます。さらに、morphの値をrampで制御した値で、quad_pivotからの距離を制御することで、最終的にquad_centerが、morphに合わせて徐々に回転しながら中心から遠ざかるようにアニメーションさせます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-184423.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-225643-1024x758.png)
quad_sizeは、最終的に0になるようにrampを制御して、最後消えていくアニメーションにします。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-183653.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-225707.png)
最後に、quad_morphの値も、元のmorphをrampで制御して、中盤くらいで四角形に変形しきるように調整します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-185101.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-225722.png)
これで、各パラメータの設定ができたので、あとは、各primitive毎に三角変形と四角変形の処理を施していきます。
後は、変形処理は重たいので、キャッシュをとった後、ルック調整に必要なColorやEmissionなどをmorphなどに合わせて設定して終了です。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-185439.png)
作例② Voxel Animation
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-19-15-15.gif)
この作例はかなり単純で、morphの制御や、三角変形と立方体変形を分ける所などは作例①とほぼ同じなので割愛します。
肝は、cube_scaleのアニメーションのさせ方なので、そこの説明だけします。
といっても、そこまで複雑ではなく、3つの頂点のuv値をシードにして、x,y,zそれぞれ、sinでアニメーションさせ、適当なスケールを乗算して、cube_scaleに設定しているだけです。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-192835.png)
その後、各primitiveに立方体変形処理を施しています。
作例③ Voxel Teleport
![](https://heyyocg.link/wp-content/uploads/2021/12/D__Houdini_GeometryShader.hiplc-Houdini-Indie-Limited-Commercial-19.0.383-Python-3-2021-12-18-19-15-42.gif)
こちらも、ベースとなるmorphの制御や、三角変形と立方体変形を分ける所などは作例①とほぼ同じなので割愛します。
cube_scaleとcube_offsetのアニメーション部分の制御が肝要なので、そこの説明をします。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-193533.png)
まず、cube_teleport_offset_scaleで、cube_scaleとcube_offsetの設定をします。演出としては、上の方から縦に長いキューブが落ちてきて、徐々に通常の立方体になるので、それを踏まえて値をアニメーションさせます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-194255.png)
今回は、変形後から元に戻る演出なので、morphの値は1→0に変わります。
moveの値は、offsetやscaleの大きさを制御する値で、morphが1→0.75に変化する間に1→0に変化します。なので、最初の4分の1の時間で、上から元の位置に落ちてくるアニメーションになります。
また、scaleについても、yについては大きめの値から1に変化させ、xzについては0から1に変化させることで、縦長のキューブが普通の立方体になるアニメーションをつけています。
後は、少しノイズなどを使ってバラつきを与えています。
次に、落ちてきた立方体が三角形に戻るまでの少しの間に、作例②のように少し大きさをアニメーションさせたいので、cube_scale_animで、cube_scaleを調整します。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-193631.png)
実装方法は大体作例②と同じなので、説明は割愛しますが、落ちてき終わった後に、アニメーションをさせるため、タイミングの制御をrampで行っています。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-193753.png)
変形のタイミングもrampで制御し、いい感じのタイミングで立方体から元の三角形に戻るようにしています。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-195255.png)
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-193727.png)
あとは、三角変形と立方体変形それぞれ処理を施していきます。
![](https://heyyocg.link/wp-content/uploads/2021/12/2021-12-18-195429.png)
見た目の調整
見た目の調整に関しては、詳しい説明はしませんので、興味がある人はHipファイルを覗いてみてください。
ここでは概要だけ説明します。
rubbertoyの中にあるmaterialを直接編集して、emissionの値だけ付け加えています。基本的には、uv2などを使って四角形や立方体の各面のedge付近をemissionさせたり、voxel teleportでは、最初の落ちてくるところで全面emissionさせたりしています。
emissionの値のコントロールも、morphの値をrampで調整して制御しています。
グローは、後処理でHoudiniのコンポで付けています。emission部分だけをうまく抜き出す良い方法を知らなかったので、LumaMatteで、Luminanceの高いところを抜き出して、blurを重ねてグローを付ける方法をとっています。
本当はkarmaを使いたかったのですが、attributeをmaterialに持って行けず、断念してmantraになってしまいました…
おわりに
こちらHipファイルになります。Houdini19.0.383で製作しました。
https://drive.google.com/file/d/1gB2NI7sZO6Gdx43zPdLPsMwV1HZY3wzg/view?usp=sharing
所感としては、「重い!」です(笑)
Unity でGeometry Shaderで実装すれば、サクサクランタイムで動くのに、180フレームのキャッシュとるのに、15分とかかかりました…
ただ、Geometry Shaderで書くとブラックボックス部分があってよくわからないところも出てきがちですが、Houdiniなら書いた通り動いてくれるので、実装のしやすさは良いですねやはり。
あとは、やはり肝なのはパラメータをどうアニメーションさせるかで、今回の作例はその辺のアイディアを既にKeijiro神が出してくれているのを真似ただけなので、ここから自分なりにどんなバリエーションが出せるか、気が向いたときにチャレンジしてみようと思います。
最後に、実はこれをHoudiniで再現した真のモチベーションに、UEで動かしたいというのがあって、UEでGeometry Shaderの動かし方が分からないので(どなたか知っている人いたら教えてください!)、一旦Houdiniで作ってUEに持ってこうと考えたりしてました。
これも気が向いたときに、チャレンジしてみようと思います。