LYSC STUDIO

LIST
Cover

컴퓨트 셰이더(Compute Shader)와 벡터 필드를 활용한 대규모 GPU 파티클 시스템 설계

·3D Art & Tech

수백만 개의 파티클을 병렬로 처리하며 유체 역학적 움직임을 시뮬레이션하는 컴퓨트 셰이더 기반 파티클 시스템의 데이터 지향적 아키텍처를 분석합니다.

1. CPU 파티클의 한계와 GPU 연산의 부상

과거의 파티클 시스템은 CPU에서 각 파티클의 상태를 업데이트하고 동적 버텍스 버퍼에 기록하여 GPU로 전송하는 방식을 사용했습니다. 그러나 이 방식은 CPU-GPU 간의 데이터 대역폭 병목 현상을 유발하여 처리할 수 있는 파티클의 개수를 제한했습니다. 이를 해결하기 위해 파티클의 생성, 갱신, 렌더링 관리를 모두 GPU 내부에서 전담하는 컴퓨트 셰이더 기반의 GPU 드리븐 파티클 시스템이 표준으로 자리 잡았습니다.

2. 컴퓨트 셰이더 기반 파티클 시스템 아키텍처

GPU 파티클 시스템은 기본적으로 데이터를 저장하는 여러 개의 구조화 버퍼(Structured Buffer)로 구성됩니다. 핵심 데이터 구조는 파티클 풀 버퍼이며, 사용 가능한 파티클의 인덱스를 관리하는 Consume Buffer와 현재 활성화되어 렌더링되어야 할 인덱스를 보관하는 Append Buffer가 필요합니다. 컴퓨트 셰이더는 프레임마다 파티클 업데이트 커널을 실행하여 활성 파티클의 위치를 갱신합니다.

3. 간접 드로우(Indirect Drawing)를 통한 완벽한 GPU 제어

CPU는 현재 살아있는 파티클의 정확한 개수를 알 필요가 없어야 합니다. DirectX 11/12와 Vulkan에서 제공하는 DrawInstancedIndirect API를 사용하면 컴퓨트 셰이더가 생성한 파티클 개수를 간접 인자 버퍼에 원자적 연산으로 기록하여 CPU 개입 없이 드로우 콜을 수행할 수 있습니다.

4. 벡터 필드(Vector Field)와 컬 노이즈(Curl Noise)를 이용한 유체 시뮬레이션

파티클이 유체 역학적으로 부드럽게 소용돌이치는 움직임은 3D 벡터 필드 텍스처나 컬 노이즈 함수를 사용하여 구현됩니다. 벡터 필드는 공간 상의 각 그리드 셀마다 방향과 힘 벡터가 저장된 3D 텍스처이며, 이를 샘플링하여 파티클의 가속도에 적용하면 자연스럽게 휩쓸리게 됩니다. 수학적 함수인 컬 노이즈를 실시간으로 평가하면 메모리를 절약하면서도 비압축성 유체의 특성을 지닌 난류장을 생성할 수 있습니다.

5. 반투명 파티클 소팅 (Depth Sorting)의 딜레마

GPU 파티클의 난제는 알파 블렌딩을 위한 파티클 정렬입니다. 수백만 개의 인덱스를 매 프레임 정렬하는 것은 비용이 크므로, 컴퓨트 셰이더를 사용한 바이토닉 정렬(Bitonic Merge Sort)이나 가산 블렌딩(Additive Blending)을 사용하여 성능 타협을 합니다.

6. 결론

컴퓨트 셰이더 기반의 파티클 시스템 구현은 GPGPU 프로그래밍의 정수입니다. 병렬 컴퓨팅의 장점을 극대화하여 수백만 개의 파티클을 제어할 수 있게 됨으로써 아티스트들은 무한한 연출의 자유를 얻게 되었습니다.

Implementation Code
[numthreads(256, 1, 1)]
void CS_UpdateParticles(uint3 DTid : SV_DispatchThreadID)
{
    uint particleIndex = DTid.x;
    Particle p = ParticlePool[particleIndex];
    p.lifeTime -= deltaTime;
    if (p.lifeTime > 0.0) {
        float3 force = VectorField.SampleLevel(LinearSampler, p.position * 0.1, 0).xyz;
        p.velocity += force * deltaTime;
        p.position += p.velocity * deltaTime;
        ParticlePool[particleIndex] = p;
        AliveList.Append(particleIndex);
    } else {
        DeadList.Append(particleIndex);
    }
}
파티클의 흐름을 통제하고 병렬 연산의 미학을 코드로 풀어내는 일은 심장 뛰는 과제입니다.