[유니티 그래픽스 최적화 스타트업] Part 07 | GI (Global Illumination)

jungizz_·2023년 7월 18일
post-thumbnail
  • 실시간이 아닌 라이팅과 그림자를 미리 연산(굽는다, Bake)해두는 라이트맵, 라이트 프로브같은 솔루션을 이용하면 성능뿐 아니라 라이팅의 퀄리티를 높일 수 있음
  • 라이팅의 퀄리티가 높아질 수 있는 이유는 GI를 적용할 수 있기 때문

◾ Glabal Illumination (GI), 전역조명

  • 빛은 표면에 반사되면서 간접적인 라이팅을 만들어내고, 이러한 빛에 영향을 받는 현상
    p.276
  • 라이트맵, 라이트 프로브를 이용하면 GI현상까지 미리 연산 가능
  • GI까지 실시간으로 처리하기에는 많은 연산이 필요하므로 실시간 라이팅은 GI처리 X

◾ Local Illumination, 지역조명

  • 라이팅 소스에서 들어오는 직접적인 라이트
  • 실시간 라이팅이 처리할 수 있는 라이트

p.277

1. 라이트맵

  • GI 및 그림자 등을 포함한 라이팅 정보를 미리 연산하여 텍스처로 저장하는 기능
  • 라이트를 담는 맵(텍스처)
  • 라이트맵 텍스처에는 라이팅 관련 정보만 담기므로 Albedo등 오브젝트의 고유 색이 아닌, 오브젝트에 빛이 튕겨서 바닥에 맺히는 GI값이 저장
  • 빨간 화살표가 가리키는 곳에 큐브의 녹색이 바닥에 묻어난 것
  • 실시간 오브젝트에는 적용이 불가능하므로 캐릭터 대신 배경 오브젝트에 적용하기 좋은 솔루션
  • 라이트맵을 생성하는 과정을 굽는다(Bake)고 표현하며, 완성된 라이트맵 텍스처는 베이크드 라이트맵(Baked Lightmap)이라고 함

1. 라이트맵 구성 요소

  • 구성요소는 Baked 모드로 설정된 라이트와 Lightmap Static 오브젝트 2가지

1. Baked 모드로 설정된 라이트

  • 라이트맵에 반영되는 라이트 모드를 Mixed 또는 Baked로 설정

2. Static 오브젝트

  • 정적인 오브젝트, 즉 Static 플래그가 체크된 오브젝트만 라이트맵을 구울 수 있음
  • 원하는 오브젝트의 Lightmap Static(Contribute GI)을 체크하여 라이트맵을 사용하는 오브젝트로 처리
  • 오브젝트에 라이트맵을 적용을 위해서는 Mesh Renderer의 Ligthmap Static(Contribute GI) 체크되어 있어야 함

✔️ UV채널

  • 라이트 결과를 계산해서 그려 넣은 텍스처이므로 UV채널이 없다면 라이트맵이 깨질 수 있음
  • UV채널이 없다면 오브젝트의 Import Setting에서 자동 생성 되도록 Generate Ligthmap UVs를 체크

2. Realtime GI

  • 실시간 라이트의 GI를 처리하는 기능
  • 라이트맵 관련 설정 Window > Rendering > Lighting Settings에서 Realtime Glabal Illumination

◾ 제약사항

  • 완전하게 실시간 업데이트가 아닌, Enlighten이라는 솔루션으로 사전 연산 과정을 거쳐 데이터를 저장하는데 이때 Static 오브젝트들에 대해서만 적용됨
  • 런타임동안 GI 업데이트는 매우 큰 성능 소모를 요구하기 때문에 라이트의 밝기, 각도가 변하면 즉시 반영되지 못하고 점진적으로 연산되며 업데이트
  • 업데이트 간격은 ProjectSettings > Graphics의 각 티어별로 Realtime Global Illumination CPU항목의 값으로 설정
  • 하지만 업데이트 반영 주기는 한계가 있으므로 빠르게 변경되는 라이트에는 적합하지 않고, 태양처럼 하루의 시간 변화에 따라 서서히 변하는 라이트 등에는 적합할 수 있음
  • 모바일 디바이스에서 실시간 GI 연산을 사용하려면 미리 연산된 데이터의 크기를 줄이기 위해 씬을 작게 유지하고 CPU 사용량을 Low로 두는 등 많은 최적화가 필요
❗책에서는 실시간 GI를 다루지 않으므로 Realtime Glabal Illumination체크 해제 후 진행

3. Progressive Ligthmapper

  • Lightmapping Settings의 Lightmapper에는 ProgressiveEnlighten이 존재
  • Progressive는 기존의 Enlighten라이트매퍼 방식과 다르게 라이트맵이 구워지는 과정을 점진적으로 볼 수 있다는 장점을 가짐
  • Lighting 윈도우 하단의 Auto Generate를 체크하면 라이팅이나 Static 오브젝트가 수정될 경우 라이트맵을 자동 업데이트
❗ 그레서 Auto Generate를 체크하고 라이트를 수정해가며 Progressive Ligthmapper로 수정된 라이트맵을 점진적으로 확인할 수 있다.
  • 베이킹이 시작된 후 초기 연산 과정 -> 거친 라이트맵과 텍셀의 도드라짐
    p.286~
  • 베이킹 진행 중
  • 베이킹 완료
  • Baked Ligthmap 모드를 선택하면 베이킹된 라이트맵을 확인할 수 있음
  • 베이킹이 진행될 때, 남은 시간이 우측 하단에 표시되며, 라이트 작업 시간을 효율적으로 예측 가능

➕ Ambient Occlusion(AO)

  • Ambient Occlusion(AO)는 지오메트리들 사이에 빛이 차폐되어 어두워지는 현상을 의미하며 이것을 활용하여 라이트맵에서 깊이감을 좀 더 살려낼 수 있음
    p.289

4. 라이트맵의 해상도

  • Light 세팅 창의 Lightmap Resolution / Padding / Size 등은 라이트맵 텍스처의 해상도 및 텍스처 개수와 연관된 항목

1. Lightmap Resolution

  • 라이트맵의 해상도보다 텍셀 밀도로 이해
  • 1유닛 당 라이트맵의 할당 텍셀을 결정
    (LIghtmap Resolution=10, 5x5 유닛 크기의 평면에 라이트맵이 적용된다면 50x50텍셀, 즉 2500개의 텍셀이 필요)

2. Ligthmap Size

  • 라이트맵 텍스처의 해상도
  • 필요한 해상도가 Lightmap Size 수치보다 크면 여러 장의 라이트맵으로 나뉨
❗ Lightmap Size가 작고 Lightmap Resolution이 크다면 라이트맵이 여러 장으로 나뉠 확률이 큼
❗ 보통 유니티에서 1유닛 = 1미터 (정할 수 있음)

◾ 여러 장으로 나뉜 라이트맵

  • 라이트맵이 여러 장으로 나뉘면 그만큼 배칭이 깨질 확률이 큼
    (프레임 디버거에서 라이트맵에 의해 배칭이 갈리는 것이 표시 됨)
  • 라이트맵도 텍스처이므로 서로 다른 텍스처를 사용하는 오브젝트들끼리 하나의 드로우콜로 처리가 안됨
  • 라이팅 윈도우의 Global Maps(Baked Lightmaps)탭에서 라이트맵의 결과물을 확인할 수 있음
    (아래 이미지는 라이트맵이 여러 장으로 나뉘지 않고 1개만 만들어진 모습)
  • 라이트맵의 텍스처 개수는 드로우콜의 개수에 영향을 미치므로 신경써야함
  • 만약 여러장으로 나눠진 경우 텍스처 개수를 줄이는 방법은
  1. Lightmap Resolution을 줄이기 -> but, 시각적인 라이트맵의 해상도가 줄어들 수 있음
  2. Lightmap Size를 늘리기 -> but, 너무 크면 대역폭 문제를 일으킬 수 있음

5. Directional Mode

  • 라이트맵 사이즈에 영향을 주는 요인 중 하나
  • 라이트맵이 적용되는 오브젝트에도 노멀맵이 적용되도록 하는 것
    (추가적인 리소스와 성능 필요)

◾ Non-Directional Mode

  • 라이팅과 그림자 등이 기록된 라이트맵만 사용
  • 라이트맵이 적용된 오브젝트의 노멀맵에 반응하지 않으며 스페큘러 하이라이트도 처리 X
  • 리플렉션 프로브는 적용됨
Mode노멀맵 적용디테일
DirectionalO리플렉션 프로브 + Occlusion맵
Non-DirectionalX리플렉션 프로브 + Occlusion맵 + Normal맵 (표면 디테일)

◾Directional 모드 특징

  • 노멀맵은 디퓨즈에만 반응하며 스페큘러 하이라이트는 적용되지 않음
  • 표면에 맺히는 라이트의 방향 등 라이팅 환경에 대한 추가적인 정보를 가진 라이트맵을 추가 생성하므로 Non-Directional모드에 비해 추가적인 텍스처가 필요해 그만큼 메모리를 차지함
  • 빛을 정확히 처리하는 연산이 추가되어 픽셀 쉐이더 비용 추가
    -> 추가적인 메모리와 GPU성능 필요

6. Light 모드 - Mixed

  • Mixed 모드는 Realtime과 Baked 두 모드의 역할을 모두 지닌 라이트
    (사전 연산 + 리얼타임)
  • Mixed 라이트의 그림자 옵션 켜 있으면 라이트맵에도 그림자 반영, 런타임 동안 동적 오브젝트에도 그림자 캐스팅 (런타임 성능에 영향)
  • 런타임동안 Mixed라이트의 트랜스폼이나 색상 등을 변경할 수는 있지만 라이트맵에 수정 내용 반영X -> 사실상 권장X

  • Mixed 라이트의 설정은 Lighting창에서 가능하며 Baked GI가 체크되어 있어야 라이트맵을 사용할 수 있음
  • Mixed 라이트는 아래 설정에 의존하므로 모두 동일한 Lighting Mode가 사용됨 (Baked Indirect / Subtractive / Shadowmask)

❗ 아래 내용은 위의 각 Lighting Mode에 관한 설명

7. Baked Indirect

  • GI만 라이트맵에 기록되고 그림자는 기록X
  • 그림자만 런타임동안 실시간 연산 (그림자가 중요한 경우)
  • 그림자 뿐만 아니라 직접광(Direct lighting)도 리얼타임으로 처리됨 -> 실시간 라이팅이 적용된 바위의 스페큘러 하이라이터
  • 씬뷰의 Baked Lightmap 모드(우측 이미지) -> AO등의 GI만 반영되어있고 Direction Light의 그림자X

8. Subtractive

  • 정통적인 라이트맵으로 GI와 직접 조명, 그림자까지 모두 라이트맵에 베이킹
  • 따라서 Static오브젝트에는 실시간 라이팅X, 오로지 라이트맵 -> 스페큘러 반영X
  • 베이킹된 그림자 위에 캐릭터의 실시간 그림자가 구분되게 그려짐 (자연스럽게 연결되는 Baked Indirect모드와 대조됨)
  • 씬뷰의 Baked Lightmap 모드(우측 이미지) -> 오브젝트의 라이팅, 그림자, AO 모두 처리되어있음
  • 베이킹된 그림자와 실시간 그림자의 자연스러움을 위해 실시간 그림자의 컬러를 조절할 수 있음 (21.3 버전에서는 어딨는지 머르겠다)
  • 런타임동안의 라이팅 오버헤드가 극히 적어 저사양 모바일 디바이스에서 사용하기 적합

9. Shadowmask

  • 라이트맵 베이킹 시 그림자 영역을 별도의 텍스처(Shadowmask)로 따로 저장
  • 런타임동안 그림자 캐스팅 연산X, 대신 Shadowmask로부터 그림자 여부 판단하여 실시간 그림자와 자연스럽게 합성
  • Subtractive모드와 다르게 그림자가 자연스럽게 연결됨
  • 라이트맵이 적용되는 오브젝트에도 스페큘러 하이라이트 적용O
    -> 픽셀쉐이더의 실시간 연산이 필요하므로 GPU성능 추가적 소모
  • Static 오브젝트는 그림자 영역을 Shadowmask로 저장하고, 다이나믹 오브젝트에 대해서만 쉐도우맵 연산을 하므로 그림자 연산에 대한 비용 절약 (Baked Indirect보다 적은 연산)
  • 씬뷰의 Shadowmask 모드(우측 이미지)로 쉐도우마스크 확인 가능
SubtractiveShadowmaskBaked Indirect
베이킹(라이트맵)GI, 그림자, 직접광GI, 그림자GI
실시간X직접광그림자, 직접광
품질 및 연산 비용

➕ 용량 문제

  • 아래 이미지는 Directinal 모드와 Shadowmask 모드로 설정하여 라이트맵을 베이킹한 결과물
  • 각 열은 본래의 라이트맵 / Directional모드로 인해 추가된 텍스처 / Shadowmask 를 나타냄
  • 라이트맵이 각 모드로 인해 3배가 됨 -> 모바일 디바이스에서 메모리 문제 일으킬 수 있음

➕ Distance Shadowmask

  • Shadowmask의 확장
  • Project Settings > Quality에서 Shadowmask Mode를 Distance Shadowmask로 설정
  • Static 오브젝트도 거리에 따라 쉐도우맵을 적용
    -> 근거리는 쉐도우맵으로 실시간 그림자, 원거리는 Shadowmask로 그림자 처리
  • 근거리 다이나믹 오브젝트에게 Static오브젝트로부터 캐스팅되는 그림자를 고품질로 드리우고 싶을 때 / 근거리 Static 오브젝트만 고품질 그림자를 원할 때 사용


2. 라이트 프로브 (Light Probe)

◾ 라이트맵의 한계

  • 아래 이미지는 Subtractive 모드로 배경 등의 Static 오브젝트는 라이트맵의 영향, 캐릭터 등의 다이나믹 오브젝트는 실시간 라이팅이 적용되는 상황
  • 좌측 캐릭터는 그림자 안에, 우측 캐릭터는 그림자 영향을 받지 않는 밝은 영역
  • 두 캐릭터에게 적용되어야하는 라이팅의 환경이 다르지만 두 캐릭터 모두 동일한 라이팅이 적용되며 어색한 모습
  • 또한, 우측 캐릭터 옆 녹색 빛의 오브젝트로 인해 GI가 건물 벽에 맺혀 녹색 빛이 묻어나지만 캐릭터에는 GI가 반영되지 않음
    (Baked Indirect 모드에서는 그렇지 않지만 성능상 모바일 디바이스에서 권장X)

◾ 라이트 프로브

  • 라이트맵처럼 빛을 저장해 놓았다가 런타임상에서 다이나믹 라이트에게 라이트를 반영해주는 라이트 프로브가 이러한 문제를 해결할 수 있음
  • 라이트맵과 라이트 프로브의 차이점은 빛을 저장해두는 방식이 다른 것
    -> 라이트맵은 표면에 맺히는 라이팅 정보를 저장하고
    -> 라이트 프로브는 라이팅이 지나가는 빈 공간의 지점을 저장하여 그 공간에 위치하는 다이나믹 오브젝트에 라이팅을 반영하는 것
  • 라이트 프로브는 다양한 지점의 빛을 수집하여 미리 저장하고, 프로브 하나하나가 주변의 빛을 미리 연산해서 가지고 있음 (라이트맵을 베이킹하는 것과 비슷)
  • 수집된 라이트 프로브들은 주변의 빛을 수치로 인코딩하고, 이 수치들을 런타임상에서 디코딩하여 사용
  • 미리 연산된 정보를 사용하므로 실제 라이팅 연산보다 훨씬 저렴
  • 라이트 프로브를 적용하여 자연스럽게 동화된 모습

1. 프로브(Probe)의 설치

  • 라이트 프로브는 실제의 라이트가 아니라서 라이트 오브젝트와 별개로 씬에 따로 설치해줘야 함
  • Component > Rendering > Light Probe Group 혹은 Create > Light > Light Probe Group으로 그룹 생성
  • Edit Light Probes 버튼을 눌러 라이트 프로브를 추가하고 편집할 수 있음
  • 라이트 프로브들을 씬 전체에 배치
  • 일정한 해상도가 존재하는 텍스처인 라이트맵과 다르게, 라이트프로브는 밀도에 따라 성능이 조절되므로 가능한 필요한만큼 배치하는 것이 좋음
    (ex- 마을 내에만 설치, 캐릭터가 들어갈 수 없는 공간에 미설치, 건물 주변에 라이트 프로브의 높은 밀도)

2. 데이터의 크기와 정밀도

  • 각 라이트 프로브들의 데이터 크기는 작음 (조화함수의 결과인 단순한 숫자 값들만 저장하고 있음)
    • 구면 조화 함수: 구면을 기준으로 주변 공간의 에너지 분포를 근사하여 표현하는 함수 (차수를 반복하여 더 많은 정밀도를 표현할 수 있으며 게임그래픽에서는 라이팅 결과를 저장하는 용도로 응용)
    • 일반적으로 실시간 렌더링에서는 성능상의 문제로 많아야 3단계(l=2)로 제한
  • 데이터 크기가 작은 만큼 정밀도도 높지 않으며, 디퓨즈 라이팅만 표현할 수 있고 스펙큘러 라이팅은 표현하지 못함
  • 그래서 다이나믹 오브젝트는 라이트 프로브가 적용되더라도 여전히 실시간 라이팅이 적용됨
❗ 실시간 라이팅만으로만 처리하기 버거운 GI등의 라이팅 환경을 보조해줌

3. 프로브의 적용

  • Lighting 창 하단의 Auto Generate가 켜져있으면 라이트 프로브의 수정이 자동으로 바로 업데이트 됨
  • 다이나믹 오브젝트가 씬에 존재하면, 유니티는 해당 오브젝트의 Mesh Renderer 주변의 라이트 프로브를 선별해 프로브들의 값을 보간
  • 만일 오브젝트에 라이트 프로브 적용을 제외하고 싶으면 Mesh Renderer의 Light Probes를 꺼줄 수 있음
profile
( •̀ .̫ •́ )✧

0개의 댓글