Slide 1

Slide 1 text

軽率にVFX Graphと Compute Shaderを 組み合わせるテクニック にー兄さん(@ninisan_drumath) VFX Graph LT会

Slide 2

Slide 2 text

にー兄さん(@ninisan_drumath) 株式会社ホロラボ ソフトウェアエンジニア Iwaken Lab. / Babylon.js勉強会運営 お仕事ではUnityを使ったxR開発がメイン 趣味ではBabylon.jsをよく触る うちの猫たち→

Slide 3

Slide 3 text

本日の話 VFX GraphとComputeShaderを組み合わせることについて 何が嬉しいのか、どうやって実現するのかを紹介

Slide 4

Slide 4 text

最近こんなものを作りました ここで使用した、ComputeShaderとVFXGraphの連携についてご紹介

Slide 5

Slide 5 text

アジェンダ 1. CompuetShaderとVFXGraphを組み合わせるモチベーション 2. ComputeShaderとVFXGraphの連携方法 3. おわりに

Slide 6

Slide 6 text

CompuetShaderとVFXGraphを 組み合わせるモチベーション

Slide 7

Slide 7 text

VFX Graphで出来ることは多い VFXGraphには豊富なノードが用意されている SDFのサンプリングや Perlinノイズの生成、 Switchなどの制御もできる 最近はProbability Samplingノード 面白いなって思った

Slide 8

Slide 8 text

しかし限界がある ノードベースならではの悩み? VFX Graphでできないこと、苦手なこと - ループ処理 - 変数定義と格納 - バッファへの書き込み Cutsom HLSLノードによって解決するものもあるが メンテナンス容易性などの考慮は必要 BoidsはForループによるバッファのサンプリングと書き込みが必要

Slide 9

Slide 9 text

一部のロジックを外部化して表現力を補う VFX Graphが苦手なロジックは他で補える

Slide 10

Slide 10 text

一部のロジックを外部化して表現力を補う Unityで属性計算するための選択肢はいくつかある - MonoBehaviour - Entity Component System - Compute Shader 構成例) - C#で全てのパーティクル属性を毎フレーム計算 - VFXGraphはそれの可視化にのみ使用する

Slide 11

Slide 11 text

例)Boidsの場合 Boidsは他のBoidの情報を参照するものの計算順序に制約はない そのため個々のBoidの状態更新処理は並列化できる

Slide 12

Slide 12 text

Compute Shaderとは 汎用的な計算をGPUで行う GPGPUのための仕組み UnityではHLSL言語で記述 Kernelという単位で処理される KernelはThreadという単位でまとめて実行され、 スレッドはThread Groupという単位でまとめて実行される

Slide 13

Slide 13 text

ComputeShaderの使い道

Slide 14

Slide 14 text

ComputeShaderとVFXGraphの 連携方法

Slide 15

Slide 15 text

3つのシステムとデータフロー ComputeShaderとVFXGraph、 そしてそれをつなぐC# 計算結果を特定のデータ型として 橋渡しする必要がある

Slide 16

Slide 16 text

AttributeMap vs GraphicsBuffer VFX Graphへ連続的なデータを渡す方法は主に2種類 - AttributeMap - GraphicsBuffer AttributeMapの実態はテクスチャ Sample AttributeMapノードがある pCacheはAttributeMap使うよね GraphicsBufferは配列ライクに扱えて手軽 2次元的なデータであればAttributeMapがいいかも

Slide 17

Slide 17 text

ComputeShaderの実行 Kernelの定義 #pragma kernel CSMain float num; RWStructuredBuffer buf; [numthreads(4,1,1)] void CSMain(const uint3 id:SV_DispatchThreadID) { buf[id.x].x = num; buf[id.x].y = num; buf[id.x].z = num; } ほぼ普通の関数だが numthreadsでスレッド数を指定 #pragma kernelで関数名を指定

Slide 18

Slide 18 text

ComputeShaderの実行 Kernelの実行 1. Kernelを取得 2. パラメータを指定 3. スレッドグループの数を指定してDispath _csMainKernel = computeShader.FindKernel("CSMain"); computeShader.SetFloat("num", 1.0f); computeShader.SetBuffer(_csMainKernel, "buf", _graphicsBuffer); computeShader.GetKernelThreadGroupSizes(_csMainKernel, out var x, out _, out _); computeShader.Dispatch(_csMainKernel, count / (int)x, 1, 1);

Slide 19

Slide 19 text

VFX Graphへバッファを渡す パーティクルの属性データはGraphicsBufferとして保持 VFX GraphはGraphicsBufferの読み込みができる

Slide 20

Slide 20 text

tips: StructuredBufferをVFXGraphでサンプルする [VFXType(VFXTypeAttribute.Usage.GraphicsBuffer, "BoidsData")] public struct BoidsData { public Vector3 Position; public Vector3 Velocity; }

Slide 21

Slide 21 text

グラフはとても単純 外部にロジックを委託しているので グラフはすごいシンプル 色や形状を決定する部分は もっと作りこめるかも ここまでやると ComputeShaderの計算結果を VXFGraphに反映できた

Slide 22

Slide 22 text

おわりに

Slide 23

Slide 23 text

まとめ VFX Graphの表現力を拡張するために 属性計算ロジックを外部に委託するという選択肢がある GraphicsBufferを使ってComputeShaderの計算結果を VFXGraphへ渡すことができる

Slide 24

Slide 24 text

参考文献 今回のサンプルプロジェクト https://github.com/drumath2237/Boids-Unity-ComputeShader-Sandbox コンピュートシェーダー - Unityマニュアル https://docs.unity3d.com/ja/2023.2/Manual/class-ComputeShader.html ComputeShaderを触ってみる その1 ~スレッド編~ https://edom18.hateblo.jp/entry/2017/05/10/083421 GPUの力を解き放て!Unity Compute Shader入門! https://www.youtube.com/watch?v=yiPVxGO-Yg0 Class VFXTypeAttribute https://docs.unity3d.com/Packages/[email protected]/api/Unity Engine.VFX.VFXTypeAttribute.html