【Houdini + ShaderGraph】転送装置エフェクト

2021/10/10に公開

Tales of ARISE の転移装置を参考に、以下のようなエフェクトを作ってみました。
https://www.youtube.com/watch?v=_jzwnlAXF58

使用ツール

Unity2021.2.0b13
Houdini (Indieライセンス)
Photoshop
Substance Designer

サンプルデータ(GitHub)

今回の転送装置エフェクトはGitHubにて公開中です
(Houdiniプロジェクトは含まれていません)
https://github.com/rngtm/Unity-TeleportVFX

エフェクトの展開

エフェクトの構成としては以下のようになります。

六角形表現

六角形が上昇する表現では、Houdiniを利用して作成した3Dモデルを利用しています。

六角形表現

3Dモデル(Houdini)

六角形を円柱上に敷き詰めた3Dモデルになっています。
頂点カラーには、アニメーションに必要な情報を載せます。

チャンネル 詳細 用途
R 六角形グラデーション 六角形の模様の作成
G Y方向グラデーション Y方向のアニメーションの時間ずらし

以下のようなノードで3Dモデルを作成します。

手順1 : 六角形の作成

Circleノードを利用して、以下のような六角形を作成します。

手順2 : 頂点カラーの設定

中心のポイントにはカラー0(黒)、外側のポイントにはカラー1(白)を割り当てて、内側から外側へのグラデーションを作成します。
中心のポイントの番号は0になっているので、ポイント0にカラー0を割り当てます。

念のため、番号0以外のポイントにはカラー1を割り当てておきます。(Circleで作成した直後のジオメトリには頂点カラー1が設定されているため、結果は変化しません)

手順3 : 六角形を並べる

六角形を隙間なく平面上に並べます。

隣接する六角形の作成

六角形をX方向に1.5、Y方向に0.5\sqrt 3 ズラすことで、隣接する六角形が求まります。

Copy and Transformノードで六角形をX方向に1.5、Y方向に0.5\sqrt 3 ズラしたものを作成します。
Total Number は 2 に設定します。

六角形を横に複数個並べる

六角形の位置をX方向に3ずらすと、二つ隣の六角形が求まります。

Copy and Transformノードで、3ずつズラしたものを複製します。
Total Number はお好みの値にします。

六角形をタテに並べる

正六角形をY方向に \sqrt(3)ずらすと、タテに隣接する六角形が求まります。

Copy and Transformノードで、六角形をY方向にsqrt(3)ずつずらしたものを複製します。
Total Numberはお好みの値にします。

Copy and TransformノードのTotal Numberの数を調整して、六角形の密度を上げておきます。

手順4 : 平面から円柱への座標変換

手順3で作成した平面の六角形タイル(画像左)に座標変換を適用し、円柱状へ変換します(画像右)。

座標変換について(数学)

座標変換について(数学)

元の頂点のX座標をラジアン、Y座標を円柱上でのY座標として座標を計算します。
これにより、平面を円柱へ変換することができます。
N個の正六角形を並べたヨコの長さ 1.5N は、円柱上での 2 \piに相当します。

長さ 1.5N の導出
正六角形をN個横に並べたとき、円柱を1周する全体の長さは、以下のようにして求めることができます。

VEXによる実装

AttributeWrangleノードを利用して、座標変換を実装します。

convert_to_tube
int num_x = chi("num_x"); // 六角形の数
float radius = chf("radius"); // 円柱の半径
float hexSize = chf("hex_height"); // 六角形の高さ

// バウンディングボックスの最小・最大を求める
vector min, max;
getbbox(geoself(), min, max);

// X座標を範囲 0~1.5Nから 0~2πへ変換したものをラジアンΘとして扱う
float x = @P.x;
float size_x = 1.5 * num_x;
float radian = efit(x, min.x, min.x + size_x, 0, 2.0 * $PI);

// Y座標
float y = @P.y * hexSize;

// 円柱座標の計算
@P = set(cos(radian) * radius, y, sin(radian) * radius);

手順5 : 頂点カラーGの設定

頂点Y座標を0~1の範囲に収まるように範囲変換し、頂点カラーGチャンネルへ格納します。
こちらの情報は、六角形アニメーションのY方向の動きのズレを作るために使用します。

あとはこちらのモデルをFBX出力すれば完成となります。

六角形Animation用シェーダー

六角形が現れるような表現を行うシェーダーを作成します。
AnimationTimeという時間パラメータでアニメーションをコントロールできる形になっています。
https://www.youtube.com/watch?v=wykXINdOWWM

シェーダーグラフは以下のような実装になっています。
六角形グラデーション(頂点カラーRチャンネル)に、Stepを適用して線を抽出します。
Stepのしきい値に対して、時間やY方向グラデーション(頂点カラーGチャンネル)を減算することで、六角形が動くアニメーションになります。

オーラ表現

角度によって濃さが変わるようなオーラを作ってみました。
真横から見たときはオーラの色が濃く、上から見たときはオーラの色が薄くなります。

https://www.youtube.com/watch?v=6iLrQI4KZL4

角度によって濃さを変える

角度によって濃さが変わる表現を実装するためには、視線ベクトルとY軸上方向ベクトルの内積を利用します。
以下の図のuはY方向ベクトル(0, 1, 0)を表しており、vはカメラ方向を向くベクトルを表しています。
vベクトルは、ShaderGraphのView Directionノードで取得できます。
u・vはuとvの内積を表しています。

内積(u・v)はカメラ位置が高くなると大きい値を取り、カメラの高度が下がると小さい値を取ります。
これをアルファとして利用することで角度によって濃さが変わるオーラ表現を作ることができます。
今回はカメラ位置が高くなると薄くなる、という表現を作りたいので1.0から内積結果を引き、0-1を反転します。

ShaderGraphで実装すると、以下のようになります。

フレネル効果

フレネル効果は、六角形とは別の円柱に張り付けています。

ShaderGraphは以下のような実装になっています。

  • 円柱の内側・外側の透明度をコントロールするため、Remapを使ってフレネルの色の範囲を変換
  • フレネルの色味(0~1)に対して、Rampテクスチャで色付け
  • 円柱の濃さはアニメーションからコントロールするため、プロパティFresnelAlphaを用意

Rampテクスチャは以下を使用しています。

Discussion