머티리얼 측정하기
먼저 성능을 어떻게 측정하는지부터 알아봅시다. 셰이더 성능을 측정하는 세 가지 주요 방법이 있습니다.
.
1. Scene View Mode
여기서 'Lit' 옵션을 선택하고 'Optimization View Modes'로 들어가 'Shader Complexity'를 선택할 수 있습니다.
이 뷰 모드는 씬의 모든 객체를 셰이더 명령어의 복잡도에 따라 초록색에서 흰색까지 그라데이션으로 보여줍니다. 씬을 둘러보면서 객체가 초록색이면 셰이더가 비교적 간단하고, 흰색에 가까울수록 더 복잡하다는 것을 알 수 있습니다.
예를 들어, 어떤 객체가 자주색 영역에 있다면 이를 최적화할 수 있습니다.
이 방법은 단지 어느 셰이더가 다른 셰이더보다 더 비용을 많이 차지하게 되는지게 대해 모니터링하는 용도로 활용할 수 있습니다.
2. 명령어 수 확인하기
두 번째 방법은 셰이더가 실행되는 명령어 수를 확인하는 것입니다. 예를 들어, 셰이더가 115개의 명령어를 사용한다고 가정해봅시다.
셰이더 노드 그래프는 HLSL 코드로 컴파일되고, 이는 다시 어셈블리 언어 명령어로 컴파일됩니다. 이 명령어들은 드라이버와 비디오 카드로 전달됩니다.
셰이더가 실행되는 어셈블리 언어 명령어 수를 알면, 셰이더가 얼마나 비싼지 대략적으로 판단할 수 있습니다. 예를 들어, 셰이더가 150개의 어셈블리 언어 명령어를 사용하고 있다면, 명령어 수를 줄이면 성능이 향상될 가능성이 높습니다.
하지만 셰이더 명령어 수를 사용하는 측정 방법도 완벽하지 않습니다. 모든 명령어가 GPU에서 실행되는 데 동일한 시간이 걸리지 않기 때문입니다.
3. 타겟 플랫폼에서 프로젝트를 실행하기
세 번째 방법이자 가장 정확한 방법은 셰이더를 모델에 적용하여, 게임이나 프로젝트의 장면에 모델을 배치하고, 의도한 타겟 플랫폼에서 그 게임이나 프로젝트를 실행하여 측정하는 것입니다.
이 방법은 가장 정확하지만, 가장 많은 단계를 요구합니다. 각 플랫폼마다 하드웨어 능력이 다르기 때문에, 타겟 플랫폼에서 측정하는 것이 가장 정확한 방법입니다. 프로젝트의 최종 단계에서는 이 방법을 사용해야 하지만, 셰이더를 만들고 있는 동안에는 명령어 수를 기준으로 다른 셰이더와 비교하여 상대적으로 얼마나 복잡한지 판단하는 것이 좋은 방법입니다.
쉐이더 최적화하기
이제 주로 명령어 수를 줄이는 방법을 통해 셰이더를 최적화하는 방법에 초점을 맞춰봅시다.
우리는 성능 뷰 모드, 셰이더 명령어 수, 타겟 플랫폼에서의 측정을 다뤘습니다.
성능 뷰 모드는 가장 덜 정확한 방법이고, 명령어 수를 사용하는 것은 두 번째로 좋은 방법이며, 타겟 플랫폼에서 측정하는 것이 가장 좋은 방법입니다.
이제 셰이더를 최적화하고 성능을 개선하는 다양한 방법에 대해 이야기해 봅시다. 오늘은 네 가지 방법을 다룰 것입니다.
1. 첫 번째 방법은 단순히 사용하지 않는 요소를 제거하는 것입니다.
셰이더에 사용하지 않는 텍스처 샘플링이 있거나, 수학적 계산 결과가 0이 나오는 경우, 이를 제거해야 합니다. 복잡한 셰이더를 만들고 많은 기능을 끄고 두세 가지만 사용하는 경우가 종종 있는데, 끈 기능이 실제로 셰이더의 비용에 기여할 수 있습니다. 따라서 사용하지 않는 기능을 제거해야 합니다.
2. 수학을 리팩터링하고 동일한 결과를 도출하기 위한 다른 방법을 사용하는 것입니다.
이 셰이더를 어떻게 만들었는지 보고 싶다면, 간단히 설명해드릴게요. 우리는 바위 재질과 이끼 재질을 가지고 있습니다. 그래서 바위 디퓨즈 텍스처와 이끼 디퓨즈 텍스처가 있고, 바위와 이끼의 노멀 맵도 있습니다. 우리는 월드 공간에서 위를 가리키는 마스크를 기반으로 이 두 가지를 혼합합니다.
이 노드들이 우리의 마스크를 만들어 줍니다. 이 노드는 월드 공간에서 노멀을 가져오고, 언리얼에서 Z 컴포넌트가 위 벡터(Up Vector)입니다. 이 값을 조정하여 더하고, 제곱하고, 클램핑(clamping)합니다. 여기 있는 파워 노드(power node)는 셰이더의 콘트라스트를 높이기 위한 것입니다. 이것을 베이스 컬러(Base Color)에 연결하여 어떻게 보이는지 확인해보겠습니다. 언리트(Unlit) 모드로 전환하여 확인하면, 마스크가 흰색인 부분과 검은색인 부분 사이에 매우 뚜렷한 선이 있음을 알 수 있습니다. 이것이 파워 노드 덕분입니다. 파워를 1로 설정하면 어떻게 되는지 보겠습니다.
보시다시피, 파워를 줄이면 그라데이션이 덜 뚜렷해집니다. 흰색에서 회색, 검은색으로 부드럽게 이동합니다. 하지만 파워를 1로 줄였을 때 마스크의 양이 아래로 많이 내려갔다는 것을 알 수 있습니다. 이것은 콘트라스트를 조정할 뿐만 아니라 마스크가 실제로 적용되는 위치에도 영향을 미칩니다.
파워 노드는 비교적 비싼 셰이더 명령어 중 하나입니다. 그래서 우리는 이 파워를 대체할 수 있는 방법을 찾아야 합니다.
파워를 사용하지 않고, 0에서 1 사이의 범위로 설정된 마스크를 예로 들어보겠습니다.
이 값을 0.5로 빼서 범위를 -0.5에서 0.5로 변경합니다. 그런 다음 곱셈 값을 사용하여 에지를 날카롭게 하고 콘트라스트를 높입니다. 그리고 다시 0.5를 더합니다. 이렇게 하면 값이 0에서 1 사이로 돌아옵니다. 마지막으로 클램핑하여 범위를 유지합니다.
이 과정을 통해 우리는 파워 노드와 비슷한 효과를 얻으면서도 더 저렴하게 할 수 있습니다. 이제 셰이더를 다시 조립해보겠습니다. (Lerp) 노드를 베이스 컬러에 연결하고, 새로운 마스크를 사용해보겠습니다.
셰이더가 컴파일되면 115개의 명령어 대신 111개의 명령어를 사용하는 것을 볼 수 있습니다.
파워 노드와 클램프를 사용하는 것은 115개의 명령어를 사용하지만, 빼기, 곱하기, 더하기, 클램프를 사용하는 것은 111개의 명령어만 사용합니다.
세 개의 노드를 사용하는 것이 하나의 노드를 사용하는 것보다 저렴할 것 같지만, 실제로는 높은 파워로 값을 올리는 것이 꽤 비싼 작업입니다. 그래서 빼기, 곱하기, 더하기로 대체하면 더 저렴하게 할 수 있습니다. 그리고 이 방법을 사용하면 마스크가 모델의 측면을 따라 이동하지 않고 콘트라스트를 조정할 수 있습니다.
이처럼 대체 방법을 찾아 비싼 명령어를 저렴한 명령어로 교체하면 셰이더의 효율성을 높일 수 있습니다.
다른 수학적 방법을 조정하여 셰이더를 더 효율적으로 만드는 예를 하나 더 살펴볼게요.
여기에서 보면 명령어 수가 100개인 셰이더가 있습니다.
기본 제공 플립 북 노드를 사용하면 명령어 수가 98개로 줄어듭니다.
그래서 저는 이 셰이더가 하는 일을 살펴보고, 플립 북 셰이더가 하는 일을 조사한 후, 더 저렴하게 동일한 작업을 수행하는 또 다른 노드 집합을 만들어냈습니다. 기본적으로 동일한 수학적 작업을 수행하지만, 공식을 리팩터링하여 더 효율적으로 만든 것입니다. 이를 텍스처 샘플에 연결하고 명령어 수가 어떻게 되는지 보겠습니다. 이제 명령어 수가 97개로 줄어든 것을 확인할 수 있습니다. 즉, 100개에서 시작해서 기본 제공 방법은 98개의 명령어를 제공했고, 새로 만든 방법은 97개의 명령어를 제공합니다.
비록 한 개의 명령어 차이가 별로 커 보이지 않을 수 있지만, 화면 전체에 걸쳐 적용되거나 셰이더가 많이 사용되는 경우, 몇 개의 명령어를 줄이는 것만으로도 성능을 향상시킬 수 있습니다.
이는 플레이어에게 몇 프레임 더 높은 성능을 제공할 수 있으며, 결국 더 나은 게임 경험을 제공합니다.
3. 세 번째 방법은 파이프라이닝(pipelining)입니다.
이제 셰이더 성능을 향상시키는 또 다른 방법인 파이프라이닝(pipelining)에 대해 살펴보겠습니다. 이전 비디오에서 만든 디스토션 셰이더(distortion shader)를 예로 들어보겠습니다.
이 셰이더는 몇 가지 텍스처를 샘플링하여 UV 좌표를 왜곡한 후 세 번째 텍스처를 참조합니다. 여기에서 이 셰이더 부분과 이 셰이더 부분이 거의 동일한 것을 볼 수 있습니다.
차이점은 시간 값을 곱할 때 사용하는 숫자뿐입니다. 여기서는 0.34와 0.12를 사용하고, 여기서는 0.13과 0.26을 사용합니다. 이러한 경우, 셰이더의 일부를 결합하여 성능을 향상시킬 수 있습니다.
UV 좌표는 U와 V라는 두 개의 값으로 이루어져 있으며, 우리는 네 개의 값을 처리할 수 있는 파이프라인을 가지고 있습니다. 따라서 이 두 부분을 결합할 수 있습니다.
가장 비싼 셰이더 작업은 곱셈과 덧셈입니다. 각각 한 번의 곱셈과 한 번의 덧셈을 수행하고, 이를 두 번 반복하는 대신 한 번의 곱셈과 한 번의 덧셈으로 줄일 수 있습니다.
이제 이 방법을 사용하여 셰이더를 간소화해 보겠습니다. 시간 값을 가져와서 0.34, 0.12, 0.13, 0.26 값을 하나의 벡터 노드로 결합합니다. 이를 곱하면 X와 Y 채널에 두 개의 값이, Z와 W 채널에 두 개의 값이 할당됩니다. 텍스처 좌표(UV)를 가져와서 두 번 연결하면, XY와 ZW 채널에 U와 V 값이 각각 들어갑니다. 이제 한 번의 곱셈과 한 번의 덧셈을 수행한 후, 결과를 분리하여 원래의 UV 좌표로 변환합니다.
이렇게 하면 동일한 결과를 얻으면서도 더 적은 수학 연산을 사용하게 됩니다. 데이터를 결합하고 파이프라이닝을 통해 효율적으로 처리하면 성능을 크게 향상시킬 수 있습니다.
4. 텍스쳐 패킹(Textuer Packing)
마지막 예제로, 몇 주 전에 만든 PBR 기본 셰이더를 다시 살펴보겠습니다. 이 셰이더는 색상, 스펙큘러, 러프니스, 노멀 맵, 앰비언트 오클루전 텍스처를 사용합니다. 셰이더에서 가장 비싼 명령어 중 하나는 텍스처 샘플링입니다.
여러 텍스처 샘플이 같은 UV 좌표를 사용할 때, 이를 하나의 텍스처로 결합하면 많은 비용을 절약할 수 있습니다. 현재 이 셰이더는 102개의 명령어를 사용합니다. 이를 개선하기 위해 스펙큘러, 러프니스, 메탈니스, 앰비언트 오클루전을 하나의 텍스처로 결합했습니다.
포토샵을 사용하여 각 채널에 그레이스케일 이미지를 삽입하면 쉽게 결합할 수 있습니다. 예를 들어, 빨간색 채널에는 앰비언트 오클루전 맵, 녹색 채널에는 스펙큘러 맵, 파란색 채널에는 메탈 맵, 알파 채널에는 러프니스 맵을 넣을 수 있습니다. 이를 통해 텍스처 샘플링 횟수를 줄이고 성능을 최적화할 수 있습니다. (102개의 명령어-> 100개의 명령어)
오늘은 성능을 측정하는 방법과 셰이더를 최적화하는 방법을 다뤄봤습니다. 성능 뷰 모드, 셰이더 명령어 수, 타겟 플랫폼에서의 측정을 다뤘고, 셰이더 최적화 방법으로는 사용하지 않는 요소 제거, 수학적 계산 리팩터링, 파이프라이닝, 텍스처 패킹을 다뤘습니다. 이 기술들이 여러분의 셰이더에 도움이 되길 바랍니다.
'테크니컬 아트 > 언리얼 머티리얼' 카테고리의 다른 글
머티리얼 프로그래밍 기초 개념 (0) | 2024.07.12 |
---|---|
테크니컬 아트 : 기초 개념 1 (0) | 2024.07.01 |
Unreal Material: Math Expressions(수학 관련 표현식) 모음 (0) | 2024.06.24 |
How to Make Default Master Material (0) | 2024.06.24 |