🐼
Geometry Shaderを使わずにGPUパーティクル(Quest対応)
背景
VRChatでpvpワールド作っていた時にせっかく作ったBoidsパーティクルをQuest対応させたので、そのときの備忘録兼アイデア記事です。
Geometry Shaderを使わずVertex Shaderで対処することでQuest対応しています。
こんなやつ(動画はPC版)
対象のGPUパーティクル
本記事で対象とするGPUパーティクルはphi16さんのFuwaParticleのようなuvでパーティクル識別をして、Geometry Shaderで四角面にして、Fragment Shaderで丸を描くタイプのです。
結構メジャーなパターンのやつではないでしょうか。
(パーティクル識別はSV_PRIMITIVEID使うのもありですね)
内容
アイデアをざっくり言うと、Vertex Shader内で以下2つさえ分かれば、メッシュ内の四角面をパーティクルにすることができます。
- 自身がどのパーティクルに属するか
- 自身が四角面のどの位置に属するか
解決方法
用意したメッシュとVertex Shader内の記載です。
用意するメッシュ
以下のようなUVのメッシュを用意します。
- 作成する四角面(今回は32768個)分均等に128×256で配置
- それぞれの領域内に以下割合で四角面の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