Unity를 사용한 모바일 게임 광원

광원은 게임에서 가장 중요한 측면 중 하나입니다. 분위기를 조성하고 플레이어를 안내하며 위협 또는 목표를 식별하는 등의 용도로 사용됩니다. 광원에 따라 게임의 시각적 요소가 좋아지거나 악화될 수 있습니다. 예를 들어 광원이 좋으면 게임에서 그냥 그런 모델도 더 좋아 보이는 반면, 광원이 좋지 않으면 잘 만든 모델도 좋지 않아 보입니다.

이 가이드에는 모바일 게임에서 광원 성능을 개선하기 위한 정보가 설명되어 있습니다. 광원 사용 방식은 모바일 게임 성능에 영향을 미칩니다. 게임을 최대한 원활하게 실행하려면 광원을 효율적으로 사용하는 것이 중요합니다.

이 도움말의 일부는 Arm Limited에서 제공해 준 저작권 보호를 받는 내용을 기반으로 합니다.

렌더링 파이프라인 옵션

Unity의 레거시 렌더링 파이프라인에는 다음과 같은 렌더링 경로가 포함됩니다.

  • 앞으로 렌더링
  • 지연된 셰이딩

앞으로 렌더링

앞으로 렌더링의 경우 실시간 광원은 비용이 많이 듭니다. 픽셀당 존재하는 광원 수를 줄이면 비용을 절약할 수 있습니다.

지연된 셰이딩

지연된 셰이딩을 사용하려면 GPU 지원이 필요합니다. 호환되는 하드웨어에서 지연된 셰이딩을 통해 높은 수준의 광원 재현성으로 다수의 실시간 광원을 렌더링할 수 있습니다. 하지만 모바일 GPU에서는 대역폭이 낮아 지연된 셰이딩의 성능이 떨어집니다.

모바일 게임을 만들 때는 최대한 많은 기기에서 게임이 원활하게 실행되도록 하는 것이 중요합니다.

범용 렌더링 파이프라인

Unity에서는 URP(범용 렌더링 파이프라인)를 개발했습니다. 모바일 게임에 URP를 사용하는 것이 좋습니다.

광원 모드

장면에서 광원이 움직이거나 사용되는 방식에 따라 다양한 광원 모드를 사용할 수 있습니다. 광원 모드 유형은 각기 다른 성능 특성을 지니고 있습니다. 광원을 구현할 때 다음 사항을 고려하세요.

  • 정적 광원에는 베이킹을 사용합니다. 런타임 중에 광원을 변경하지 않는 객체에 가장 적합합니다. 광원 베이킹은 라이트맵이라고 하는 텍스처 지도에 광원 데이터를 미리 처리하고 저장하는 프로세스입니다.
    • 베이킹된 광원을 런타임에 수정할 수 없습니다. 라이트맵의 빛과 그림자는 정적입니다. Unity에서 모든 광원은 사전 처리되므로 런타임 광원 계산은 성능에 영향을 미치지 않습니다.
    • 베이킹된 광원으로는 동적 그림자를 만들 수 없습니다. 따라서 동적이나 움직이는 객체는 이상하게 보일 수도 있습니다.
  • 움직이는 객체와 상호 작용하려면 정적 광원에 혼합을 사용합니다. 예를 들어 플레이어에게 광원을 비추며 플레이어 움직임에 따라 그림자를 만드는 횃불이 있습니다.
    • 혼합 광원을 사용하면 동적으로 직접 광원과 그림자를 만들 수 있습니다.
    • 정적 객체에 대한 라이트맵 계산에 혼합 광원을 포함할 수 있습니다.
    • 런타임 시 강도를 변경할 수 있으며 직접 광원만 업데이트됩니다.
    • 비용이 많이 듭니다.
  • 땅에서 솟아올라 폭발하는 파이어볼의 광원과 같이 동적이거나 움직이는 광원에 실시간을 사용합니다.
    • 동적 광원 및 그림자 속성은 런타임에 수정할 수 있습니다.
    • 실시간 광원은 라이트맵에 베이킹되지 않습니다.
    • 비용이 매우 많이 듭니다.

자세한 내용은 Unity의 광원 파이프라인을 참고하세요.

가능하면 정적 광원을 사용하고 동적 광원 피하기

동적 또는 실시간 광원은 모든 프레임에서 계산되고 업데이트됩니다. 이는 움직이는 객체, 상호작용, 분위기 조성에 매우 유용합니다.

반면 정적 광원 정보는 라이트맵에 베이킹됩니다. 라이트맵 텍스처를 사용하면 객체에 대한 비용이 많이 드는 꼭짓점당 또는 픽셀당 광원 계산을 피할 수 있습니다. 라이트맵 텍스처의 렌더링 비용은 동적 광원보다 항상 훨씬 저렴합니다. 모바일 게임을 구현할 때는 베이킹된 광원을 가장 먼저 선택하는 것이 좋습니다.

라이트맵 베이킹

빛의 효과를 사전 계산하는 작업을 라이트맵 베이킹이라고 합니다. 빛의 효과는 라이트맵이라고 불리는 별도의 텍스처에 저장됩니다. 라이트맵을 사용하여 객체의 외관을 보강할 수 있습니다. 라이트맵 베이킹은 장면의 반복당 한 번만 수행하면 됩니다. 장면의 도형을 변경하거나 베이킹된 광원의 매개변수를 변경하는 경우 라이트맵을 다시 베이킹해야 합니다. 라이트맵 텍스처의 오버헤드를 제외하면 런타임 시 추가 성능 비용이 발생하지 않습니다. 이는 모바일 플랫폼에서 광원에 접근하기 가장 좋은 초기 방법입니다.

베이킹된 광원은 장면의 동적 특성이나 움직임의 영향을 받지 않습니다. 베이킹된 광원은 모든 정적 요소를 위한 베이킹 글로벌 일루미네이션이 포함합니다. 즉, 라이트맵 계산에 다른 객체에 의해 반사되는 간접 광원과 객체에 직접 부딪히는 베이킹된 광원이 포함됩니다.

그림 1. Armies 기술 데모에 사용된 전체 베이킹된 광원 설정.

광원을 베이킹하려면 다음 세 단계를 따르세요.

1단계: 광원을 혼합 또는 베이킹으로 설정

광원의 Mode(모드)를 'Mixed'(혼합) 또는 'Baked'(베이킹)로 설정합니다. 모바일 게임의 경우 혼합 광원보다 베이킹된 광원을 사용하는 것이 좋습니다. 베이킹은 빛을 렌더링하는 가장 저렴한 방법입니다.

그림 2. Unity의 광원 Mode(모드) 설정.

2단계: 객체를 정적으로 만들기

베이킹된 광원의 영향을 받은 모든 객체를 Static(정적)으로 만듭니다. 정적으로 표시된 객체를 위한 여러 최적화 방법이 있지만 일반적으로 Static(정적) 드롭다운 목록에서 Everything(전체)을 선택하는 것이 가장 좋습니다. Static(정적)으로 표시된 객체를 사용하면 Unity에서 라이트 베이킹에 이 객체를 포함해야 한다는 사실을 알 수 있습니다.

그림 3. 정적 메뉴의 예.

3단계: 광원 베이킹

Window > Rendering > Lighting Settings(창 > 렌더링 > 광원 설정)로 이동하여 Lighting(광원) 메뉴에서 광원을 베이킹할 수 있습니다.

광원을 베이킹할 때 저장되는 데이터는 베이킹을 시작할 때 장면에서 활성 상태였던 객체에 따라 달라집니다. 베이킹된 장면과 동일한 이름으로 폴더가 생성됩니다. 이 폴더에는 광원 데이터의 모든 구성요소가 저장됩니다. 프로젝트가 한 번에 여러 장면을 로드하는 경우 각 장면에 광원을 베이킹해야 합니다. 장면을 조정하는 경우 광원을 다시 베이킹해야 합니다.

그림 4. 베이킹한 라이트맵의 예.

라이트맵 최적화

광원이 베이킹되도록 설정한 후 베이킹된 지도가 최적화되었는지 확인합니다. 라이트맵은 베이킹할 때 설정에 따라 크기가 달라집니다. 모바일에서는 메모리 사용량을 줄여야 하므로 라이트맵 크기를 모니터링해야 합니다.

Armies 데모의 다음 예에는 7개의 1024x1024 픽셀 라이트맵이 있습니다. 지도의 미리보기를 보면 라이트맵에 메시가 배치된 것을 확인할 수 있습니다. 선택한 메시가 강조표시됩니다.

그림 5. 라이트맵의 예입니다. 파란색 섹션은 선택된 메시입니다.

Lightmapping Settings에는 지도의 크기와 함께 각 지도에서 사용하는 메모리와 저장공간을 결정하는 다양한 설정이 있습니다. 다음 섹션에서는 몇 가지 중요한 설정을 중점적으로 설명합니다.

라이트매퍼

Unity는 장면에 광원을 베이킹하는 세 가지 방법을 제공합니다.

  • Enlighten(인라이튼): 2020 장기적 지원(LTS) 출시 전까지만 지원됩니다. 새 프로젝트에는 사용하지 마세요.
  • Progressive CPU(프로그레시브 CPU): 라이트맵을 점진적으로 만들기 때문에 많은 시간을 절약할 수 있습니다. Prioritize View(프로그레시브 뷰)를 선택하면 장면 보기의 영역 우선순위가 지정됩니다. 이렇게 하면 장면의 광원을 설정하는 반복 시간을 단축할 수 있습니다.
  • Progressive GPU(프로그레시브 GPU): Progressive CPU(프로그레시브 CPU)와 동일한 원리로 작동하지만 CPU 대신 GPU에 라이트맵이 생성됩니다. 지원되는 하드웨어에서 이 방법을 사용하면 CPU를 사용할 때와 비교하여 베이킹 시간이 크게 단축됩니다. Progressive GPU(프로그레시브 GPU)에는 추가 요구사항이 있습니다. Progressive GPU Lightmapper(프로그레시브 GPU 라이트매퍼) 페이지에서 요구사항을 자세히 알아보세요.

그림 6. Lightmapper Settings(라이트매퍼 설정)를 사용하면 장면의 베이킹 방법을 변경할 수 있습니다.

텍셀

텍셀 또는 텍스처 픽셀은 텍스처 맵의 개별 픽셀입니다. 텍셀은 객체가 빛을 받는 각 지점에 관한 정보를 라이트맵에 저장합니다. 공간 단위당 사용되는 텍셀이 많을수록 광원의 품질, 베이킹에 소모되는 시간, 디스크 저장 비용, 라이트맵의 VRAM 비용에 영향을 줍니다.

필요한 라이트맵 데이터양을 줄이려면 Lightmapping Settings(라이트매핑 설정)에서 베이킹 단위당 텍셀 수를 조정합니다.

그림 7. 라이트맵에 사용할 수 있는 설정.

Lightmapping Settings(라이트매핑 설정)에서 Lightmap Resolution(라이트맵 해상도) 매개변수는 라이트맵에서 단위당 사용되는 텍셀 수를 제어합니다. 다음은 다른 Lightmap Resolution(라이트맵 해상도) 설정이 사용된 정육면체의 예입니다. 해상도가 높아지면 할 일이 많아짐을 확인할 수 있습니다.

그림 8. 첫 번째 정육면체의 Lightmap Resolution(라이트맵 해상도)은 1입니다. 두 번째 정육면체의 Lightmap Resolution(라이트맵 해상도)은 2입니다. 세 번째 정육면체의 Lightmap Resolution(라이트맵 해상도)은 5입니다.

장면에서 텍셀이 배치되는 방식을 보려면 장면 보기의 Draw Mode(그리기 모드) 드롭다운 목록을 선택하고 Baked Lightmap(베이킹된 라이트맵)을 선택합니다.

베이킹된 객체는 격자무늬 오버레이로 덮여 있습니다. 격자무늬 패턴은 광원을 베이킹할 때 배포된 텍셀 수를 보여줍니다.

다음 예에서는 Armies 데모에서 Lightmap Resolution(라이트맵 해상도)을 15에서 12로 줄이면 필요한 라이트맵 수가 7개에서 4개로 감소합니다.

그림 9. Lightmap Resolution(라이트맵 해상도)이 12인 Armies 데모.

텍셀 사용

전체 장면에서 단위당 텍셀 수를 설정할 수 있지만 많은 텍셀이 필요하지 않은 객체도 있습니다.

Unity에서는 각 객체가 사용하는 텍셀 수를 제어할 수 있습니다. 객체의 Inspector > Mesh Renderer(인스펙터 > 메시 렌더러)에서 Scale In Lightmap(라이트맵 스케일) 매개변수 값은 라이트맵에서 객체가 사용하는 텍셀 수를 제어합니다.

다음 예시에서 왼쪽 정육면체는 베이킹 단위당 광원 정보 텍셀 5개를 가지고 있습니다. 오른쪽 정육면체의 Scale In Lightmap(라이트맵 스케일)은 0.5로 설정되어 있습니다. 이렇게 설정하면 광원 텍셀이 2.5로 조정되므로 왼쪽 정육면체의 라이트맵보다 공간을 적게 차지합니다.

그림 10. 라이트맵 해상도가 서로 다른 2개의 정육면체.

그림 11. Scale In Lightmap(라이트맵 스케일) 설정을 변경하여 객체의 텍셀 수가 줄어듭니다.

다음에 대해서는 텍셀 사용을 피합니다.

  • 플레이어가 볼 수 없는 면이나 객체. 이렇게 하면 화면에 표시되지 않는 세부정보에 라이트맵 메모리가 낭비되지 않게 할 수 있습니다.
  • 광원 변형이 거의 없는 면. 예를 들어 항상 그림자가 드리워져 있는 객체나 단일 광원이 고정된 물체가 있습니다.
  • 작거나 가는 객체. 이러한 객체가 받는 광원의 양은 장면의 최종 렌더링에 많이 추가되지 않습니다.

최대한 많은 가짜 광원

처리 요구사항을 줄이려면 일부 요소를 가짜로 만들면 됩니다. 이렇게 하면 콘텐츠가 광원을 사용하는 것처럼 보이지만 실제로는 더 효율적인 방법이 사용됩니다.

가짜 그림자

실시간 그림자가 비용이 많이 들며 쉐도우 매핑이라는 기술을 통해 생성됩니다. 장면의 도형을 그림자 지도에 렌더링하는 비용은 그림자가 설정된 꼭짓점 수와 비례합니다. 그림자가 있는 도형의 양과 실시간 그림자를 만드는 광원의 수를 제한하는 것이 좋습니다.

동적 광원 없이 동적 객체의 그림자 대용으로 가짜 그림자를 구현할 수 있습니다. 이렇게 하면 렌더링 비용을 낮추고 동적 그림자와 유사한 효과를 얻을 수 있습니다. 다음은 가짜 그림자를 구현하는 몇 가지 방법입니다.

  • 플레인 또는 쿼드와 같은 3D 메시를 캐릭터 아래에 두고 블러 텍스처를 적용합니다.
  • 보다 정교한 blob 그림자를 만들기 위해 자체 맞춤 셰이더를 작성할 수 있습니다.

다음 예는 그림자에 3D 메시를 사용하는 경우의 결과를 보여줍니다.

그림 12. Armies 기술 데모의 그림자 구현.

텍스처에 광원 정보를 직접 칠하기

일부 그림자를 텍스처로 그리는 경우 추가 광원에 필요한 계산이 줄어듭니다. 이렇게 하면 라이트맵 데이터가 줄어들어 장면의 광원을 베이킹할 때 메모리를 절약할 수 있습니다.

광원 프로브

베이킹된 광원이 있는 동적 객체를 사용할 때 이들은 라이트맵의 영향을 받지 않습니다. 이로 인해 장면의 일부가 아닌 것처럼 느껴질 수 있습니다.

이 문제는 광원 프로브로 해결할 수 있습니다. 광원 프로브는 라이트맵과 유사한 이점을 제공합니다. 이 둘은 모두 미리 계산되어 런타임에 사용할 수 있도록 저장된 광원 데이터를 보관합니다. 이렇게 하면 계산 비용을 크게 절감할 수 있습니다.

라이트맵은 표면에 대한 텍셀로 들어오는 빛을 인코딩하는 반면 광원 프로브는 빈 공간을 통과하는 빛을 저장합니다. 이 데이터를 사용하여 움직이는 객체를 확인할 수 있습니다. 광원 프로브는 동적 객체를 장면 속의 라이트 매핑된 객체와 시각적으로 통합하는 데 도움이 됩니다.

광원 프로브는 장면에서 움직이는 객체에 빛을 비추는 데 가장 적합합니다. 프로브는 베이킹된 광원을 활용하며 움직이는 객체가 장면과 동일한 광원을 받게 합니다. 광원 프로브로 빛을 받는 동적 객체는 실시간 광원보다 비용이 적게 듭니다.

자세한 내용은 광원 프로브가 사용된 정적 광원광원 프로브 페이지를 참고하세요.

그림 13. Armies 기술 데모에서 움직이는 군중을 비추기 위해 배치된 라이트 프로브

메시 렌더러 설정

장면에 사용되는 빛 유형과 관계없이 Mesh Renderer 설정이 정확해야 합니다.

사용하지 않는 설정은 모두 사용 중지합니다. Cast Shadows(그림자 캐스트)와 같은 설정은 객체에 광원이 없더라도 장면을 렌더링할 때 비용이 추가됩니다. 다음 Mesh Renderer(메시 렌더러) 설정의 예는 그림 13에 표시된 캐릭터용입니다. 캐릭터는 광원 프로브 데이터를 사용하지만 반사 프로브는 사용하지 않습니다.

광원 프로브의 Blend probes(프로브 블렌딩) 설정이 가장 가까운 광원 프로브의 광원 정보를 캐릭터에 혼합합니다. 캐릭터가 장면에서 이동하면 캐릭터에 영향을 미치는 광원 프로브가 바뀝니다. 렌더링이 blob 메서드를 사용하므로 Cast Shadows(그림자 캐스트)가 사용 중지되어 있습니다. 장면이 베이킹되고 실시간 그림자가 없으므로 Receive Shadows(그림자 받기)도 사용 중지되어 있습니다.

그림 14. 그림 13 렌더링을 위한 Mesh Renderer(메시 렌더러) 설정.

실시간 광원 및 광원 유형

베이킹된 광원, 광원 프로브, 가짜 광원 기술(광원 텍스처 그리기, 셰이더 소재 효과 등)로 광원을 처리하는 것이 좋습니다. 하지만 실시간 광원이 필요한 경우 사용할 빛 유형을 고려해야 합니다.

광원 유형별로 광원을 계산하는 비용이 다릅니다. 다음은 각 광원 유형에 대한 자세한 설명입니다.

  • Directional(방향): 이 광원은 하나의 방향만 향하며 감쇄가 없습니다. 방향 광원은 가장 저렴한 실시간 광원입니다. 대개 장면당 방향 광원이 1개씩만 필요합니다. 모바일용 추천 렌더링 경로인 앞으로 렌더링을 사용하면 장면에 방향 광원이 없는 경우 Unity에서 기본 방향 광원을 포함합니다.
  • Spot(스폿): 스폿 광원은 고깔 모양 광원 밖에 있는 객체에는 빛을 비추지 않음으로 도태시킵니다. 이렇게 하면 스폿 광원이 구형 점 광원보다 계산 비용이 적게 듭니다. 최상의 성능을 얻으려면 고깔 모양 너비를 작게 잡고 원하는 객체에만 비춥니다.
  • Point(점): 모든 방향으로 빛을 비춥니다. 어떤 방향으로든 빛을 비출 수 있으나 비용이 매우 많이 듭니다. 점 광원을 넓은 지역에 사용할 경우 비용이 증가합니다. 또한 그림자 계산은 빛의 비용 중 가장 큰 부분을 차지할 수 있습니다. 모든 방향으로 빛을 보내면 더 많은 그림자와 계산이 필요합니다.