Unity 2023.2aからVFX GraphでカスタムHLSLが実行できる話(Custom HLSL Block)
はじめに
TL;DR
Custom HLSL Block を使えば、.hlsl
ファイルに記述した関数を VFX Graph の中で実行できる。
記事の概要と対象読者
タイトルにもある通り、自作の HLSL ロジックを VFX Graph で使える「Custom HLSL Block」という機能が新しくリリースされていました。Unity 2023.2 から使えるようです。
個人的にはリリース前から気になっていた機能だったので、使用方法を調査し、記事の中で紹介します。
本記事では次のような内容を取り扱います。
- Custom HLSL Block の概要
- Custom HLSL Block の使用方法
これらの内容を扱うのに際して、Unity HDRP や VFX Graph に関する基本的なことがわかっている前提としていますので、ご了承ください。
検証環境
検証環境を次に示します。
env | |
---|---|
OS | Windows 10 Home, Windows 11 Home |
Unity | 2023.2.0a22 |
HDRP | 16.0.2 |
VFX Graph | 16.0.2 |
サンプルプロジェクト
Custom HLSL Block を使用した VFX Graph のサンプルを次の GitHub にて公開しております。
Custom HLSL Blockについて
VFX Graphのロードマップを確認
本記事の執筆時点(2023/08/05)では Custom HLSL Block は Unity のα版で使える機能みたいです。
VFX Graph を含む Unity のグラフィクス関連の機能はロードマップが公開されておりますので、将来どんな機能が追加される予定なのか、どのバージョンで予定されていた機能が追加されたのかなどを確認できます。
Custom HLSL Blockの項目を見てみると、6/23 くらいに Unity 2023.2.0a19 で使えるとのコメントがついていますね。
VFX Graph にはユニークな機能が継続的に追加されているので、時々ロードマップを確認すると面白い発見があって楽しいです。
Custom HLSL Blockの概要
Custom HLSL Block とはその名の通り、VFX Graph 内で HLSL のコードを動かせるようになる機能です。
基本的に VFX Graph はノードベースでロジックを組むものなので、処理をまとめたり再利用したい場合にはサブグラフを作り、そのサブグラフの中でノードを組む必要がありました。
もっと複雑な処理をしたい場合には C#や Compute Shader によりプログラムを組み、計算結果を外出しにして VFX Graph に Exposed Property から渡すこともできます。
Custom HLSL Block を使えば真に VFX Graph のなかでコードを実行できるので、C#や Compute Shader を使うしかなかった一部の実装を VFX Graph のなかで完結できます。
考え方自体は簡単で、例えば次のような HLSL の関数を作成します。
引数で受け取った整数値に1を加算して返すだけの簡単な関数です。
int AddOne(in int value)
{
return value + 1;
}
このロジックを HLSL ブロックにすると、次図の真ん中にあるようなオペレータノードが出来上がります。受け取った Value に 1 を加算した値が Out から出てくるノードです。
ブロックを作ってみる
それでは具体的な手順を踏みながらブロックを作成してみましょう。
作例として今回は「球の表面上のランダムな位置にパーティクルの position を設定する」ブロックを作成してみます。
まずは任意の場所に.hlsl
ファイルを作成しましょう。このファイルに書かれた関数が Custom HLSL Block で実行されるロジックになります。ここにSetPositionOnSphereSurface
という関数を作成し、パーティクルの position を球面上のランダムな位置に設定するロジックを記述します。
void SetPositionOnSphereSurface(inout VFXAttributes attributes, in float3 positionOffset, in float radius)
{
const float pi = 3.14159265;
float cosTheta = -2.0 * VFXRAND + 1.0;
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
float phi = 2.0 * pi * VFXRAND;
attributes.position = radius * float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta) + positionOffset;
}
この関数ではVFXAttributes
型の inout 引数attributes
を受け取っています。
attributes
にはパーティクルの情報が格納されており、ここから position や lifetime、color といった値を取得・変更できます。オペレータノードとは違い、ブロックでは値を出力しない代わりにattributes
を受け取る仕組みになっているということですね(そのため関数の引数は void 型です)。
関数の中身は球の表面上の点をランダムにサンプリングしてattributes.position
に格納するコードです。球面上の点の一様乱数を生成する方法は次の記事を参考にしました。
サンプリングする球はoffsetPosition
とradius
により中心と半径を変更できるようにしています。
コードを見ていると、VFXRAND
という変数を使っていますが、これにより
一様乱数を取得できます。どうやらブロック限定の変数みたいです。他にも float3 型の一様乱数などを取得できます。
次に任意の VFX Graph を作成します。
Unity 2023 だと VFX Graph にテンプレートがあるんですね。今回は「Simple」を選んで、initialize コンテキストに HLSL で作成したロジックを適用してみます。
まずは Initialize コンテキストに Cutsom HLSL ブロックを追加しましょう。デフォルトではCustomHLSL
という関数が設定されているみたいです。
Edit ボタンを押すとコードの中身を編集できます。デフォルトで書かれているコードは以下の通りでした。
void CustomHLSL(inout VFXAttributes attributes, in float3 offset, in float speedFactor)
{
attributes.position += offset;
attributes.velocity *= speedFactor;
}
デフォルトで設定されているHLSLのコード
ここのテキストボックスの中身を編集して保存すればコードを変えられるのですが、
せっかく HLSL ファイルを作ったのでそちらを Custom HLSL Block に適用しましょう。
Custom HLSL Block を選択した状態でインスペクタビューを確認すると次図のように「Shader File」という項目があるので、そこへ HLSL ファイルを D&D します。
Custom HLSL Blockを選択した状態のインスペクタ
すると Available Function の欄に先ほど作成した関数名が表示され、無事実行できる状態になりました。in 引数で指定していた positionOffset
と radius
を外部から指定してやれば初期化時に球面上のランダムな点に位置を設定するコードが動いているのが確認できます。
Available Functionに関数名が指定され、動く状態になったブロック
シーン上で動いているのを確認
おわりに
HLSL で実装した関数を VFX Graph で実行できる Custom HLSL Block について解説しました。まだこの機能自体は 2022 では扱えないですが、ノードベースの仕組みの中でコードも扱えるという革新的なものなので、今後の動向も追っていきたいですね。
あと、どのようなユースケースがあるのかも考えてみたいです。
参考文献
Discussion