합치지 않고도 빨라지는 법
메시를 합치는 게 비싸다면 안 합치면 됩니다. 문제는 드로우 콜이 아니라 그 앞에 붙는 상태 변경이었으니, 상태를 안 바꾸면 됩니다.
SRP Batcher 가 하는 일이 정확히 그것입니다.
값을 GPU 에 두고 온다
머티리얼마다 색, 타일링, 커스텀 프로퍼티 같은 값이 있습니다. 기존 방식은 오브젝트를 그릴 때마다 이 값들을 CPU 에서 GPU 로 올려 보냈습니다. SRP Batcher 는 이걸 미리 GPU 쪽 상수 버퍼에 올려 두고, 바뀔 때만 갱신 합니다.
그래서 앞의 실측에서 드로우 콜이 524 에서 765 로 늘었는데 SetPass Call 이 517 에서 300 으로 떨어졌던 것입니다. 그리기 명령은 오히려 잘게 나뉘었지만 그 앞에서 하던 일이 사라졌습니다.
배치 조건이 다르다
여기가 다이나믹 배칭과 갈리는 지점이고, 실무에서 가장 헷갈리는 자리입니다.
| 배치가 이어지는 조건 | |
|---|---|
| 다이나믹 배칭 | 같은 머티리얼 (같은 텍스처, 같은 값) |
| SRP Batcher | 같은 셰이더 변형 (값은 달라도 됨) |
SRP Batcher 에서는 머티리얼이 달라도 됩니다. 빨간 적과 파란 적이 같은 셰이더를 쓰고 값만 다르면 배치가 안 끊깁니다. 값은 어차피 버퍼에 다 있고 오프셋만 바꾸면 되니까요.
반대로 값이 완전히 같아도 셰이더가 다르면 끊깁니다.
Sprite-Default 와 Sprite-Lit-Default 를 섞어 쓰면 그 경계마다 끊깁니다.
커스텀 셰이더를 하나 추가할 때마다 배치가 하나씩 더 쪼개집니다.
다이나믹 배칭에서는 “머티리얼 종류를 줄여라” 가 맞고, SRP Batcher 에서는 “셰이더 종류를 줄여라” 가 맞습니다. 조언이 서로를 대체하지 않습니다.
셰이더 쪽 조건
SRP Batcher 가 걸리려면 셰이더가 머티리얼 프로퍼티를 UnityPerMaterial 이라는
상수 버퍼 블록 안에 선언해야 합니다. URP 내장 셰이더는 전부 그렇게 돼 있습니다.
직접 쓴 셰이더나 오래된 에셋에서 가져온 셰이더는 아닐 수 있습니다. Shader Graph 로 만든 것은 자동으로 맞춰집니다. 셰이더 인스펙터를 열면 SRP Batcher 호환 여부가 한 줄로 적혀 있고, 호환이 아니면 그 이유까지 적혀 있습니다. 먼저 여기를 봅니다.
켜는 것만으로는 절반이다
Unity 6 에서 SRP Batcher 는 기본으로 켜져 있습니다. 그래서 “이미 켜져 있는데 왜 안 빨라지지” 가 자주 나옵니다.
켜는 것은 조건을 만들어 준 것뿐입니다. 배치가 실제로 이어지려면 콘텐츠 구조가 받쳐 줘야 합니다. 셰이더가 몇 종류인지, 정렬 레이어를 얼마나 쪼갰는지, 반투명 순서가 교차하는지가 전부 여기에 걸립니다.
그러니 켰다면 그다음 할 일은 Frame Debugger 를 열어 어디서 몇 번 끊겼는지 세는 것입니다.
6.3 의 3D Mesh in 2D 는 예외다
Unity 6.3 부터 3D 메시를 2D 정렬 체계에 넣을 수 있게 됐습니다. 예전에는 스프라이트 뒤에 3D 오브젝트를 자연스럽게 끼우려면 카메라 트릭이 필요했는데, 이제는 Mesh 2D 계열 셰이더에 Sorting Group 컴포넌트를 붙이면 됩니다.
단 이 셰이더 계열은 현재 SRP Batcher 와 호환되지 않습니다. 3D 와 2D 를 자주 번갈아 배치하면 배치가 그때마다 끊깁니다.
쓸 거라면 레이어 구조를 단순하게 유지하는 편이 낫습니다. 배경, 게임플레이, 전경 정도로 층을 나누고 그 안에서 섞지 않는 식입니다. 이건 버전에 따라 바뀔 수 있으니, 쓰는 Unity 6.x 패치 릴리스 노트를 확인해 보세요.