🎇

Unity 2023.2aからVFX GraphでカスタムHLSLが実行できる話(Custom HLSL Block)

2023/08/10に公開

はじめに

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 にて公開しております。

https://github.com/drumath2237/VFX-Graph-Custom-HLSL-testbed

Custom HLSL Blockについて

VFX Graphのロードマップを確認

本記事の執筆時点(2023/08/05)では Custom HLSL Block は Unity のα版で使える機能みたいです。
VFX Graph を含む Unity のグラフィクス関連の機能はロードマップが公開されておりますので、将来どんな機能が追加される予定なのか、どのバージョンで予定されていた機能が追加されたのかなどを確認できます。

https://portal.productboard.com/unity/1-unity-platform-rendering-visual-effects/tabs/9-vfx-graph

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 から出てくるノードです。

img

ブロックを作ってみる

それでは具体的な手順を踏みながらブロックを作成してみましょう。
作例として今回は「球の表面上のランダムな位置にパーティクルの position を設定する」ブロックを作成してみます。

まずは任意の場所に.hlslファイルを作成しましょう。このファイルに書かれた関数が Custom HLSL Block で実行されるロジックになります。ここにSetPositionOnSphereSurfaceという関数を作成し、パーティクルの position を球面上のランダムな位置に設定するロジックを記述します。

SetPositionOnSphereSurface.hlsl
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に格納するコードです。球面上の点の一様乱数を生成する方法は次の記事を参考にしました。
サンプリングする球はoffsetPositionradiusにより中心と半径を変更できるようにしています。

https://qiita.com/aa_debdeb/items/e416ae8a018692fc07eb#球面上の一様乱数-1


コードを見ていると、VFXRANDという変数を使っていますが、これにより\left[ 0,1 \right)
一様乱数を取得できます。どうやらブロック限定の変数みたいです。他にも float3 型の一様乱数などを取得できます。

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@16.0/manual/Block-CustomHLSL.html#use-macros-to-generate-random-numbers

次に任意の VFX Graph を作成します。
Unity 2023 だと VFX Graph にテンプレートがあるんですね。今回は「Simple」を選んで、initialize コンテキストに HLSL で作成したロジックを適用してみます。

まずは Initialize コンテキストに Cutsom HLSL ブロックを追加しましょう。デフォルトではCustomHLSLという関数が設定されているみたいです。

Alt text

Edit ボタンを押すとコードの中身を編集できます。デフォルトで書かれているコードは以下の通りでした。

CustomHLSL
void CustomHLSL(inout VFXAttributes attributes, in float3 offset, in float speedFactor)
{
  attributes.position += offset;
  attributes.velocity *= speedFactor;
}

Alt text
デフォルトで設定されているHLSLのコード

ここのテキストボックスの中身を編集して保存すればコードを変えられるのですが、
せっかく HLSL ファイルを作ったのでそちらを Custom HLSL Block に適用しましょう。
Custom HLSL Block を選択した状態でインスペクタビューを確認すると次図のように「Shader File」という項目があるので、そこへ HLSL ファイルを D&D します。

Alt text
Custom HLSL Blockを選択した状態のインスペクタ

すると Available Function の欄に先ほど作成した関数名が表示され、無事実行できる状態になりました。in 引数で指定していた positionOffsetradius を外部から指定してやれば初期化時に球面上のランダムな点に位置を設定するコードが動いているのが確認できます。

Alt text
Available Functionに関数名が指定され、動く状態になったブロック

Alt text
シーン上で動いているのを確認

おわりに

HLSL で実装した関数を VFX Graph で実行できる Custom HLSL Block について解説しました。まだこの機能自体は 2022 では扱えないですが、ノードベースの仕組みの中でコードも扱えるという革新的なものなので、今後の動向も追っていきたいですね。
あと、どのようなユースケースがあるのかも考えてみたいです。

参考文献

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@16.0/manual/CustomHLSL-Common.html

https://portal.productboard.com/unity/1-unity-platform-rendering-visual-effects/c/114-custom-hlsl-block

GitHubで編集を提案

Discussion