Unity Term Book
그래픽 & 이펙트

VFX & Particle System

Unity는 CPU 기반 Particle System과 GPU 기반 VFX Graph 두 입자 시스템을 제공합니다. 불·연기·비·마법 FX에 쓰며 플랫폼·입자 수에 따라 고릅니다. Play·Emit·SendEvent와 풀링으로 성능을 잡는 VFX·파티클 실전 가이드입니다.

상상해 보세요...

Particle System손으로 쏘는 폭죽 — rate·각도·색을 정하면 CPU가 입자마다 갱신합니다. 정밀하지만 수가 많으면 느립니다. VFX Graph산업용 폭죽 기계 — GPU에서 병렬로 돌아 수백만 입자가 가능하지만 강한 GPU와 URP/HDRP가 필요합니다. 입자 수·타깃 플랫폼·행동 복잡도에 따라 고르세요.

개념 자세히

Particle System(일명 Shuriken)은 GameObject의 컴포넌트로 CPU에서 입자를 만들고 갱신합니다. 각 입자는 위치·속도·색·크기·수명을 가집니다. 모듈(Emission, Shape, Velocity, Color over Lifetime, Force, Collision…)로 세밀 제어. 적합: 작은 불, 비, 눈, 히트 FX, 연기 — 수십~수천 입자.

VFX Graph(Visual Effect Graph)는 GPU compute shader에서 전부 돕니다. Shader Graph와 비슷한 노드 그래프로 갱신 로직을 만듭니다 (Initialize, Update, Output). 수백만 입자도 좋은 성능. 필요: URP 또는 HDRP, Compute Shader 지원 GPU(2015+ 대부분), 구형 Android/iOS는 불가.

VFX Graph는 입자를 나눕니다: Spawn(rate/burst), Initialize(초기 속성), Update(프레임별 물리·색·크기), Output(그리는 방식: quad, mesh, ribbon). Context가 데이터 흐름으로 연결됩니다 — 렌더 파이프라인처럼.

성능: Particle System은 라이브 입자 ~1000 이하면 모바일·콘솔에서도 괜찮습니다. maxParticles로 캡하고 재생 후 Stop Action = Disable. VFX Graph는 더 잘 스케일하지만 타깃 플랫폼에서 프로파일하세요.

Particle System vs VFX Graph

기준Particle SystemVFX Graph
처리CPUGPU (Compute Shader)
최적 파티클 수100 – 10,00010,000 – 10,000,000+
PipelineBuilt-in, URP, HDRPURP, HDRP only
Mobile✅ 좋음⚠️ 제한적
InterfaceInspector moduleNode graph editor
Script API완전한 C# APILimited (SetFloat, SetTexture)
사용할 때불, 비, 히트 FX, 연기은하, 유체, 군중, 파괴

실습 단계 (Particle System)

1

Particle System 만들기

GameObject → Effects → Particle System, 또는 기존 GO에 Add Component → Particle System.

2

Main 모듈 설정

Duration, Looping, Start Lifetime, Start Speed, Start Size, Start Color — 기본.

3

방출 Shape 고르기

Shape 모듈: Cone(불), Sphere(폭발), Box(위에서의 비), Circle(링). Radius와 Arc 조절.

4

Color over Lifetime 켜기

그라디언트 추가: 빨강 → 주황 → 노랑 → 투명으로 불을 페이드 아웃.

5

필요할 때 코드로 Play

ps.Play() / ps.Stop() / ps.Emit(count) — 또는 EmitParams로 즉시 burst.

인터랙티브 시뮬레이터

Particle System 파라미터를 조절하고 Burst / 프리셋으로 효과를 보세요.

살아있는 파티클:0Mode: Fire

코드 예제

기본

Particle System Play/Stop과 요청 시 burst emit(예: 히트 이펙트).

using UnityEngine;

public class HitEffect : MonoBehaviour
{
  public ParticleSystem sparks;
  public ParticleSystem smoke;

  // Call on bullet impact — PlayOneShot a prefab at a position
  public static void PlayAt(Vector3 pos, Vector3 normal,
                             GameObject fxPrefab)
  {
      GameObject fx = Instantiate(fxPrefab, pos,
          Quaternion.LookRotation(normal));
      Destroy(fx, 2f); // Clean up after 2 seconds
  }

  // Burst emit: 30 particles immediately, no looping
  public void BurstEmit()
  {
      ParticleSystem.EmitParams ep = new ParticleSystem.EmitParams();
      ep.position = transform.position;
      sparks.Emit(ep, 30);
      smoke.Play();
  }

  // Change particle color at runtime via Main module
  public void SetColor(Color color)
  {
      var main = sparks.main;
      main.startColor = new ParticleSystem.MinMaxGradient(color);
  }
}

코드 예제

고급

C#에서 VFX Graph 구동 — ExposedProperty로 속성과 이벤트.

using UnityEngine;
using UnityEngine.VFX;

public class VFXController : MonoBehaviour
{
  public VisualEffect vfx;

  // Property IDs — must match Exposed Property names in VFX Graph
  static readonly int SpawnRateID = Shader.PropertyToID("SpawnRate");
  static readonly int ColorID     = Shader.PropertyToID("BaseColor");
  static readonly int ExplodeID   = Shader.PropertyToID("OnExplode");

  void Start()
  {
      vfx.SetFloat(SpawnRateID, 50f);
      vfx.SetVector4(ColorID, new Vector4(1f, 0.5f, 0f, 1f));
  }

  public void Explode()
  {
      // SendEvent fires an event in VFX Graph (Burst spawn)
      vfx.SendEvent(ExplodeID);
  }

  public void SetIntensity(float t)
  {
      // Spawn rate 0 → 500 from intensity
      vfx.SetFloat(SpawnRateID, Mathf.Lerp(0f, 500f, t));
  }
}

📌 빠른 정리

  • Particle System: CPU, 모든 플랫폼, <10k 입자
  • VFX Graph: GPU, URP/HDRP만, 수백만 입자
  • Stop Action = Disable로 재사용(오브젝트 풀링)
  • ps.main.startColor는 struct로 재할당해야 함
  • VFX Graph: SendEvent()가 Burst context를 발사

⚠️ 흔한 실수

  • ❌ Destroy 없이 PS prefab을 많이 스폰

    수천 Particle System 누적 → 심한 렉

    ✅ PS를 풀하거나 끝난 뒤 Destroy(fx, lifetime)

  • ❌ ps.main.startColor.color를 직접 수정

    struct 복사 — 변경이 적용되지 않음

    ✅ var main = ps.main; main.startColor = new MinMaxGradient(c);