scenario-unity-vfx について
リアルタイム VFX 制作に取り組む Unity のアーティストや開発者向けスキルです。ゲームプレイ上の見やすさ、性能予算、フレーム単位の検証を、Shuriken と VFX Graph の制作工程に取り入れます。
主な機能
- 01ゲーム上の重要度で演出を分類
- 02Shuriken と VFX Graph を選択
- 03マテリアル、テクスチャ、演出の構築
- 04フレーム確認と負荷測定
- 05バッチング、カリング、数の検証
活用シーン
- 01モバイル向け衝撃波や爆発の制作
- 02複数の演出が並ぶ場面の視認性確認
- 03オーバードロー、粒子数、フレーム予算の分析
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-unity-vfxインストール後、Claude Code で/scenario-unity-vfxを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/ut_vfx.pyscripts/AgentKit/Vfx/VfxAudit.csVfxBudget.csVfxFireballKit.csVfxGraphJobs.csVfxMaterials.csVfxMeshes.csVfxMeshFx.csVfxSequence.csVfxShuriken.csVfxStress.csVfxTextures.csVfxUber.csscripts/EditorGraph/Unity.Testing.VisualEffectGraph.EditorTests.asmdefVfxGraphAuthoring.csscripts/EditorGraph/Sdf/AgentKit.Vfx.GraphTools.asmdefVfxSdf.csscripts/Runtime/AgentKit.Vfx.Runtime.asmdefscripts/Runtime/Vfx/FireballProjectile.csVfxStressSpawner.csVfxTier.csscripts/Shaders/VfxOverdraw.shaderVfxUber.shader詳細
Unity VFX(リアルタイムVFXアーティスト)
熟練したVFXアーティストは、まずゲーム体験を優先します。プレイヤーが対象デバイス上で、実際の画面内表示数のもと、何が起きているのか、危険がどこにあるのか、いつ終わるのかを把握できなければなりません。技術(レイヤー、コントラスト、動き、テクスチャ)と予算(フィル、パーティクル、ドローコール、メモリ)の両方をここで評価します。すべてのエフェクトを画面外でフレームごとに進め、確認し、数えます。対象環境:Unity 6000.3.21f1、URP 17.3、VFX Graph 17.3.0、macOS Apple Silicon。この文書に記載された兄弟スキルが利用可能なスキルに見つからない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で実行する場合は、ツールスキーマに基づいて進め、不足があることを明記してください。
必須の背景知識: scenario-unity-expert(チャンネル、レビューループ、6.3の落とし穴、ut_run、ut_review、ut_stat、AgentKit)。
ステータス(2026-09-24、ブラインド評価リファクタリング後): すべての手順を tests/code/unity-vfx/ 経由で Unity 6000.3.21f1 上で実行済みです(結果は archive/tests/unity-vfx/live_results.jsonl、数値は references/procedures.md を参照)。
スタンス(専門家との違い)
- 美しさよりゲームプレイを優先します(元RiotのJason Keyser)。基本形状はゲームプレイ上の境界と一致させます。明るさは重要度に応じて配分します(待機時や通常攻撃は控えめにし、ゲームの流れを変えるものやアルティメットは明るくします)。エフェクトはゲームプレイの状態が終わると同時に終了させます。1つではなく、N個のコピーでレビューします。すべてのルートに
VfxTierを設定し、重要度の段階を確認します(ut_vfx.importance_ladder。観測値:斬撃 0.39 < マズル 0.46 < 衝撃 1.50 < 衝撃波 2.60 < 爆発 5.99)。群衆内での視認性(crowd_readability:ゲームプレイ上の間隔で爆発を20個配置すると20個の形状として認識できますが、2.2 m間隔で密集させると6個しか認識できません)と、停止後の残りも確認します。 - モバイルでは、パーティクルの雲より、メッシュ上を移動するテクスチャが効果的です(NordeusのNikola Damjanov:リリース済みエフェクトの約90%で採用。パーティクルは装飾的な要素であり、エミッターあたり最大100個です。オーバードローはドローコールよりも負荷が大きくなります)。観測値:同じ衝撃波を1つのリングメッシュで描画すると、全体で1レイヤー、ピーク時に0.037フルスクリーン相当(FSE)でした。一方、36個のパフでは、重なる箇所で5~7レイヤーになり、0.35 FSEでした。パーティクル数ではなく、フレームごとのフィルレートを測定します。
- プラットフォームとデータフローに応じてシステムを選択します。 あらゆる対象スマートフォン、WebGL、パーティクルごとのC#、Unity物理演算の衝突には、モジュールを個別にスクリプト可能なParticle Systemを使用します。数千から数百万のGPUパーティクル、深度バッファーによる衝突、デカール、6方向の煙、GPUイベントにはVFX Graphを使用します。VFX Graphにはコンピュート機能が必要で、AndroidではハイエンドURPデバイスの一部のみで動作し(電子書籍)、WebではWebGPU経由でのみ動作します。WebGPUは6.3では実験的機能です。
- 1つのUberマテリアルを使い、Custom Dataからパーティクルごとのデータを渡します。 NordeusのUberシェーダーでは、グレースケールのRをLUTランプで着色し、Gを発光、Bをアルファ上書きに使用します。また、線形フェード、侵食、2つ目のアルファ値、マテリアルごとのBlendとCullを使います。
AgentKit/VFX/Uberはこのシェーダーをテキストで表現したものです。インスタンスごとのバリエーション(侵食カーブ、ランダムなUVオフセット、ワイプ)は、カスタム頂点ストリームを介してCustom Dataモジュールから渡します(Hovl Studio:「シェーダー内で乱数を生成することはできません」)。これにより、1つのマテリアルですべてのバリエーションに対応し、SRP Batcherも有効なまま保てます。監査では、ストリームの順序が契約どおりか確認します。 - VFX Graphは公開APIを備えたブラックボックスです(VFX Graphの電子書籍、UnityのOrson Favrel)。テンプレートをコピーし、少数のプロパティとイベントを公開して、キャッシュ済みIDで操作します。コマンドは遅延実行されます。また、
aliveParticleCountは最初の読み戻しが完了するまで-1を返し、その後は60フレームごとに更新されます(観測値)。メモリ使用量は容量×保存属性数です。バウンズによってカリングが決まります。ソートにはディスパッチのコストがかかります。パーティクルが位置情報だけを必要とする場合はポイントキャッシュを、形状に沿わせたり衝突させたりする場合はSDFを使用します(どちらもスクリプト可能、P8、P12)。 - 各レイヤーに役割を1つ与え、コントラスト、順序、動きを意識します(Sirhaian、Gabriel Aguiar、Nordeus)。加算合成の熱表現の下に暗いアルファの本体を置き、その上にグローを重ねます。アルファレイヤーを重ねる場合は、それぞれに異なるソート順を設定します。ループ以外では線形カーブを避け、速い要素と遅い要素を組み合わせ、ループの開始時にバーストを加え、常に何かが動くようにします。バリエーションシートはアニメーションではなく、パーティクルごとにランダムに選んだ固定フレームとして再生します。火が大きくなる一方で火花は小さくし、すべてのレイヤーをフェードインおよびフェードアウトさせます。
- 借用または生成できるものは描かず、画面に表示されるサイズでインポートします(Simon Trümpler、Nordeusでは通常256、最大512)。借用したフリップブックにはブレンドと減速するフレームカーブを適用し、単純な形状は生成します。スプライトのエッジはガウスではなくモーションブラーで柔らかくし、値が境界からはみ出さないようにします。チャンネルパックされたデータテクスチャはリニアでインポートします(sRGBとして扱うと0.5のグレーが0.21として読み取られます。観測値)。LUTは非圧縮のままにします。
- 6.3では、Shader GraphのパーティクルシェーダーがメッシュパーティクルのGPUインスタンシングを、何も通知せずに無効にします(UnityのFred Moreau)。ドローコール数は同じままでも、キューブ5,000個でメインスレッドの時間が69%増加します(観測値)。監査でこの問題を検出します。修正方法はscenario-unity-shadersで確認できます。
最初に確認すること
最初に一度だけ確認します。対象ティアとフレーム予算(デフォルトはモバイルで 65% の場合に 30 fps = 21.7 ms)、利用可能な計算リソース、最低ティアでのポストプロセス(Bloom が使えない場合は加算レイヤーでグローを再現)、ゲームプレイカメラと距離、各エフェクトの重要度ティア、頻度、ダメージ半径、持続時間、最悪時に画面上に表示されるコピー数(デフォルトは 20)、3 つのエフェクトの柱(Keyser)、ワールドがライティングされているかどうか、時刻。デフォルトは URP、Shuriken、モバイルではメッシュ優先、低ティアではポストプロセスなし、予算は ut_vfx.BUDGETS["mobile"] です。
ワークフロー
- 数値でブリーフを作成します。 ティア、半径、持続時間、コピー数、予算。ゲート:以降のすべてのチェックにしきい値を設定します(
ut_vfx.BUDGETS、ソースに記載、または [追加])。 - システムとバックボーンを選択します(スタンス 2、3)。Shuriken:
レイヤーごとに
VfxShuriken.Build(parent, Layer, seed)を使用します。メッシュレイヤーではLayer.meshを設定します(VfxMeshes.Ring、Cone、QuadXZ、Color32 の頂点アルファ)。VFX Graph:VfxGraphJobs.CopyTemplateを実行し、GUI で公開するか(references/gui-paths.md)、サポートされていない場合はVfxGraphJobs.Authorを使用します。 ゲート:VfxGraphJobs.Contractに、ゲームプレイで使用するすべてのプロパティとイベントが記載されています。 - テクスチャとマテリアル。
VfxTextures.ImportVfxTexture(Clamp、ティアに応じたサイズ。データテクスチャでは sRGB をオフ);URP のパーティクルマテリアルにはVfxMaterials.Particle(インスペクターロジックはBaseShaderGUI.SetMaterialKeywordsを使用);Uber マテリアルには、アセット上でキーワードを設定し、実行時には決して切り替えないVfxUber.Create(path, UberSpec)を使用します。炎、火花、軌跡、魔法には Unlit を使用します。煙と塵には、ライティングが変化する場合は Simple Lit または six-way を使用します。URP のパーティクルシェーダーは影を落としません。ゲート:レンダーキューが 3000、想定されるキーワードが設定済み、マゼンタ表示なし、Built-in シェーダーなし(監査)。 - エフェクトを構築します。 実装例:
VfxFireballKit.Build(飛翔体、マズルフラッシュ、焦げ跡と高温コアを伴う着弾、爆発)とVfxMeshFx.Build(メッシュ衝撃波、パーティクル衝撃波、Custom Data を使った斬撃)。Custom Data:Layer.custom1X/custom1Y/custom2X/custom2Y(カーブまたはランダム範囲)でモジュールとVfxUber.Streamsを設定します。スポーンコードではVfxSeed.Reseed(go)を呼び出します。固定シードはキャプチャ用です。ゲート:VfxAudit.AuditPrefabsのエラーが 0 件、警告には説明が付いています。 - ステップ実行して見た目を確認します。
VfxSequence.CaptureEffect(任意のプレハブに対応。異なるシードを使ったコピー、ループにはstop_t、シェーダー時間はシミュレーション時間に固定)またはCaptureFireballを使用します。ut_review.review_imagesを実行し、コンタクトシートを開きます。ゲート:空白またはマゼンタのフレームがありません。A と B がreferences/critique.mdの基準を満たしています。 - 測定します。
VfxBudget.Overdraw(ピクセルあたりのレイヤー数、FSE、ヒートマップ)、Counts、VisualRadius(メッシュを考慮)、ScreenTexelを使用します。エフェクト一式を対象にut_vfx.effect_verdictまたはsequence_verdict、texel_verdict、importance_ladderを実行します。ゲームプレイ時の間隔でVfxStress.StressOverdrawに対してcrowd_readabilityを、均等間隔のループフレームに対してmotion_gapsを実行します。コピー数 0 のシーンと比較して、AgentKit.AgentProfile.PlayModeTimingsでストレスプロファイルを確認します。ゲート:判定を通過するか、警告に書面の理由が添えられていること。フレーム時間の差分が VFX の割り当て内に収まっていること。 - VFX Graph の実行時チェック(
VfxGraphJobs.PlayTest):オフスクリーンカメラターゲット、プロパティとイベント、遅延フレーム後のカウント、バッチ処理された N 個のインスタンス、背を向けたときのカリングを確認します。ut_vfx.graph_hygiene(vfx_yaml_facts(...), peak_alive)も実行します。ゲート:カウントが公開されたレートに比例し、unbatchedInstanceCount == 0であり、両方向へのカリングが機能し、容量が生存数に近いこと。 - 1 つ修正し、手順 5〜7 を再実行して比較します(
ut_review.compare、ヒートマップを並べて比較)。エビデンスを添えて納品します(scenario-unity-expert のレポート形式)。
数値
| 値 | 対象 | 出典 |
|---|---|---|
| 約90% | メッシュ上を移動するテクスチャであるエフェクト(モバイル) | Nordeus |
| 100 | エミッターあたりの最大パーティクル数、モバイル | Nordeus |
| 8~10 / 5~6 / 2~3 | 高レベル / 低レベル / マルチターゲットのSPELLあたりのドローコール数(デバイスの性能レベルではなく、ゲームプレイのレベル別) | Nordeus |
| 通常256、最大512;LUTは非圧縮 | VFXテクスチャのインポート、モバイル | Nordeus |
| 0.1~0.2秒;0.15~0.2秒 | マズルフラッシュの寿命;高速な飛翔体の軌跡の時間 | Gabriel Aguiar |
| 約0.3秒 | 斬撃の持続時間(=振り) | Hovl Studio |
| 焦げ跡1.75~2、ホットコア0.75~1.3 | 着弾面に重ねる2つの跡 | Gabriel Aguiar |
| 50 units/s | VFX Graph Spawn Over Distanceのしきい値 | 17.3 source |
| 0.5秒;0.5~4 | ゲームプレイ上の停止後の尾;パーティクルあたりのテクセル数 / 画面上のピクセル数(詳細なテクスチャ) | [added] |
| 1対5~7レイヤー、0.037対0.35 FSE | ピーク時のリングメッシュと36個のパフによる衝撃波、960 x 540 | observed |
| 0.51 FSE、p95 11、98パーティクル | ピーク時のファイアボールキットの動作(モバイルの性能レベル) | observed |
| 1.05 FSE、540パーティクル;CPU +0.22 ms | ピーク時の爆発20個を同時に再生した場合と再生しない場合の比較(エディター、参考値) | observed |
| 0.89対1.51 ms | メッシュパーティクル5,000個:URP Particles/Unlitと6.3 Shader Graph particle template | observed |
品質ゲート
- 測定可能性:
counts.error == 0を監査します。エフェクトまたはシーケンスの判定が合格、または警告の理由が説明されていること (塗りつぶし、パーティクル数、視覚上/ゲームプレイ上の半径0.85~1.2、ウィンドウ終了後のパーティクル数0、尾は0.5秒未満)。レベル別テストに合格すること。ゲームプレイ上の間隔で群衆テストに合格すること。テクセル判定、負荷テストの差分、VFX Graphの契約、カウント、バッチ処理、カリング、衛生状態を確認します。 - 視覚: コンタクトシートを開いていること。飛翔中は先端が最も明るいこと。ジオメトリに遮られて切れている部分がないこと。レイヤーがフェードすること。ヒートマップのホットスポットが目に見える要素と一致すること。連続するインスタンスに違いがあること。
よくある間違い
| 間違い | どのように見えるか | 修正方法 |
|---|---|---|
| メッシュで済むところにパーティクルクラウドを使用する(モバイル) | リングに5~7層が重なっている(確認済み) | リングまたは弧のメッシュ+スクロールするユーバーマテリアルを1層使用する |
| 対応するストリームなしでカスタムデータを使用する | シェーダーがゼロを読み取る:侵食もホットスタートも発生しない(確認済み) | VfxUber.Streamsを使用する;vfx.stream_mismatchを監査する |
| チャンネルパックされたテクスチャをsRGBとしてインポートする | 暗く、侵食されたエフェクト | sRGBをオフにする;vfx.data_texture_srgbを監査する |
| メッシュパーティクルのメッシュで浮動小数点頂点カラーを使用する | 平坦な濃い青、アルファ0.25;MeshRendererなら問題なし(確認済み) | Mesh.SetColors(List<Color32>)を使用する;vfx.mesh_color_formatを監査する |
| サイズや侵食のカーブを線形にする | 機械的な動き;v0.1キットでは6つ(確認済み) | EaseOut/EaseIn/Decelerateを使用する;vfx.linear_curveを監査する |
| バリアントシートをアニメーションとして再生する | すべてのパーティクルが同時に形状を切り替える | ランダムな固定フレームにする:Frame over Timeを2つの定数間でランダム化する |
| 囲まれた透明エフェクトの後にディストーションを描画する | その下のグローが消える(31%残存、確認済み) | ディストーションを先に描画する:描画順序を下げるか、Sorting Fudgeを大きくする |
| キットのシードを固定したまま出荷する | ショットが毎回同じになる | スポーン時にVfxSeed.Reseedを使用する |
| 発射レートが高いとき、ショットごとにInstantiateとDestroyを行う | 割り当てのスパイク | プールを使用する:Clear+Playで再生する(VfxStressSpawner)、ロード時に事前ウォームアップする |
| 近距離の爆発で画面が埋まる | 画面全体を埋めるスパイク | Renderer Max Particle Size(キット:モバイルでは0.35)[追加] |
| ビロウやフラッシュをヒットポイントの中心に配置する | 表面への切り替わりが直線的で不自然になる | 法線に沿ってオフセットする(モバイル)、またはソフトパーティクルを使用する(PC) |
| 重なったアルファレイヤーに同じ描画順序を設定する | チラつき | 異なる描画順序を設定し、グローを最前面にする |
| URPにレガシーのパーティクルマテリアルを残す | そのまま描画されるため誰も気づかない;URPの機能は使えない | VfxMaterials.MigrateLegacyJobを使用し、キャプチャを比較する |
| 送信フレームでVFX Graphの数をアサートする | -1または古い値 | 遅延フレームと60フレーム以上待つ |
| FPS上限なしのバッチPlayモードでプロファイリングする | 300フレームでエフェクト時間は0.3秒 | Time.captureDeltaTime = 1f / 60fを設定し、600フレーム実行する |
VFX Graphの構成、イベント、トレイル、キャプチャ時の落とし穴に関する追加の行は、references/critique.mdのセクションFを参照してください。
引き継ぎ
- 受け取るもの:scenario-unity-gameplay からはヒットポイントと法線、ダメージ半径、弾速、発射レートを受け取ります。scenario-unity-shaders からはディゾルブ、トレイル、インスタンス化された Shader Graph パーティクル、
AgentKit/VFX/Uberのバリアントレビューを受け取ります。scenario-textures または scenario(Scenario MCP)からはフリップブックとマスク、加算合成用の黒地にグレースケールを受け取ります。scenario-unity-rendering-lighting からはティアごとの Bloom、Depth と Opaque Texture(ソフトパーティクル、歪み用)、Decal 機能を受け取ります。 - 引き渡すもの:scenario-unity-gameplay には
VfxTierを含むプレハブ、FireballProjectile形式の接続処理、エフェクトの契約を引き渡します。scenario-unity-performance には負荷テスト用シーン、CSV、ヒートマップを引き渡します。scenario-unity-mobile にはティアごとの予算と削減項目(重要度の低いレイヤーから)を引き渡します。scenario-unity-web には WebGPU ビルドでのみ VFX Graph を使用することを伝えます。 - パケット:プロジェクト、チャンネル、数値で示した概要、ジョブ ID、コンタクトシートとヒートマップ、判定行、Verified、Assumed。
Unity 6.3 に関する注意事項
- VFX Graph 17.3.0 はコアパッケージです。テンプレート 01_Minimal_System から 06_Firework では何も公開されません。非推奨:モードを持つ Trigger Event ブロック、Set Position Shape、Collision Shape、Set Position From Source、Output Particle URP Lit Decal。出力ソートは YAML で Auto、Off、On(0、1、2)です。
EnableVertexStreamsはSetActiveVertexStreamsに置き換えられました。URP パーティクルシェーダーには ShadowCaster パスがなく、モーションベクトルなしでフリップブックをブレンドします(VFX Graph には Flipbook Motion Blend があります)。ヒーロー要素や低速要素にはモーションベクトル付きフリップブックを使用してください(Nordeus)。URP の歪みは不透明テクスチャをサンプリングします。このテクスチャには透明オブジェクトは含まれません。- 6.3 以降:6.5 では動的バッチ処理が非推奨となり、6.6 では廃止されます。6.6 では Shader Graph Preprocessor Directives とパーティクルノードが追加されます。WebGPU は 6.6 で実験的機能を終了します。
参考資料
references/expert-notes.md:タイムスタンプ、意見の相違、判断条件を含む、専門家による原則。references/procedures.md:P0 から P19 までの、コピーして使用できるコードと実行結果。references/critique.md:自己レビュー用の評価基準(ゲームプレイ、技術、予算、VFX Graph、誠実さ)と、すべてのミスをまとめた表。references/gui-paths.md:ウィンドウとメニューを使った同じ作業手順。references/sources.md:すべてのソース、認証情報、URL、最適なタイムスタンプ、改訂履歴。scripts/ut_vfx.py(予算、判定、段階構成、群衆、テクセル、モーションの欠落、グラフの衛生状態、.vfxの情報、pCache);scripts/AgentKit/Vfx/(ジョブ、ユーバーマテリアル、メッシュ、メッシュ優先のキット);scripts/Runtime/(負荷テスト用スポナー、弾丸の接続処理、VfxTier、VfxSeed);scripts/Shaders/(VfxUber.shader、VfxOverdraw.shader);scripts/EditorGraph/(未サポートのグラフ作成、SDF ベイク)。