콘텐츠로 이동

Unity VFX Graph 기초와 GPU 파티클 시스템

VFX Graph는 Unity의 GPU 기반 파티클 시스템으로, 기존 Particle System(Shuriken)과 달리 연산이 GPU에서 병렬로 실행됩니다. 수십만 개의 파티클을 실시간으로 처리할 수 있으며, 노드 기반 시각 편집기로 복잡한 이펙트를 만들 수 있습니다.

요구사항: URP 또는 HDRP (Built-in 파이프라인 미지원), Compute Shader 지원 GPU


VFX Graph는 네 가지 컨텍스트로 구성됩니다.

[Spawner Context] ← 파티클 생성 타이밍/수량 제어
[Initialize Context] ← 각 파티클 초기 속성 설정
[Update Context] ← 매 프레임 파티클 속성 갱신
[Output Context] ← 렌더링 방식 결정 (Quad, Mesh, Strip 등)

// VFX Graph 컴포넌트 참조
using UnityEngine.VFX;
public class VFXController : MonoBehaviour
{
[SerializeField] private VisualEffect vfxEffect;
void Start()
{
// 재생 제어
vfxEffect.Play();
vfxEffect.Stop();
vfxEffect.SendEvent("OnHit"); // 이벤트 트리거
// 속성 설정
vfxEffect.SetFloat("SpawnRate", 100f);
vfxEffect.SetVector3("SpawnPosition", transform.position);
vfxEffect.SetTexture("MainTexture", myTexture);
vfxEffect.SetGradient("ColorOverLife", gradient);
vfxEffect.SetBool("Active", true);
}
}

VFX Graph 에디터에서 속성을 Exposed로 설정하면 C#에서 런타임으로 제어할 수 있습니다.

public class FireEffect : MonoBehaviour
{
[SerializeField] private VisualEffect fire;
// 불의 세기 조절 (0~1)
public void SetIntensity(float intensity)
{
fire.SetFloat("SpawnRate", Mathf.Lerp(0f, 500f, intensity));
fire.SetFloat("ParticleSize", Mathf.Lerp(0.1f, 0.5f, intensity));
fire.SetFloat("Lifetime", Mathf.Lerp(0.5f, 2.0f, intensity));
fire.SetVector3("Velocity", Vector3.up * Mathf.Lerp(1f, 5f, intensity));
}
// 폭발 이벤트
public void Explode()
{
fire.SendEvent("Explode");
fire.SetFloat("ExplosionRadius", 5f);
}
}

이벤트와 함께 데이터를 전달합니다.

using UnityEngine.VFX;
public class ProjectileHit : MonoBehaviour
{
[SerializeField] private VisualEffect hitEffect;
private VFXEventAttribute _attr;
void Awake()
{
_attr = hitEffect.CreateVFXEventAttribute();
}
public void OnHit(Vector3 position, Vector3 normal, float force)
{
_attr.SetVector3("HitPosition", position);
_attr.SetVector3("HitNormal", normal);
_attr.SetFloat("Force", force);
hitEffect.SendEvent("OnHit", _attr);
}
}

VFX Graph의 Initialize 컨텍스트에서 Get Attribute 노드로 전달된 데이터를 읽어 각 파티클 초기값으로 사용합니다.


// Spawner Context 노드 구성 예시
[Constant Burst] ← 한 번에 N개 생성
Count: 100
[Constant Rate] ← 초당 N개 지속 생성
Rate: 50
[Periodic Burst] ← 주기적으로 N개 생성
Count: 20, Period: 0.5s

VFX Graph에서 커스텀 HLSL 코드를 삽입합니다.

// VFX Graph의 Custom HLSL 노드에 입력
void NoisyVelocity(
inout float3 velocity,
in float3 position,
in float time,
in float scale,
in float strength)
{
float3 noisePos = position * scale + time * 0.5;
float3 noise = float3(
sin(noisePos.x * 1.7 + noisePos.z * 2.3),
cos(noisePos.y * 1.3 + noisePos.x * 1.9),
sin(noisePos.z * 2.1 + noisePos.y * 1.5)
);
velocity += noise * strength;
}

public class TrailEffect : MonoBehaviour
{
[SerializeField] private VisualEffect trailVFX;
private Vector3 _lastPosition;
void Update()
{
// 이동 속도를 VFX에 전달
Vector3 velocity = (transform.position - _lastPosition) / Time.deltaTime;
_lastPosition = transform.position;
trailVFX.SetVector3("Position", transform.position);
trailVFX.SetVector3("Velocity", velocity);
trailVFX.SetFloat("Speed", velocity.magnitude);
// 빠를 때만 이펙트 활성화
trailVFX.SetBool("Active", velocity.magnitude > 5f);
}
}

// Flipbook 애니메이션 텍스처 설정
public class FlipbookEffect : MonoBehaviour
{
[SerializeField] private VisualEffect vfx;
[SerializeField] private Texture2D flipbookTexture; // 8x8 시트
void Start()
{
vfx.SetTexture("FlipbookTexture", flipbookTexture);
vfx.SetVector2("FlipbookSize", new Vector2(8, 8));
vfx.SetFloat("AnimationSpeed", 24f); // 초당 24프레임
}
}

// 카메라 거리에 따른 LOD
public class VFXLODController : MonoBehaviour
{
[SerializeField] private VisualEffect vfx;
[SerializeField] private Camera mainCamera;
[Header("LOD 거리")]
[SerializeField] private float highQualityDist = 10f;
[SerializeField] private float mediumQualityDist = 30f;
void Update()
{
float dist = Vector3.Distance(
transform.position, mainCamera.transform.position);
if (dist < highQualityDist)
{
vfx.SetFloat("SpawnRate", 500f);
vfx.SetFloat("MaxParticles", 10000f);
}
else if (dist < mediumQualityDist)
{
vfx.SetFloat("SpawnRate", 100f);
vfx.SetFloat("MaxParticles", 2000f);
}
else
{
vfx.SetFloat("SpawnRate", 0f); // 생성 중단
}
}
}

Output 타입용도
Output Particle Quad빌보드 스프라이트 (가장 일반적)
Output Particle Mesh3D 메시 파티클
Output Particle Strip리본/트레일
Output Particle Point포인트 클라우드
Output Particle Lit Quad조명 영향 받는 스프라이트

  • VFX Graph = GPU Compute Shader 기반 → 수십만 파티클 가능
  • Spawner → Initialize → Update → Output 4단계 파이프라인
  • VisualEffect.SetFloat/Vector3/Bool 등으로 C#에서 실시간 제어
  • SendEvent()로 이벤트 트리거, VFXEventAttribute로 데이터 전달
  • HDRP/URP 전용 — Built-in 렌더 파이프라인 미지원