🐼

Geometry Shaderを使わずにGPUパーティクル(Quest対応)

2023/03/11に公開

背景

VRChatでpvpワールド作っていた時にせっかく作ったBoidsパーティクルをQuest対応させたので、そのときの備忘録兼アイデア記事です。
Geometry Shaderを使わずVertex Shaderで対処することでQuest対応しています。

こんなやつ(動画はPC版)

対象のGPUパーティクル

本記事で対象とするGPUパーティクルはphi16さんのFuwaParticleのようなuvでパーティクル識別をして、Geometry Shaderで四角面にして、Fragment Shaderで丸を描くタイプのです。
結構メジャーなパターンのやつではないでしょうか。
(パーティクル識別はSV_PRIMITIVEID使うのもありですね)

内容

アイデアをざっくり言うと、Vertex Shader内で以下2つさえ分かれば、メッシュ内の四角面をパーティクルにすることができます。

  1. 自身がどのパーティクルに属するか
  2. 自身が四角面のどの位置に属するか

解決方法

用意したメッシュとVertex Shader内の記載です。

用意するメッシュ

以下のようなUVのメッシュを用意します。

  1. 作成する四角面(今回は32768個)分均等に128×256で配置
  2. それぞれの領域内に以下割合で四角面のUV配置

uvに幅・高さ掛けてfloorしたらどの領域か、fracしたら領域内のどの位置か(0.25 or 0.75)得られます。

シェーダー

//自身がどのパーティクルに属するか
uint id = floor(v.uv.x * 128) + 128 * floor(v.uv.y * 256); //0~32767のいずれか

//自身が四角面のどの位置に属するか (-1,-1),(-1,1),(1,-1),(1,1)のいずれか
float2 dir = sign(frac(v.uv * float2(128, 256)) - 0.5);

//以下補足
float3 wPos = [idから移動させるワールド座標を一意に取得]

//View座標に対してdir方向に移動し画面上に四角形作成
float4 viewPos = mul(UNITY_MATRIX_V, float4(wPos, 1)) 
 + float4((dir * パーティクルサイズ), 0, 0);
o.vertex = mul(UNITY_MATRIX_P, viewPos);
o.uv = float2(0.5, 0.5) * dir;

自身がどのパーティクルに属するか分かれば異なるVertex Shaderでもパーティクルに属する頂点を同じ位置に動かすことができ、
自身が四角面のどの位置に属するか分かればFragment Shaderに渡す四角面を描くことができます。

以上です。

備考

別途Quest2でGeometry Shader動かす記事を見かけましたが、試したところVRChatでは動かなかったので恐らく普通のUnityアプリの話と思われます。(確かに記事中にVRChatとは一言も書いてませんし。)

Discussion