mcpField
P
particle-systems

particle-systems

github.com/pluginagentmarketplaceクリエイティブ・メディア45177 回インストール42 週間前に更新
リポジトリ

particle-systems について

ゲームやビジュアルエフェクト開発向けのパーティクルシステムのスキルです。エフェクト設計や Unity の実装、性能最適化に加え、GPU パーティクル、プーリング、各エンジンのツールを扱います。

主な機能

  1. 01パーティクルのライフサイクルと放出設計
  2. 02爆発などのエフェクトレシピ
  3. 03Unity のパーティクル制御例
  4. 04GPU パーティクルとコンピュートシェーダー
  5. 05性能予算とエフェクトプーリング
  6. 06Unity・Unreal・Godot のツール概要

活用シーン

  1. 01ゲームの爆発や煙のエフェクト制作
  2. 02Unity でのパーティクルエフェクト設定
  3. 03GPU パーティクルを使ったエフェクト作成
  4. 04粒子数の最適化とエフェクトの再利用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-game-developer --skill particle-systems

インストール後、Claude Code で/particle-systemsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
particles_config.yaml
references/
PARTICLES_GUIDE.md
scripts/
particle_designer.py

詳細

パーティクルシステム

パーティクルシステムのアーキテクチャ

┌─────────────────────────────────────────────────────────────┐
│                    PARTICLE LIFECYCLE                        │
├─────────────────────────────────────────────────────────────┤
│  EMISSION                                                    │
│  ├─ Spawn Rate (particles/second)                           │
│  ├─ Burst (instant spawn count)                             │
│  └─ Shape (point, sphere, cone, mesh)                       │
│                    ↓                                         │
│  SIMULATION                                                  │
│  ├─ Velocity (initial + over lifetime)                      │
│  ├─ Forces (gravity, wind, turbulence)                      │
│  ├─ Collision (world, depth buffer)                         │
│  └─ Noise (procedural movement)                             │
│                    ↓                                         │
│  RENDERING                                                   │
│  ├─ Billboard (camera-facing quads)                         │
│  ├─ Mesh (3D geometry per particle)                         │
│  ├─ Trail (ribbon following path)                           │
│  └─ GPU Instancing (batched draw)                           │
│                    ↓                                         │
│  DEATH                                                       │
│  └─ Lifetime expired → recycle or destroy                   │
└─────────────────────────────────────────────────────────────┘

よく使われるエフェクトのレシピ

EXPLOSION EFFECT:
┌─────────────────────────────────────────────────────────────┐
│  LAYERS:                                                     │
│  1. Flash (instant, bright, 0.1s)                           │
│  2. Core fireball (expanding sphere, 0.3s)                  │
│  3. Debris (physics-enabled chunks, 1-2s)                   │
│  4. Smoke (slow rising, fade out, 2-3s)                     │
│  5. Sparks (fast, gravity-affected, 0.5-1s)                 │
│  6. Shockwave (expanding ring, 0.2s)                        │
│                                                              │
│  SETTINGS:                                                   │
│  • Emission: Burst only (no rate)                           │
│  • Start speed: 5-20 (varies by layer)                      │
│  • Gravity: -9.8 for debris, 0 for smoke                    │
│  • Color: Orange→Red→Black over lifetime                    │
│  • Size: Start large, shrink (fireball) or grow (smoke)     │
└─────────────────────────────────────────────────────────────┘

FIRE EFFECT:
┌─────────────────────────────────────────────────────────────┐
│  LAYERS:                                                     │
│  1. Core flame (upward, orange-yellow, looping)             │
│  2. Ember particles (small, floating up)                    │
│  3. Smoke (dark, rises above flame)                         │
│  4. Light source (flickering point light)                   │
│                                                              │
│  SETTINGS:                                                   │
│  • Emission: Continuous (50-100/sec)                        │
│  • Velocity: Upward (2-5 units/sec)                         │
│  • Noise: Turbulence for natural movement                   │
│  • Color: White→Yellow→Orange→Red over lifetime             │
│  • Size: Start small, grow, then shrink                     │
│  • Blend: Additive for glow effect                          │
└─────────────────────────────────────────────────────────────┘

MAGIC SPELL EFFECT:
┌─────────────────────────────────────────────────────────────┐
│  LAYERS:                                                     │
│  1. Core glow (pulsing, bright center)                      │
│  2. Orbiting particles (circle around core)                 │
│  3. Trail particles (follow movement path)                  │
│  4. Impact burst (on hit/destination)                       │
│  5. Residual sparkles (lingering after effect)              │
│                                                              │
│  SETTINGS:                                                   │
│  • Emission: Rate + burst on cast/impact                    │
│  • Velocity: Custom curves for orbiting                     │
│  • Trails: Enable for mystical streaks                      │
│  • Color: Themed to element (blue=ice, red=fire)            │
│  • Blend: Additive for ethereal glow                        │
└─────────────────────────────────────────────────────────────┘

Unity パーティクルシステムのセットアップ

// ✅ Production-Ready: Particle Effect Controller
public class ParticleEffectController : MonoBehaviour
{
    [Header("Effect Settings")]
    [SerializeField] private ParticleSystem mainEffect;
    [SerializeField] private ParticleSystem[] subEffects;
    [SerializeField] private AudioSource audioSource;
    [SerializeField] private Light effectLight;

    [Header("Pooling")]
    [SerializeField] private bool usePooling = true;
    [SerializeField] private float autoReturnDelay = 3f;

    private ParticleSystem.MainModule _mainModule;
    private float _originalLightIntensity;

    public event Action OnEffectComplete;

    private void Awake()
    {
        _mainModule = mainEffect.main;
        if (effectLight != null)
            _originalLightIntensity = effectLight.intensity;
    }

    public void Play(Vector3 position, Quaternion rotation)
    {
        transform.SetPositionAndRotation(position, rotation);

        // Play all particle systems
        mainEffect.Play();
        foreach (var effect in subEffects)
        {
            effect.Play();
        }

        // Play audio
        if (audioSource != null)
            audioSource.Play();

        // Animate light
        if (effectLight != null)
            StartCoroutine(AnimateLight());

        // Auto-return to pool
        if (usePooling)
            StartCoroutine(ReturnToPoolAfterDelay());
    }

    public void Stop()
    {
        mainEffect.Stop(true, ParticleSystemStopBehavior.StopEmitting);
        foreach (var effect in subEffects)
        {
            effect.Stop(true, ParticleSystemStopBehavior.StopEmitting);
        }
    }

    private IEnumerator AnimateLight()
    {
        effectLight.intensity = _originalLightIntensity;
        effectLight.enabled = true;

        float duration = _mainModule.duration;
        float elapsed = 0f;

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float t = elapsed / duration;
            effectLight.intensity = Mathf.Lerp(_originalLightIntensity, 0f, t);
            yield return null;
        }

        effectLight.enabled = false;
    }

    private IEnumerator ReturnToPoolAfterDelay()
    {
        yield return new WaitForSeconds(autoReturnDelay);

        OnEffectComplete?.Invoke();

        // Reset for reuse
        Stop();
        if (effectLight != null)
        {
            effectLight.enabled = false;
            effectLight.intensity = _originalLightIntensity;
        }
    }

    public void SetColor(Color color)
    {
        var startColor = _mainModule.startColor;
        startColor.color = color;
        _mainModule.startColor = startColor;

        if (effectLight != null)
            effectLight.color = color;
    }

    public void SetScale(float scale)
    {
        transform.localScale = Vector3.one * scale;
    }
}

GPU パーティクル(コンピュートシェーダー)

// ✅ Production-Ready: GPU Particle Compute Shader
#pragma kernel UpdateParticles

struct Particle
{
    float3 position;
    float3 velocity;
    float4 color;
    float size;
    float lifetime;
    float maxLifetime;
};

RWStructuredBuffer<Particle> particles;
float deltaTime;
float3 gravity;
float3 windDirection;
float windStrength;
float turbulenceStrength;
float time;

float noise3D(float3 p)
{
    // Simple 3D noise for turbulence
    return frac(sin(dot(p, float3(12.9898, 78.233, 45.164))) * 43758.5453);
}

[numthreads(256, 1, 1)]
void UpdateParticles(uint3 id : SV_DispatchThreadID)
{
    Particle p = particles[id.x];

    if (p.lifetime <= 0)
        return;

    // Apply forces
    float3 acceleration = gravity;

    // Wind
    acceleration += windDirection * windStrength;

    // Turbulence
    float3 turbulence = float3(
        noise3D(p.position + time) - 0.5,
        noise3D(p.position + time + 100) - 0.5,
        noise3D(p.position + time + 200) - 0.5
    ) * turbulenceStrength;
    acceleration += turbulence;

    // Update velocity and position
    p.velocity += acceleration * deltaTime;
    p.position += p.velocity * deltaTime;

    // Update lifetime
    p.lifetime -= deltaTime;

    // Fade out
    float lifetimeRatio = p.lifetime / p.maxLifetime;
    p.color.a = lifetimeRatio;
    p.size *= (0.5 + 0.5 * lifetimeRatio);

    particles[id.x] = p;
}

パフォーマンスの最適化

PARTICLE BUDGET GUIDELINES:
┌─────────────────────────────────────────────────────────────┐
│  PLATFORM      │ MAX PARTICLES │ MAX DRAW CALLS │ NOTES    │
├────────────────┼───────────────┼────────────────┼──────────┤
│  Mobile Low    │ 500           │ 5              │ Simple   │
│  Mobile High   │ 2,000         │ 10             │ Moderate │
│  Console       │ 50,000        │ 50             │ Complex  │
│  PC Low        │ 10,000        │ 20             │ Moderate │
│  PC High       │ 1,000,000+    │ 100+           │ GPU sim  │
│  VR            │ 5,000         │ 15             │ 90 FPS!  │
└────────────────┴───────────────┴────────────────┴──────────┘

OPTIMIZATION TECHNIQUES:
┌─────────────────────────────────────────────────────────────┐
│  REDUCE COUNT:                                               │
│  • LOD system (fewer particles at distance)                 │
│  • Cull off-screen emitters                                 │
│  • Limit max particles per system                           │
│                                                              │
│  REDUCE OVERDRAW:                                            │
│  • Use smaller particle sizes                               │
│  • Reduce transparency layers                               │
│  • Use cutout instead of transparent                        │
│                                                              │
│  BATCH DRAWS:                                                │
│  • Share materials between systems                          │
│  • Use texture atlases                                      │
│  • Enable GPU instancing                                    │
│                                                              │
│  GPU SIMULATION:                                             │
│  • Use compute shaders for >10K particles                   │
│  • Move physics to GPU                                      │
│  • VFX Graph (Unity) / Niagara (Unreal)                    │
└─────────────────────────────────────────────────────────────┘

エフェクトのプーリングシステム

// ✅ Production-Ready: VFX Pool Manager
public class VFXPoolManager : MonoBehaviour
{
    public static VFXPoolManager Instance { get; private set; }

    [System.Serializable]
    public class EffectPool
    {
        public string effectName;
        public ParticleEffectController prefab;
        public int initialSize = 5;
        public int maxSize = 20;
    }

    [SerializeField] private EffectPool[] effectPools;

    private Dictionary<string, Queue<ParticleEffectController>> _pools;
    private Dictionary<string, EffectPool> _poolConfigs;

    private void Awake()
    {
        Instance = this;
        InitializePools();
    }

    private void InitializePools()
    {
        _pools = new Dictionary<string, Queue<ParticleEffectController>>();
        _poolConfigs = new Dictionary<string, EffectPool>();

        foreach (var pool in effectPools)
        {
            _pools[pool.effectName] = new Queue<ParticleEffectController>();
            _poolConfigs[pool.effectName] = pool;

            // Pre-warm pool
            for (int i = 0; i < pool.initialSize; i++)
            {
                var effect = CreateEffect(pool);
                _pools[pool.effectName].Enqueue(effect);
            }
        }
    }

    private ParticleEffectController CreateEffect(EffectPool pool)
    {
        var effect = Instantiate(pool.prefab, transform);
        effect.gameObject.SetActive(false);
        effect.OnEffectComplete += () => ReturnToPool(pool.effectName, effect);
        return effect;
    }

    public ParticleEffectController SpawnEffect(
        string effectName,
        Vector3 position,
        Quaternion rotation)
    {
        if (!_pools.ContainsKey(effectName))
        {
            Debug.LogError($"Effect pool '{effectName}' not found!");
            return null;
        }

        var pool = _pools[effectName];
        ParticleEffectController effect;

        if (pool.Count > 0)
        {
            effect = pool.Dequeue();
        }
        else if (_poolConfigs[effectName].maxSize > pool.Count)
        {
            effect = CreateEffect(_poolConfigs[effectName]);
        }
        else
        {
            Debug.LogWarning($"Pool '{effectName}' exhausted!");
            return null;
        }

        effect.gameObject.SetActive(true);
        effect.Play(position, rotation);
        return effect;
    }

    private void ReturnToPool(string effectName, ParticleEffectController effect)
    {
        effect.gameObject.SetActive(false);
        _pools[effectName].Enqueue(effect);
    }
}

// Usage
public class WeaponController : MonoBehaviour
{
    public void OnHit(Vector3 hitPoint, Vector3 hitNormal)
    {
        VFXPoolManager.Instance.SpawnEffect(
            "ImpactSparks",
            hitPoint,
            Quaternion.LookRotation(hitNormal));
    }
}

🔧 トラブルシューティング

┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Particles popping in/out                           │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS:                                                   │
│ → Add fade-in at birth (size/alpha over lifetime)           │
│ → Increase soft particle distance                           │
│ → Check culling settings                                    │
│ → Extend lifetime with fade-out                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Low frame rate with particles                      │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS:                                                   │
│ → Reduce max particle count                                 │
│ → Use LOD (fewer particles at distance)                     │
│ → Switch to GPU simulation                                  │
│ → Reduce overdraw (smaller/fewer particles)                 │
│ → Use simpler shaders                                       │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Particles clipping through geometry                │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS:                                                   │
│ → Enable collision module                                   │
│ → Use depth fade/soft particles                             │
│ → Adjust near clip plane                                    │
│ → Position emitter away from surfaces                       │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Effect looks different in build                    │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS:                                                   │
│ → Check quality settings (particle raycast budget)          │
│ → Verify shader compatibility                               │
│ → Test on target hardware                                   │
│ → Check for editor-only components                          │
└─────────────────────────────────────────────────────────────┘

エンジン固有のツール

エンジンシステムGPU サポートビジュアルエディター
UnityShurikenVFX Graphはい(VFX Graph)
UnityVFX Graphネイティブはい
UnrealCascade限定的はい
UnrealNiagaraネイティブはい
GodotGPUParticlesはいインスペクター

このスキルを使う場面:ビジュアルエフェクトの作成、ゲームプレイの仕上げ、またはパーティクルのパフォーマンス最適化を行うとき。

コメント