on
Particle Animation 메모리 최적화 방안 끄적임
Particle Animation 메모리 최적화 방안 끄적임
주의: 생각의 흐름을 정리하기 위한 글이라 앞 뒤 맥락없이 아무 말이나 할 수 있습니다.
이전에 Metal을 이용해서 Particle Animation을 만들었는데, 메모리 사용량 때문에 머리가 복잡했다.
Particle이 10000개만 넘어가도 RAM을 많이 차지하고, 결국 한계가 명확해 보였기 때문에 이 문제를 해결하고 싶었다.
1. Particle 구조를 최대한 슬림하게
가장 먼저 시도한 건 Particle 구조체 자체를 “다이어트”하는 것. position, velocity 등 꼭 필요한 값만 남기고, Double → Float, Int → UInt8로 바꾸는 식이다. 분명 배열 용량은 줄지만, 결국 모든 particle을 한 번은 메모리에 다 담아야 하는 구조라 진짜 근본적인 해결책이 아니라는 느낌.
2. batch 단위로 draw하는 방식
한 번에 수만 개의 파티클을 만들지 않고, batchSize(예: 1000개)씩 생성해서 바로 GPU로 넘기고 메모리에서 해제하는 방식을 생각해봤다.
하지만 Metal에서는 drawPrimitives를 호출하려면 모든 파티클 데이터를 미리 메모리에 준비해서 buffer에 채워둬야 한다는 구조적인 제약이 있다. batch로 나눠 여러 번 drawPrimitives를 호출해도 결국 한 프레임에 전체 파티클을 그리고 싶다면 모든 데이터를 한꺼번에 메모리에 들고 있어야 해서, 결국 메모리상 이득을 볼 수 없었다…
3. GPU에서 particle 생성
생각을 계속하다 보니, “CPU에서 particle 데이터를 안 만들고, 그냥 개수만 넘긴 뒤 GPU에서 vertex_id로 생성/애니메이션까지 처리”
이 방법이 가장 근본적으로 메모리 문제를 없앨 수 있을 것 같다.
- CPU: 파티클 개수만 넘김 (vertexCount)
- Metal 쉐이더: 각 vertex_id마다 position/velocity/애니메이션 전부 계산
vertex_id로 2D 위치, random velocity, 시간에 따른 애니메이션까지 모두 만들 수 있다면 파티클 배열을 메모리에 둘 필요도 없어지는 구조.
아직 실제로 vertex_id만으로 얼마나 다양한 효과를 낼 수 있을지, 코드로 구현해보기 전이지만 지금까지 고민한 방법 중에선 가장 가능성이 커 보인다.
3-1. 아이디어 정리
- vertex_id로 Particle 위치 결정
vertex_id
를 2D로 변환 (x, y)해서 사용하면 될 것 같기도..?- sqrt(area / pixelCount)로 한변의 길이를 구해서 계산하면 변환할 수 있을 것 같다.
- 속도는 특정 범위 안에서 random하게
- uniform으로 시간(time) 전달
time
값을 쉐이더에 uniform으로 전달- position, alpha 등을 시간에 따라 동적으로 계산
- 예시:
position = initialPosition + velocity * time
- CPU 메모리 사용 최소화
- 파티클 개수(vertexCount)만 넘기고, 별도 데이터 배열/버퍼 불필요
- 대량 파티클 생성 시에도 메모리 극소화