TECHARTNOMAD | TECHARTFLOWIO.COM

TECH.ART.FLOW.IO

[번역] 유니티 Shader Warmup에 대하여

jplee 2024. 9. 12. 19:33

저자: 倉平

안녕하세요!열정개발부 프로그래머 구라히라 입니다!

9월에 접어들면서 날씨가 선선해져서 다행이지만, 대신 날씨가 변덕스러워지는 경우가 많네요.
외출 중 갑작스러운 게릴라성 폭우를 만날 때도 많을 것이다.
이럴 때만 우산을 가지고 오지 않았다면....
흠뻑 젖을 각오로 움직일지, 멈출 때까지 기다릴지 고민이다.

준비하면 고생하지 않고, 번거롭지 않게 작은 우산을 들고 다니는 것을 추천합니다.

이번 시간에는 Unity에서 셰이더 로딩에 대해 알아보겠습니다.

이 글에서는 Unity 버전 2022.3.44f1을 사용하고 있습니다.
또한, URP의 샘플 장면을 사용하였습니다.

 

URP 3D 샘플

유연성과 성능을 겸비한 멋진 그래픽스를 만들고, 커스터마이즈하고, 스케일링하는 방법을 알아보세요.

unity.com

처음 그릴 때 스파이크가 발생?

 

Unity로 제작한 게임의 장면 재생이나 오브젝트 드로잉 시 처음 한 번만 스파이크가 발생할 수 있습니다. 이는 드로잉에 필요한 셰이더를 실시간으로 로드하고 있기 때문입니다.

예) 씬 전환 시 순간적으로 끊김 현상 발생

Profiler를 살펴봅시다.

'Shader.ComplineGPUProgram' 이쪽이 의심스럽네요. 두 번째 이후 트랜지션 시 Profiler도 살펴봅니다.

Shader.ComplineGPUProgram'이 없었습니다. 아무래도 이것이 원인인 것 같네요.

이번 글에서는 이 스파이크를 방지하는 방법을 설명해 보겠습니다.

그리고 그 전에 먼저 도면 처리에 사용되는 ShaderVariant에 대해 알아보도록 하겠습니다.


ShaderVariant란?

ShaderVariant

하나의 셰이더를 기반으로 다양한 환경에서 효율적으로 렌더링을 처리하기 위해 사용되는 것입니다.

셰이더는 키워드 설정에 따라 드로잉 처리를 다르게 할 수 있습니다.

// 키워드 정의
#multi_compile _ TEST_KEY
fixed4 testColor = fixed4(0, 0, 0, 1);
// 키워드가 유효하면 색상 변경
#ifdef TEST_KEY
	testColor = fixed4(1, 1, 1, 1);
#endif

이처럼 하나의 셰이더 자체도 키워드의 종류나 Different Light 모드, 라이트맵, 그림자 등의 설정에 따라 변형을 만들어 낼 수 있습니다.
이를 패스 타입과 키워드 세트로 구분할 수 있도록 한 것이 ShaderVariant입니다.

키워드가 늘어나면 ShaderVariant도 늘어납니다.
셰이더는 하나만 있어도 변형의 수가 증가하기 때문에 셰이더가 늘어나는 한 요인이 됩니다.

드로잉을 할 때 기존에 사용하지 않던 조합이 발생하면 ShaderVariant를 생성합니다.
이것이 스파이크가 발생하는 원인이 됩니다.

ShaderVariant를 미리 로드하면 이를 방지할 수 있습니다.
다음은 로드에 필요한 ShaderVariantCollectio에 대해 설명합니다.


ShaderVariantCollection?

ShaderVariantCollection

Collection이라는 이름에서 알 수 있듯이, 셰이더별 ShaderVariant를 모아놓은 클래스입니다.
ShaderVariant를 로드하는 기능이 있습니다.

이를 생성하여 적절한 위치에 로드하는 것을 목표로 합니다.

ShaderVariantCollection 생성하기

자동 생성

간단한 생성 방법으로 UnityEditor에서 보유하고 있는 ShaderVariant를 저장하는 방법이 있습니다.
UnityEditor에서 게임을 플레이하면서 ShaderVariant를 생성하고 유지하도록 합니다.

유지된 ShaderVariant는 'ProjectSettings/Graphics'에서 확인할 수 있습니다.

아래 'Save to asset...'을 실행하면 보유하고 있는 ShaderVariant를 ShaderVariantCollection으로 일괄 저장할 수 있습니다.

간단하게 만들 수 있지만, 프로젝트에 따라서는 에디터에서만 사용하는 ShaderVariant도 포함될 수 있습니다.
또한, 조합 누락이 발생할 수 있으니 주의하시기 바랍니다.

참고로 옆에 있는 'Clear'를 누르면 보유하고 있는 ShaderVariant가 모두 삭제된 상태가 됩니다.

수동 작성

UnityEditor에서 우클릭 메뉴 'Create/ShaderVariantCollection'을 실행합니다.
그러면 빈 상태의 ShaderVariantCollection이 생성됩니다.


ShaderVariantCollection을 편집해 봅시다.

ShaderVariantCollection은 Inspector에서 편집할 수 있습니다.
'Add shader'를 누르면 선택 창이 뜨는데, 원하는 셰이더를 선택하면 된다.

등록된 셰이더의 오른쪽 옆에 있는 '-'를 누르면 해당 셰이더를 삭제할 수 있습니다.

+ 를 누르면 ShaderVariant를 추가할 수 있습니다.

ShaderVariant 설정 창이 나타납니다.
에서 라이팅 상태, ②에서 유효한 키워드 설정, ③에서 ShaderVariant를 추가할 수 있습니다.

스크립트 상에서 편집하는 방법

public bool Add (ShaderVariantCollection.ShaderVariant variant);

public bool Remove (ShaderVariantCollection.ShaderVariant variant);

위의 Add 함수와 Remove 함수로 추가와 제거를 할 수 있습니다.

프로젝트에서 사용하는 Shader에서 발생하는 ShaderVariant를 계산하여 추가하는 기능을 만들어도 좋을 것 같습니다.

등록된 ShaderVariant의 총 개수가 늘어날수록 로딩 시간도 늘어납니다.
무작정 많이 추가하지 말고, 게임 내에서 실제로 사용하는 것만 포함시키는 것이 좋습니다.

ShaderVariant를 미리 불러오기

ShaderVariantCollection이 준비되었다면, 이를 사용하여 사전 로드 처리를 내장해 봅시다.

ShaderVariantCollection에는 ShaderVariant의 로드 처리인 Warmup 함수가 있습니다.
두 가지 Warmup 함수가 있는데, 각각의 사용법과 주의사항을 소개합니다.

Warmup 함수는 동기화 처리이기 때문에 완료될 때까지 화면이 멈춰있습니다.
실행하는 장소는 타이틀 로고 중 등 정지된 환경에서 실행하는 것을 권장합니다.

또한, DX11과 OpneGL은 완벽하게 지원되지만, DX12, Vulkan, Metal에서는 부분적으로만 지원됩니다.
버텍스 레이아웃이나 렌더 타깃 설정이 사전 준비에 사용하는 데이터와 다를 경우, 그래픽 드라이버를 통한 작업이 필요할 수 있으니 참고하시기 바랍니다.

void Warmup()

ShaderVariantCollection 내의 모든 ShaderVariant를 모두 로드합니다.

Variant 수에 따라 로딩 시간도 증가하기 때문에, 경우에 따라서는 완료될 때까지 몇 초간 화면이 멈출 수 있습니다.
이를 완화하기 위해서는 ShaderVariantCollection을 여러 개로 분할하여 별도의 프레임에서 실행해 보시기 바랍니다.

shaderVariantCollection.Warmup();

bool WarmUpProgressively(int variantCount)

인수 variantCount로 지정한 수만큼 ShaderVariant를 로드합니다.
반환값은 모든 ShaderVariant가 로드된 경우 true, 그렇지 않은 경우 false를 반환합니다.

Warmup()과 달리 ShaderVariantCollection을 분할하지 않고도 조금씩 Warmup을 할 수 있기 때문에 매 프레임마다 실행하면 화면이 멈추는 현상을 줄일 수 있습니다. 

int variantCount = 1;
bool result = shaderVariantCollection.WarmUpProgressively(variantCount);

프리로딩을 내장해 보았습니다.

 

Warmup 구현 전후 비교입니다. 위쪽이 내장 전, 아래쪽이 내장 후입니다.

장면 전환 후의 거친 느낌이 줄어든 것을 확인할 수 있습니다.


Warmup의 진행 상황에 대해

Warmup의 진행 상황을 계산하고 싶은 경우의 예시입니다.
진행 상황을 화면에 표시하고 싶은 경우 등에 활용하시기 바랍니다.

/// <summary>
/// Warmup 진행 상황을 반환
/// </summary>
/// <returns>진행상황(0~1)</returns>
public bool GetWarmupProgressRate()
{
    int variantCount = shaderVariantCollection.variantCount;            // variant의 총 개수
    int warmedUpCount = shaderVariantCollection.warmedUpVariantCount;   // Warmup 완료된 variant 수
    return (float)warmedUpCount / (float)variantCount;
}

마무리

Unity에서 Shader Warmup에 대해 알아보았는데요, 어떠셨나요?

프로젝트마다 적절한 ShaderVariantCollection을 준비하는 것은 정보 조사 등 많은 노력이 필요하지만, 효과가 크니 꼭 구현해 보시기 바랍니다.

 

면책조항 :
본 사이트의 정보 이용으로 인한 손해 등에 대해 
주식회사 로직비트( )는 어떠한 책임도 지지 않습니다.

 


원문

로직비트.

 

【Unity】ShaderのWarmupについて

こんにちは!情熱開発部プログラマの倉平です! 9月に入り涼しくなってきたのはありがたいですが、代わり [...]<p><a class="btn btn-secondary understrap-re

logicalbeat.jp