개요
이 문서에서 설명하는 전략의 주요 목표는 개별 레벨과 전체 레벨에서 파티클 시스템이 수행하는 작업의 양을 줄이는 것입니다. 첫 번째 튜토리얼의 지침은 추가 작업 수행되는 영역을 알려주며, 이 튜토리얼은 해당 영역에서 변경을 수행하는 툴과 옵션을 제공합니다. 일반적으로 수행되는 작업량을 줄이려면 불필요한 작업을 피하거나 오버헤드가 적은 솔루션을 선택하면 됩니다.
인스턴스 수: 레벨에서 시스템 수 줄이기
최적화된 시스템이라도 레벨에 시스템이 너무 많으면 퍼포먼스에 영향을 줄 수 있습니다. 기본적으로 같은 시스템의 인스턴스는 나이아가라 월드 매니저(Niagara World Manager)를 사용하여 배치로 틱하지만, 시스템 인스턴스가 많을수록 게임 스레드에서 수행해야 하는 작업도 많아집니다. 일반적으로 더 많은 인스턴스에 걸쳐 같은 수의 파티클을 시뮬레이션하면 수행되는 작업 측면에서 퍼포먼스가 저하되지만, 인스턴스가 많을수록 나이아가라가 더 세부적인 레벨에서 파티클을 컬링할 수 있으므로, 소수의 대규모 인스턴스와 다수의 소규모 인스턴스 간에는 상충 관계가 있습니다.
인스턴스 수 감소 전략
전반적으로 레벨에 스폰하는 시스템의 수를 제어하거나 더 적극적으로는 스폰된 시스템을 컬링하는 방법으로 인스턴스 수를 줄일 수 있습니다. 두 접근 방식 모두 각기 장점이 있으며, 언리얼에서는 두 방식에 대한 툴을 모두 제공하지만, 보통은 프로젝트의 핵심 이펙트 타입(Effect Type)을 구성하고 모든 나이아가라 시스템에 하나씩 할당하는 것부터 시작하는 것이 가장 좋습니다.
엔진 퀄리티 및 이펙트 타입
언리얼 엔진은 나이아가라에서 다양한 엔진 퀄리티 옵션을 제공합니다. 여기에는 이펙트 타입 에셋을 통해 모든 시스템에 적용할 수 있는 재사용 가능한 에셋 및 시스템, 이미터 및 렌더러 레벨에서 나이아가라 에셋을 직접 오버라이드하는 옵션이 포함됩니다. 이러한 옵션을 사용하여 중간(Medium), 높음(High), 에픽(Epic) 등의 엔진 퀄리티 레벨에 따라, 그리고 플랫폼별로 제어할 수 있으므로 프로젝트의 각 타깃 플랫폼에 맞게 각 레벨을 차별화할 수 있습니다. 이러한 세팅 중 다수는 레벨에서 나이아가라 시스템 인스턴스를 컬링하여 그 수를 줄이지만, 스폰되는 파티클 수를 줄이거나, 비용이 많이 소모되는 렌더러를 비활성화하거나, 이미터 및 시스템을 완전히 비활성화하는 데 사용할 수도 있습니다.
서비스형 시스템
인스턴스 수를 줄이는 또 다른 접근 방식은 이미 있는 시스템을 최대한 활용하는 것입니다. 발사체와 임팩트 같은 파티클 이펙트의 경우, 짧은 간격으로 집중된 영역에 연속해서 여러 인스턴스를 스폰하는 것이 일반적입니다. 여기서 풀링을 어느 정도 활용하여 이러한 인스턴스에 대한 컴포넌트 재할당을 방지할 수 있지만, 다시 활성화하는 데는 여전히 오버헤드가 있으며 이전 인스턴스가 완료되어 풀에 반환되는 방식에 의존한다는 문제가 있습니다. 서비스형 시스템 접근 방식은 레벨에 새 시스템을 추가하는 대신 기존 시스템에 새 파티클을 추가하는 방식입니다. 5.4에서는 이러한 워크플로를 간소화하기 위한 새 기능이 도입되었지만, 이전 버전에서는 사용자 파라미터를 대신 사용할 수 있습니다. 이 전략은 다음 튜토리얼에서 더 자세히 살펴볼 것입니다.
이미터 수: 에셋 레벨에서 오버헤드 줄이기
나이아가라 시스템을 빌드할 때, 특히 캐스케이드(Cascade)의 패러다임에서 전환하는 경우, 자연스럽게 시스템에 모든 고유한 비주얼 엘리먼트에 대한 새로운 이미터를 추가하거나 비헤이비어에 약간의 베리에이션을 주게 될 수 있습니다. 하지만, 이 경우 모든 이미터와 관련된 오버헤드가 발생하기 때문에 퍼포먼스에 부정적인 영향을 줄 수 있습니다.
나이아가라는 가상 머신을 사용하여 CPU에서 스크립트를 실행합니다. 이렇게 하는 주요 이유는 두 가지인데, 엔진 퀄리티와 병렬화 때문입니다. GPU의 SIMD 특성을 모방하는 VM을 사용하여 기본적으로 CPU와 GPU 양쪽에서 모든 나이아가라 스크립트가 작동하도록 할 수 있습니다. 처음부터 스크립트로 빌드하면 자신만의 스크립트를 만들고자 하는 사용자의 진입 장벽이 낮아지고 엔진 퀄리티가 향상되며, SIMD용으로 설계하면 나이아가라가 CPU에서 더 쉽게 실행을 병렬화할 수 있습니다.
이 가상 머신의 단점이라고 하면, 모든 이미터와 관련된 오버헤드입니다. GPU 시뮬레이션을 위해 파티클을 타기팅하는 경우에도 게임 스레드와 상호작용할 수 있도록 CPU에서 시스템 및 이미터 스크립트를 여전히 실행합니다. 즉, 오버헤드는 고정된 것이므로 이 오버헤드를 피하는 유일한 방법은 시스템에서 이미터 수를 줄이거나 레벨에서 인스턴스 수를 줄이는 것입니다.
5.4에는 실험단계의 경량 이미터가 있는데, 이는 퍼포먼스를 위해 엔진 퀄리티와 기타 기능을 포기한 이미터입니다. 이러한 경량 이미터는 VM 오버헤드가 없으므로 향후 버전에서 이미터 수를 줄이는 많은 사용 사례에 유용한 대안이 될 것입니다.
완화 전략
다음은 시스템에서 이미터 수를 줄이는 데 사용할 수 있는 몇 가지 전략입니다. 일반적인 아이디어는 시뮬레이션의 행동이 대체로 비슷하고 시각적 엘리먼트(렌더러) 또는 시작 위치와 같은 초기화 데이터만 다른 이미터를 통합하는 것입니다.
스폰 인덱스
스폰 인덱스를 사용하여 공통 행동 또는 시작 데이터가 있는 이미터의 파티클 그룹을 생성할 수 있습니다. 파티클은 스폰 인덱스를 파라미터로 저장하며, 이 파라미터를 사용하여 나이아가라 스크립트에서 다른 데이터를 동적으로 선택할 수 있습니다. 이에 대한 일반적인 예시는 같은 행동을 하는 메시의 다양한 섹션을 샘플링하기 위해 그룹을 생성하는 것입니다. 캐릭터의 손과 발에서 샘플링하는 포트나이트의 비행운을 예로 들 수 있습니다. 캐스케이드에서는 각 비행운에 대해 하나의 이미터를 생성하지만, 나이아가라에서는 캐릭터의 스켈레톤에서 서로 다른 본이나 소켓을 샘플링하도록 각각 설정된 4개의 스폰 그룹과 함께 전체 이펙트에 대해 하나의 이미터를 생성합니다.
여러 렌더러
나이아가라에서는 단일 이미터에 여러 개의 렌더러가 있을 수 있으므로, 이미터가 시뮬레이션하는 각 파티클에서 여러 개의 비주얼 엘리먼트를 생성할 수 있습니다. 일반적인 사용 사례는 라이트 렌더러를 스프라이트 또는 메시 렌더러와 결합하여 파티클이 빛을 방출하면서도 관련 지오메트리를 가질 수 있도록 하는 것입니다. 이 방식은 다양한 메시 또는 스프라이트 표현 중에서 무작위로 선택하여 지오메트리를 변경하는 데에도 사용할 수 있습니다. 또한, 거리에 따라 메시에서 스프라이트로 트랜지션하는 데에도 사용할 수 있습니다. 다양한 파라미터를 서로 다른 렌더러에 바인딩하여 시뮬레이션 내에서 약간의 베리에이션을 허용할 수 있습니다. 예를 들어, 렌더러마다 다른 위치를 바인딩하여 한 위치에 오프셋을 지정하면서도 다른 위치를 따르도록 할 수 있습니다.
메시 렌더러를 사용하면 메시 배열을 지정할 수 있으며, 메시 인덱스 바인딩을 통해 배열에서 렌더링할 메시를 제어할 수 있습니다. 여러 렌더러 대신 이 방식을 사용하면 렌더러를 복제하고 활성화 및 비활성화를 구성할 필요 없이 더 다양한 메시 셰이프를 구현할 수 있습니다. 여기에는 비저빌리티 태그 및 메시 배열에 관련된 비용이 발생합니다. 전반적으로 다른 이미터를 사용하는 것보다 이러한 전략이 유리하지만, 여러 이미터를 사용하는 방식과 이러한 전략 중에서 하나를 결정할 때 프로젝트의 퍼포먼스 특성이 다를 수 있습니다. 프로젝트를 더 최적화해야 한다면, 두 방식을 비교해 보는 것이 좋습니다.
풀링: 메모리 관리 및 할당 줄이기
나이아가라 함수 라이브러리를 사용하면 Spawn System at Location 및 Spawn System Attached를 통해 시스템을 스폰할 때 풀링 메서드를 선택할 수 있습니다. 풀링 시, 같은 에셋에 기반한 나이아가라 컴포넌트는 일반 컴포넌트처럼 할당되거나 가비지 컬렉션되지 않습니다. 대신 더는 사용되지 않는 할당된 컴포넌트가 풀에 보관되고 같은 에셋을 사용하는 새 컴포넌트를 스폰할 때 재사용됩니다. 이렇게 하면 자주 사용되는 컴포넌트에 대한 할당 및 가비지 컬렉션 비용이 절약됩니다.
나이아가라 시스템은 퍼포먼스에 따라 시스템 프로퍼티에서 풀 크기와 프라이밍을 제어합니다. 풀을 프라이밍하면 런타임 할당을 줄일 수 있지만, 에셋이 동적으로 로드되는 경우 히치가 발생할 수 있습니다.
시뮬레이션 비용: 나이아가라 스크립트 최적화하기
GPU 대 CPU
앞의 이미터 수 오버헤드에 대한 섹션에서 언급했듯이, 모든 나이아가라 시뮬레이션에는 CPU 오버헤드가 있습니다. CPU 시뮬레이션을 선택하든 GPU 시뮬레이션을 선택하든, 차이는 파티클 시뮬레이션의 타깃뿐입니다. 즉, 이미터에 대해 선택한 시뮬레이션 타깃(Sim Target)에 따라 파티클 스폰, 파티클 업데이트 및 시뮬레이션 스테이지에서 스크립트만 변경됩니다.
파티클 스크립트에는 병렬화할 수 있는 부분이 많으므로 GPU를 타기팅할 때 가장 효과가 좋으며, 대부분의 경우 GPU 시뮬레이션이 더 퍼포먼스가 뛰어나고 더 많은 수의 파티클을 허용합니다. 파티클 수가 적은 이미터의 경우, CPU 시뮬레이션이 더 적합할 수도 있는데, 왜냐하면 GPU 리소스는 미세하게 나눌 수 없기 때문입니다. 정확한 리소스 사용량은 하드웨어에 따라 다르지만, 파티클 1개의 시뮬레이션이 파티클 64개의 시뮬레이션과 같은 리소스를 차지할 수 있습니다.
또한 일부 프로젝트와 일부 플랫폼에서는 GPU가 병목 현상이 발생하여 CPU 시뮬레이션이 더 적합할 수 있다는 점도 유의해야 합니다. 이러한 현상은 특히 모바일처럼 GPU 메모리가 적은 플랫폼에서 흔히 발생합니다. 그 반대의 경우도 있을 수 있습니다. CPU가 제한적인 프로젝트는 파티클 수가 적은 시뮬레이션이라도 GPU로 전환하는 것이 유리할 수도 있습니다. 프로젝트를 개발할 때 이와 같은 여러 가지 이유로 이러한 퍼포먼스 가정을 검증하는 것이 중요합니다.
기타 모범 사례
프로젝트 프로파일링은 프로젝트에서 병목 현상이 발생하는 위치에 대해 가장 구체적인 데이터를 제공하며, 퍼포먼스 문제를 파악하는 가장 좋은 방법이기는 하지만, 모범 사례도 콘텐츠 제작 중에 흔히 발생하거나 쉽게 놓칠 수 있는 실수를 방지하는 데 큰 도움이 될 수 있습니다. 이러한 모범 사례는 포트나이트와 같은 프로젝트에 참여한 에픽의 이펙트 아티스트들이 오랫동안 수집한 것으로, 에픽 팀에서 공유하는 일반적인 조언에 해당합니다. 이러한 조언에는 예외가 있으며, 기능과 비주얼을 위해 퍼포먼스를 희생할 영역에 관해서는 프로젝트별로 최종 결정을 내려야 합니다.
고정 바운드 대 다이내믹 바운드
일반적으로 고정 바운드는 더 적은 작업이 필요하기 때문에 다이내믹 바운드보다 퍼포먼스가 좋습니다. 하지만 예외도 있는데, 예를 들면 대규모 레벨을 가로지르는 탄환 트레이스처럼, 상대적으로는 작지만 먼 거리를 이동하는 이펙트가 이에 해당합니다. 이러한 경우의 고정 바운드는 실제 비주얼보다 훨씬 크지만, 대부분의 기간에 이펙트가 보이지 않는데, 그래도 바운드 때문에 여전히 연관성이 있을 수 있습니다.
바운드 타입을 변경하는 것 외에도 다음과 같이 다이내믹 트랜스폼 업데이트 빈도(Dynamic Transform Update Frequency)를 줄이기 위한 CVar도 있습니다.
- fx.Niagara.EmitterBounds.DynamicSnapValue
- fx.Niagara.EmitterBounds.DynamicExpandMultiplier
- fx.Niagara.EmitterBounds.FixedExpandMultiplier
웜업
파티클 시스템에 대해서는 웜업을 피하는 것이 가장 좋은데, 그 이유는 웜업의 각 프레임은 순차적으로 평가되어야 하며 매우 쉽게 히치가 발생할 수 있기 때문입니다.
메시 에셋 위생
나이아가라에서 사용하는 스태틱 메시 에셋을 단순화하면 지오메트리를 변경하지 않고도 이러한 메시를 생성 및 렌더링할 때 퍼포먼스가 향상됩니다. 예시:
- 스태틱 메시 에셋에서 콜리전을 제거합니다.
- 섀도가 필요 없는 경우 나이아가라에서 사용하는 LOD에서 '그림자 드리우기(Cast Shadow)'를 끕니다. 예를 들어, 투명 머티리얼을 사용하는 경우입니다.
- LOD의 디스턴스 필드 해상도 스케일(Distance Field Resolution Scale)을 0.0으로 설정하여 디스턴스 필드를 끕니다.
- 메시에 추가 UV 채널이 없도록 합니다.
대규모 파티클 버스트
대량의 파티클을 생성해야 하는 경우, 한 프레임에서 모두 스폰하면 히치가 발생할 수 있습니다. 여러 프레임에 걸쳐 스폰을 분산하면 작업이 분산되어 이러한 히치를 방지할 수 있습니다.
현재 프레임 데이터
최신 게임 데이터에 의존하지 않는 파티클의 경우, '현재 프레임 데이터 필요(Require Current Frame Data)'를 비활성화하면 나이아가라가 가능한 한 프레임 초반에 틱을 시작하여 더 긴 기간에 걸쳐 작업을 분산할 수 있습니다. 움직이지 않거나 움직이는 무언가를 샘플링하는 파티클 시스템의 경우, 보통 이 플래그를 비활성화할 수 있지만, 일부 움직이는 파티클도 마지막 프레임의 데이터를 샘플링하여 여전히 괜찮은 비주얼을 보여줄 수 있습니다. 이 플래그를 비활성화하고 눈에 띄는 변화가 있는지 실험해 보는 것도 유용할 수 있습니다.
복잡한 작업을 스택 위로 이동
각 파티클이나 이미터에 대해 동일한 복잡한 작업은 종종 스택 위로 이동하여 작업이 자주 반복되지 않게 할 수 있습니다. 또한, 이미터 및 시스템 스크립트에서 읽기를 통해 데이터 인터페이스(Data Interfaces) 및 나이아가라 파라미터 컬렉션(Niagara Parameter Collections)과의 상호작용을 더 효율적으로 수행할 수 있습니다. 모듈의 전체 작업 범위가 파티클마다 다르더라도, 대개 작업의 샘플링 부분을 분리할 수 있으므로 퍼포먼스가 향상될 수 있습니다.
데이터 인터페이스
복잡한 작업과 마찬가지로, 이미터와 파티클에 중복된 데이터 인터페이스가 있으면 불필요한 메모리가 사용될 수 있습니다. 스택에서 그러한 데이터 인터페이스를 더 높이 올릴 수 있다면, 퍼포먼스가 더 향상될 것입니다.
또한 사용자 파라미터로서의 데이터 인터페이스는 모든 나이아가라 컴포넌트에 대해, 또는 기존 나이아가라 컴포넌트에서 에셋 설정(Set Asset)이 호출될 때마다 새로운 UObject가 생성되기 때문에 더 많은 메모리를 사용할 수 있습니다.
이벤트 회피
어트리뷰트 리더 데이터 인터페이스를 사용하는 파티클 읽기는 일반적으로 이벤트보다 퍼포먼스가 뛰어나며, 보통 동일한 행동을 구현할 수 있습니다.
정렬
정렬은 기본적으로 비활성화되어 있지만, 활성화하면 정렬 작업이 기본적으로 GPU에서 실행되면서 GPU 오버헤드가 더해지고 인덱스 버퍼에서 추가 메모리가 사용됩니다. 이로 인해 그리기 퍼포먼스가 저하될 수 있습니다.
다음 CVar를 사용하여 CPU 이미터가 CPU에서 정렬 작업을 실행하도록 강제할 수 있습니다.
- Niagara.GPUSorting.CPUToGPUThreshold
- Niagara.GPUCulling.CPUToGPUThreshold