멈추지 않고 끈질기게

[Graphic][Unity] 라이트 프로브(Light Probe), 리플렉션 프로브(Reflection Probe) 본문

Graphics

[Graphic][Unity] 라이트 프로브(Light Probe), 리플렉션 프로브(Reflection Probe)

sam0308 2023. 3. 21. 11:14

※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.

※ 해당 포스팅은 Unity 2021.3.15f1 버전을 기준으로 작성되었습니다.

※ 해당 포스팅은 하기 출처들을 참조하였습니다.

- 오지현, 유니티 그래픽스 최적화 스타트업, 비엘북스, 2019

 

 

 

 

이번 포스팅에서는 라이트 프로브와 리플렉션 프로브에 대해 알아보겠습니다.

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

라이트 프로브의 필요성 

그림 1. 라이트맵의 한계

 라이트 맵은 비싼 라이팅 연산을 저렴한 비용으로 처리할 수 있는 좋은 방법이지만, static 오브젝트에만 반영된다는 한계가 있습니다. 동적 오브젝트는 위치에 따라 다른 라이팅을 받아야 하지만, 라이트맵을 사용하면 동일한 라이팅이 적용됩니다. 그림 1을 보면 그림자 안에 있는 오브젝트와 밖에 있는 오브젝트에 동일한 라이팅이 적용되어 같은 밝기로 노출되는 모습을 확인할 수 있습니다. 라이트맵 포스팅에서 소개한대로 Baked Indirect 모드를 선택하면 동적 오브젝트에도 그림자를 드리울 수 있지만, 성능소모가 큰 방법입니다. 

 

 라이트맵만으로는 라이팅을 완벽하게 처리할 수 없고, 그렇다고 라이팅을 실시간 연산하기에는 비용이 너무 크기 때문에 이를 보조해줄 기능이 필요합니다. 라이트 프로브(Light Probe)가 이러한 문제를 해결해줄 수 있습니다. 라이트 프로브는 라이트맵처럼 빛을 저장해 두었다가 런타임상에서 동적 오브젝트에 반영해줄 수 있는 기능입니다. 라이트맵이 표면에 맺히는 라이팅 정보를 저장한다면, 라이트 프로브는 라이팅 지나가는 빈 공간의 지점을 저장해두었다가 그 공간에 들어온 동적 오브젝트에 라이팅을 반영합니다. 주변의 라이팅 결과를 미리 인코딩하여 저장해놓으며, 런타임상에서 디코딩하여 사용합니다. 미리 연산된 정보를 사용하기 때문에 실시간 라이팅보다는 훨씬 저렴한 비용으로 라이팅을 보강해줄 수 있습니다.

 

그림 2. 라이트 프로브 적용 후

그림 2는 그림 1과 동일한 씬에 라이트 프로브를 추가한 모습입니다. 그림자 안의 오브젝트가 그림자의 영향을 받아 어두워지면서 밖의 오브젝트와 구분되는 모습을 확인할 수 있습니다. 

 

 

라이트 프로브 설치

 라이트 프로브는 직접 빛을 내는 광원이 아니기 때문에 라이트 오브젝트와 별개로 씬에 배치해야 합니다. 하이아라키 뷰에서 우클릭 -> Light -> Light Probe Group을 선택하여 생성할 수 있으며, Light Probe Group 컴포넌트의 Edit Light Probes 버튼을 눌러 추가, 삭제 등의 편집을 할 수 있습니다. 라이트맵과 달리 라이트 프로브의 밀도는 여기서 어떻게 배치하느냐에 달려있으므로, 적절한 밀도를 판단하여 설치해주는 것이 좋습니다. 프로브 하나에 든 데이터는 라이트맵보다 훨씬 적지만, 그렇다고 프로브를 무분별하게 설치하면 동적 오브젝트가 주변의 라이트 프로브를 탐색하는 데 드는 비용이 커지게 됩니다. 동적 오브젝트가 접근할 수 없는 영역이라면 굳이 설치하지 않는것도 괜찮고, 가급적이면 빛의 변화가 큰 영역일수록 밀도를 높이는 것이 좋습니다.  

 

 

라이트 프로브 적용

그림 3. 오브젝트 근처의 라이트 프로브

 프로브 수정 결과를 바로바로 확인하고자 한다면 Lighting 창 하단의 Auto Generate 플래그를 체크해 주는 것이 좋습니다. 업데이트가 완료되면 라이트맵에 영향을 주는 광원들이 동적 오브젝트에도 영향을 주게 됩니다. 동적 오브젝트 배치 시 유니티는 씬에 존재하는 라이트 프로브 중 해당 오브젝트 주변의 라이트 프로브를 선별하고 프로브들의 값을 보간해줍니다. 라이트 프로브 근처의 오브젝트 선택 시 하얀 구체로 나타나는 것을 확인할 수 있습니다. 특정 오브젝트의 라이트 프로브 적용 여부를 끄고 싶다면 (Skinned)Mesh Renderer에서 Light Probes 항목을 Off로 설정하면 됩니다.

 

 

2. 리플렉션 프로브(Reflection Probe)

빛의 반사 과정

그림 4. 빛의 반사

 그래픽스 라이팅에서도 에너지 보존 법칙은 적용됩니다. 빛이 표면에 닿으면 빛의 일부는 표면에 흡수되었다가 산란되며, 흡수되지 않은 빛은 바로 반사됩니다. 이 때 (반사되는 빛의 양) + (산란되는 빛의 양) <= (원래 빛의 양)이 성립합니다(=은 현실에선 거의 불가능). 이 때 반사되는 빛을 스페큘러(specular), 산란되는 빛을 디퓨즈(diffuse)라고 합니다. 빛의 반사는 대상의 미세한 표면(microfacet)이 매끄러울수록 선명하게 일어나며, 거칠수록 분산됩니다. 

 

 이러한 정보들은 오브젝트의 재질에 따라 나뉘며, 이것을 파라미터화 시킨 것이 물리 기반 쉐이더의 머티리얼입니다. 유니티의 스탠다드 쉐이더는 이 머티리얼을 이용하여 물리 기반 라이팅을 시행합니다. 또한 에너지 보존 법칙에 따라 반사광이 많을수록 산란광은 적어야 합니다. 즉, 머티리얼에서 스페큘러 ∝ 1/ 디퓨즈 의 관계가 성립합니다. 

 

 

금속 재질의 Reflection

그림 5. 금속 재질의 머티리얼(리플렉션 프로브 X)

 빛의 반사(Reflection)는 특히나 금속 재질에 가까운 머티리얼일수록 중요합니다. 하지만 복잡한 씬에 반사율이 높은 머티리얼의 오브젝트 배치 시 주변 환경과 제대로 어울리지 못합니다. 금속 재질 느낌을 최대한 주기 위해 Metalic, Smoothness를 1로 설정하여 반사광을 최대한 살린 머티리얼의 오브젝트를 배치해보면, 그림 5와 같이 주변 환경을 반사하는 것이 아니라 부자연스러운 반사 이미지를 확인할 수 있습니다.

 

 유니티에서 반사 이미지는 라이팅 창에서 설정할 수 있으며, Environment Reflections Source의 디폴트 값은 스카이박스입니다. 스카이박스는 하늘을 표현하기 위한 이미지이므로, 이를 반사하면 상기 사진처럼 주변 환경과 어울리지 않게 됩니다. 이를 해결하기 위한 수단이 리플렉션 프로브(Reflection Probe) 입니다. 

 

 

리플렉션 프로브 적용

그림 6. 금속 재질의 머티리얼(리플렉션 프로브 O)

 라이트 프로브가 빛을 저장해두었다가 주변 오브젝트에 적용한다면, 리플렉션 프로브는 주변 환경을 반사하는 반사 이미지를 저장해둡니다. 주변 환경을 미리 렌더링하여 이미지로 저장해두고, 동적 오브젝트가 리플렉션 프로브의 영역에 들어오면 반사 이미지를 스카이박스 대신 리플렉션 프로브의 이미지로 대체하는 것입니다. 그림 5의 씬에서 리플렉션 프로브를 배치하면 오브젝트 표면이 스카이박스 대신 주변 환경을 보여주는 것을 확인할 수 있습니다.

 

 라이트 프로브와 마찬가지로 하이아라키 뷰에서 우클릭 -> Light -> Reflection Probe를 선택하여 생성할 수 있습니다. 라이트 프로브와 달리 여러개의 그룹이 아닌 하나의 프로브 포인트를 가지며, 편집 버튼을 눌러 박스 컬라이더와 같이 육면체의 프로브 영역을 조절할 수 있습니다. 오브젝트가 이 영역 안에 있으면 반사 이미지로 해당 리플렉션 프로브의 이미지를 사용하고, 벗어날 경우 디폴트값인 스카이박스를 사용합니다.

 

 프로브 영역을 필드 사이즈만큼 크게 잡으면 어디서든 리플렉션 프로브의 영향을 받게 되지만, 해당 필드 안에 광원이 많다면 부자연스럽게 연출될 수 있습니다. 리플렉션 프로브의 영역 안에도 리플렉션 프로브를 배치할 수 있으므로, 이러한 특정 광원 근처에 리플렉션 프로브를 추가하여 해결할 수 있습니다. 이렇게 영역이 중첩될 경우 가장 가까운 프로브의 영향을 받으므로, 주요 포인트에 프로브를 추가로 배치함으로써 디테일을 살릴 수 있습니다.

 

 

성능 상 주의사항

 다만, 리플렉션 프로브는 일종의 큐브맵 형태의 이미지로, 라이트 프로브에 비해 메모리를 요구하는 편입니다. 리플렉션 프로브 컴포넌트의 Cubemap Capture Settings에서 Resolution항목을 통해 해상도를 조절할 수 있습니다. 디폴트 값은 128인데, 이는 육면체의 한 면의 사이즈가 128 텍셀이라는 뜻으로 총 128 * 128 * 6 = 98,304 텍셀입니다. 256으로 늘릴 경우 256 * 256 * 6 = 393,216 텍셀로, 일반적인 2D 텍스처에 비해 총 6장인 만큼 해상도 증가에 따른 텍셀 상승폭이 상당한 편입니다. 따라서 타겟 디바이스의 성능을 고려하여 해상도를 가급적 낮게 설정하는 것이 좋습니다.

 

 기본적으로 리플렉션 프로브는 매우 밝은 광원의 빛을 제대로 반사해주지 못하나, 리플렉션 프로브 컴포넌트의 HDR 플래그를 체크하면 이러한 밝은 빛도 반사시켜줍니다. 본디 HDR 텍스처는 R, G, B, A 채널의 값을 0~1 범위를 넘어도 저장할 수 있는 대신 일반 텍스처에 비해 높은 용량이 필요하나, 유니티에서는 0~1의 범위로 압축하고 대신 Multiply 값을 넣어 일반적인 텍스처에 HDR 정보를 기록합니다. 따라서  HDR 옵션을 사용해도 메모리 용량이 늘어나지 않으나, 마하밴드(명도가 다른 영역 간에 경계선이 보이는 현상)와 같은 부작용이 있습니다. 

 

 리플렉션 프로브의 Type 옵션은 Baked가 디폴트 값이며, 반사 이미지에 static 오브젝트만 렌더링하여 저장해둡니다. 해당 옵션을 Realtime으로 변경하면 동적 오브젝트도 런타임상에 반영해줍니다. 플레이어가 움직이는 대상의 반사 이미지로 사용할 때 고려할 수 있습니다. 움직일 오브젝트의 하위에 리플렉션 프로브를 집어넣고 Culling Mask에서 해당 오브젝트의 레이어를 선택하여 제외하면 됩니다.

 하지만 Realtime 리플렉션 프로브는 일반적인 Baked 리플렉션 프로브에 비해 성능 소모량이 큽니다. 매 프레임마다 리플렉션 프로브 때문에 추가적인 렌더링을 실행해야 하므로, 렌더링 대상을 줄이기 위해 Culling Mask를 통해 대상 오브젝트를 최대한 제한하고 Clipping Planes를 조절하여 렌더링 범위를 줄이는 등의 노력이 필요합니다.