주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 21. PBR Shader 구성


챕터 20 까지 하고 글을 마무리하려고 했는데, 궁금해 하시는 분이 계셔서 글을 추가합니다.

아마도 프로그래머나 TA 라면 PBR 을 실제로 어떻게 구성해야 하는지에 대한 의문이 들 겁니다.

각각의 의미는 알겠는데 셰이더의 결과에는 무엇이 반영되어야 하나요?

우리는 [ 9. Global Illumination & Indirect Lighting ] 에서 조명은 Direction Lighting 과 Indirect Lighting 으로 구분된다는 것을 알게 되었습니다. 이러한 조명들 중에서 눈에 도달하게 되는 성분들이 셰이더 계산의 결과가 됩니다.


조명 분석


눈에 들어 오는 빛들을 정리해 보죠. 여기에서는 대기 산란( atmospheric scattering )과 같은 복잡한 현상에 대해서는 언급하지 않고 기본적인 것들에 대해서만 다루도록 하겠습니다. 그림 1 에 눈에 들어 오는 빛의 몇 가지 샘플들을 그려 봤습니다.

그림 1.

여러분은 그림 1 에 있는 빛들의 카테고리를 규정할 수 있어야 합니다. 반사나 굴절을 통해 눈으로 직접 들어 온 빛은 직접 조명( direct lighting )이며, 다른 물체에 튕겨졌다가 온 빛은 간접 조명( indirect lighting )입니다.

  • 1 : [ direct ] diffuse + specular.
  • 2 : [ direct ] diffuse + specular.
  • 3 : [ direct ] emissive( 방출 ). 물체 자체가 발광하고 있음.
  • 4 : [ indirect ] diffuse + specular.
  • 5 : [ direct ] diffuse + specular.
  • 6 : [ direct ] diffuse + specular.
  • 7 : [ indirect ] transmission( 투과 ).
  • 8 : [ indirect ] diffuse + specular.
  • 9 : [ direct ] transmission.

여기에서 혼란에 빠지는 분들이 있을 겁니다.

제 눈에는 정반사 성분은 안 보이는데요, 왜 "diffuse + specular" 가 들어 오는 건가요?

스펙큘러 반사는 정반사( 입사각과 반사각이 동일한 반사 )만을 의미하는 것이 아닙니다. 특정 방향을 중심으로 로브( lobe )를 형성합니다. 스펙큘러 반사가 얼마나 퍼지냐는 BRDF 에 의해서 결정되죠. 이것은 표면이 완전히 평평하지 않기 때문에 발생하는 현상입니다. 그림 2 에서 여러 형태의 로브를 보여 주고 있습니다.

그림 2. 매질의 거칠기에 따른 스펙큘러 로브. 출처 : [Specular IBL].

그러므로 정반사 각도가 아니더라도 스펙큘러가 눈에 들어 올 수 있는 것입니다.

자, 이제 눈에 들어 올 수 있는 빛의 성분들을 나눠 보죠. 빛이라는 것은 눈에 들어 오면 누적되기 때문에 다음과 같은 식을 세울 수 있습니다.

식 1.

식 1 이 기본적인 셰이더의 함수입니다.

간단하게 머리글자로 표기하도록 하겠습니다.

식 2.

그런데 식 2 를 보고 있으면 의문이 생길 겁니다. 셰이더라는 것이 화면상의 한 픽셀에 대해서 처리됩니다. 그런데 어떻게 여러 광원에서 오는 빛을 처리할 수 있을까요?

그래서 실제로 결과는 다음과 같이 처리되어야 합니다.

식 3.

식 3 에서 Sigma 연산자는 괄호 안의 요소를 모두 더한 결과를 누적한다는 의미입니다. 광원이 1 부터 n 까지 있을 때 각각의 diffuse, specular, transmission 를 더한 결과를 모두 누적한다는 겁니다.

여기에서 하나의 의문을 가질 수 있습니다.

왜 E 는 광원별로 처리하지 않나요?

방출( Emissive ) 은 광원에서 발생하는게 아니라 재질의 특성입니다. 그러므로 한 번만 처리됩니다. 

이런 계산을 셰이더에서 수행하는 방법은 여러가지가 있는데, 크게 두 가지 방식으로 처리됩니다. 여기에서는 누적된 광원을 적용하는 패스가 따로 있다는 가정을 가지고 있습니다. 

  • 한 셰이더에서 한 개의 광원에 대한 결과를 처리하고 광원을 바꿔가면서 여러 패스를 실행할 수 있습니다.
  • 한 셰이더에서 여러 개의 광원의 결과를 한꺼번에 처리합니다.

그림 3. 조명 누적.

그런데 사실 싱글패스를 구현하는 것은 어렵습니다. 셰이더라는 것이 화면의 전체 픽셀에 대해서 적용되므로 불필요한 계산이 수행될 수 있습니다. 게다가 몇 개의 광원을 처리해야 할지 애매하죠. 셰이더에서 무거운( 지금은 안 무거울라나... ) 루프를 돌려야 합니다. 그래서 최적화를 위해서 광원 영역에 대한 stencil 을 찍어 두거나 영역( viewport, scissor-rect )을 따로 잡은 후에 멀티패스로 돌리는 경우가 많습니다.


Direct Lighting vs Indirect Lighting


눈썰미가 좋은 분들은 식 3 에 직접 광원 성분과 간접 광원 성분이 분리되어 있지 않다는 것을 눈치채셨을 겁니다.

간접 광원은 매우 계산하기 힘들기 때문에 보통은 라이트맵( Lightmap )을 사용하거나 IBL( Image-Based Lighting ) 큐브맵을 사용하게 됩니다. 라이트맵과 IBL 큐브맵에 대해서 여기에서 자세하게 설명하지는 않겠습니다. 검색해 보면 관련 자료들이 많으니 그것들을 참고하시기 바랍니다.

여기에서는 그것들의 차이만을 간략하게 설명하도록 하겠습니다. 나중에 기회가 되면 한 번 정리하도록 하겠습니다.

  • 라이트맵은 정적인 라이팅 환경을 대상으로 구워집니다. 그래서 일반적으로 어느 방향에서 봐도 동일한( 뷰 독립적인, view-independent ) 디퓨즈 성분만을 저장합니다. 일반적인 라이트맵을 사용하게 되면 스펙큘러 성분을 알 수 없습니다. 대신 스펙큘러 성분을 어느정도 반영하기 위해서 RNM( Radiosity Normal Map ) 라이트맵이라는 것이 있기는 하지만 이것 역시 정적 환경이라는 점에서는 차이가 없습니다.
  • IBL 큐브맵은 조도( irradiance ) 샘플을 저장합니다. 어떤 기준점을 중심으로 주변의 빛들을 모두 광원으로 처리합니다. 여기에는 디퓨즈 성분과 스펙큘러 성분이 모두 들어 갈 수 있습니다. 실시간에 큐브맵을 생성한다면 동적인 라이팅 환경을 반영하는 것도 가능합니다( 물론 성능 저하는 감수해야 합니다. 큐브맵을 다시 만들어야 하기 때문이죠 ). 동적인 라이팅을 허용하는 IBL 구현은 현재 많지 않습니다. 기존에 Asker 라는 게임 프로젝트에서 프레임별로 각 면을 나눠서 생성한 적은 있는데, 그것만으로도 큰 부하가 듭니다. 단순하게 씬을 렌더링하는 것을 떠나서 임포턴스 샘플링( importance sampling )같은 것도 해야 하기 때문입니다. 게다가 시차때문에 생기는 문제를 해결( 시차 보정, Parallax Correction )해야 합니다. 현재 하드웨어에서는 사용할만 한지는 잘 모르겠네요. 펄 어비스에 다니는 지인의 말로는 실제로 프로젝트에서 사용하고 있다고 하는 것 같더군요. 이 외에도 여러 가지 문제( 캡쳐 범위 등 )가 존재하는데 잡다한 문제를 다 해결해야지 사용할 만 합니다.

어쨌든 라이트맵이나 IBL 큐브맵을 사용해서 간접광 성분을 계산할 수 있습니다.

그러므로 식 3 은 다음과 같이 변경됩니다.

식 4.

"dl" 은 직접광을 의미하며 "il" 은 간접광을 의미합니다.

그런데 사실 투과( Transmission )같은 경우에는 서브 서피스 스캐터링( Sub-Surface Scattering )이 아니라면 일반적으로는 배제합니다. 피부나 초같은 밀랍( Wax )같은 재질이 아니라면 그냥 투과는 처리하지 않습니다. 왜냐하면 그 비용이 상당히 비싸기 때문이죠. 하지만 어쨌든 일반식을 만드는 것이니 식은 그냥 두겠습니다.


에너지 보존 법칙


마지막으로 고려해야 할 부분은 에너지 보존법칙입니다. 

일반적으로 에너지 보존법칙은 디퓨즈와 스펙큘러에만 적용합니다. Emissive( 방출 )은 자체적으로 에너지가 생성된 것이고  에너지 보존 법칙이 성립하려면 다음과 같이 되어야 합니다.

식 5.

그런데 일반적인 BRDF 식에서의 Diffuse, Specular, Transmission 에는 이미 Absorbtion( 흡수 ) 이 포함되어 있습니다. 이런 계산까지 전부 다 하게 되면 엄청나게 복잡해질 겁니다. 물론 이런 계산을 포함한 BRDF 도 어딘가에는 있겠죠. 제가 BRDF 함수들을 모두 완벽하게 알고 있는 게 아니라서 잘은 모르겠습니다.

그러므로 일반적으로는 Diffuse 와 Specular 에 대해서만 에너지 보존 법칙을 적용하게 됩니다. 그게 눈에 가장 잘 보이기 때문입니다.

보통 Specular 의 세기는 금속성( metalic )에 의해서 결정되고 있기 때문에 metalic 을 에너지 보존법칙을 적용하는데 사용합니다. 물론 구현마다 차이는 있을 수 있습니다만, 적어도 UE4 는 metalic 을 기준으로 사용합니다.

그래서 식 4 에 에너지 보존 법칙을 적용하면 다음과 같습니다.

식 6.


BRDF 와 Light Intensity


가끔 BRDF 식을 보면 Light Intensity 를 포함하고 있는 경우가 있습니다. 챕터 20 댓글에 어떤 분이 이와 관련한 질문을 하셨습니다. 요약하자면 "Light Intensity 와 BRDF 의 관계가 어떻냐"는 것이었습니다.

그분이 예로 드신 Oren-Nayar BRDF 식은 다음과 같습니다.

식 7. Oren-Nayar BRDF. 출처 : [ Oren-Nayar reflectance model ], Wikipedia.

해당 문서에서는 E0 를 미세면에 도달한 조도( E0 is irradiance when the facet is illuminated head-on )라고 이야기하고 있습니다. 그리고 Lr 을 휘도( the radiance of the reflected light Lr ) 라고 이야기하고 있습니다. E0 이 일반적으로 Light Intensity 라 할 수 있습니다.

여기에서 두 가지 이슈가 발생합니다.

  • Light Intensity 에는 어떤 값이 들어 가야 하나요?
  • 식 7 에다가 Light Intensity 를 곱해야 하는 것일까요?

첫 번째 질문에 대해서 이야기하자면, 일단 대부분의 BRDF 함수들은 Light Intensity 로 칸델라( Candela, cd )를 받는 것으로 알고 있습니다. 위에서도 미세면에 도달한 빛( 조도 )에 대한 함수이기 때문에 이것은 칸델라여야 합니다. 칸델라는 단위 입체각당 광속을 의미합니다. UE4 에서는 점광원에 대해서 광속( luminous flux, lm )을 받다가 최근에 칸델라를 받도록 수정했죠. 광속이 뭔지 기억이 안 나시는 분들은 [ 4. 광원의 밝기( 광속 ) ] 챕터를 참조하시기 바랍니다.

두 번째 질문에 대해 답하자면, Light Intensity 가 BRDF 공식에 이미 적용되어 있다면 적용하지 말아야 한다는 겁니다. 그러므로 BRDF 셰이더 함수를 만든다면 Light Intensity 가 배제된 순수한 BRDF 를 만드는 것이 좋겠죠. 식 7 의 경우에는 E0 을 배제한 나머지 항들이 순수한 BRDF 식의 항들입니다.


정리


기본적으로 그래픽스에서 휘도( radiance, luminance )를 다룰 때는 눈에 들어 오는 모든 빛은 누적된다고 생각해야 합니다.

단지 해당 빛이 어디에서 오는지를 명확하게 할 필요가 있습니다. 그래야지 조명별로 처리할지 한 번만 처리할지 결정할 수 있기 때문입니다.

하지만 더하기만 하지는 않는 경우도 존재합니다. 예를 들어 차폐같은 것들이 그렇죠. 하지만 차폐도 보통 빛을 아예 누적하지 않거나 감쇠( attenuation ) 비율을 곱하는 식으로 적용하는 경우가 많습니다. Ray-Tracing 기법을 사용하면 무조건 더하기만 해도 아무 문제가 없지만 Rasterization 에서는 이런 저런 꼼수들이 들어 갑니다. 여기에 대해서 자세하게 언급은 안 하겠지만, Ray-Tracing 과 Rasterization 의 차이에 대해서 한 번 찾아 보는 것도 생각을 정리하는데 많은 도움이 될 것이라 생각합니다.

나름대로 정리한다고 하긴 했지만 빠져 있는 성분들이 꽤 많습니다; 대기산란, 차폐( Shadow, Ambient Occlusion 등 ).

하지만 BRDF 공식을 가지고 있을 때 어떻게 이것들을 결합해야 할지에 대해서는 대충 감이 오셨을 것이라 생각합니다.

PS : 반투명 재질을 렌더링한 결과( 우리가 일반적으로 사용하는 알파블렌딩 )는 투과( Transmission ) 성분을 반영합니다. 단지 IOR( Index Of Reflection )을 고려하지 않아서 굴절( Refraction )이 없는 것처럼 보일 뿐입니다. 투과 성분은 광원에서의 빛이 매질 내부에서 산란이 된 후 튀어 나오는 성분이기 때문에 매우 계산이 어렵습니다. 그래서 보통 후처리( Post-Process ) 패스에서 대충 왜곡( distortion )하는 식으로 처리합니다.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.

주의 : 여기에서 Specular BRDF 공식에 대해서는 자세하게 다루지 않을 계획입니다. 공부를 더 하고 싶은 분들은 참고자료들을 확인하세요.


[ PBR 이란 무엇인가 ] 20. Specular BRDF

19. Diffuse BRDF ] 에서 Diffuse 를 위해서는 일괄적으로 Lambert cosine law 를 사용한다고 했습니다. 그렇기 때문에 금속이 아니라면 Diffuse 는 모든 재질에 대해서 동일하게 적용된다고 보면 됩니다.

Disney 의 Burley 같은 경우에는 새로운 diffuse model 을 만들었습니다. 그러나 그것은 그림1 처럼 외형상 큰 차이를 보여주지 못하고 계산 비용만 더 들기 때문에 실시간 그래픽스에서 잘 사용되지 않습니다.

그림1. Lambert 모델과 Burley 모델의 비교. 큰 차이를 보이지는 않음. 출처 : [ 1 ].

하지만 Specular 의 경우는 다릅니다. 물체가 어떤 재질로 구성되어 있느냐에 따라 달라집니다( 물론 Diffuse 도 그래야 하지만 대충 넘어갑시다. 두 마리 토끼를 잡기는 쉽지가 않으니... ). Specular 는 물체의 재질특성을 보여주는 매우 중요한 요소입니다. 그러므로 여러분이 한 번이라도 들어 본 대부분의 BRDF 모델들은 거의 다 specular 와 관련된 것일 겁니다. 그렇기 때문에 조금 비용을 들이더라도 재질 차이를 확실하게 보여 줄 만한 모델을 사용하죠.

지금까지 우리는 PBR 의 대원칙들에 대해서 살펴 봤습니다. 처음에 글을 시작하면서 PBR 이라는 것은 다음과 같은 요소를 포함해야 한다고 했습니다.

    • 전역 조명( Global Illumination ) : 이미지 기반 라이팅( Image Based Lighting, IBL ).
    • 에너지 보존 법칙( Energy Conservation ).
    • 반사도( Reflectivity ) : 디퓨즈 및 스펙큘러( Diffuse & Specular ).
    • 미세면( Microsurface ) : 러프니스( Roughness ).
    • 프레넬 법칙( Fresnel's Law ).
    • 금속성( Metalicity ).

[ 1. 인간과 빛 ], [ 2. 조도와 휘도 ], [ 3. 빛의 감쇠 ], [ 4. 광원의 밝기( 광속 ) ], [ 5. 조도( illuminance ) 측정 ], [ 6. 휘도( luminance ) 측정 ] 에서는 빛의 기본 성질에 대해서 중점적으로 이야기했습니다.

[ 7. Light Intensity 설정 ], [ 8. Attenuation Radius 설정 ] 에서는 에너지 보존 법칙에 대해서 중점적으로 이야기했습니다.

[ 9. Global Illumination & Indirect Lighting ], [ 10. Image Based Lighting ], [ 11. UE4 GI : Sky Light ], [ 12. UE4 GI : Reflection Capture ], [ 13. UE4 GI : Lightmass & Mobility ] 에서는 전역 조명에 대해서 중점적으로 이야기했습니다.

[ 14. 모든 것은 빛납니다 ], [ 15. 모든 것은 프레넬을 가집니다 ], [ 17. Fresnel 이란 ] 에서는 프레넬 법칙에 대해서 중점적으로 이야기했습니다.

[ 실제 이미지에서 specular 와 Diffuse 분리하기 ], [ 16. Reflection 에 대한 잘못된 상식들 ], [ 18. Distribution Function ] 에서는 반사도와 Diffuse  및 specular 개념에 대해서 중점적으로 이야기했습니다.

[ 19. Diffuse BRDF ] 에서는 Diffuse BRDF 에 대해서 중점적으로 이야기했습니다.

마지막으로 이번 챕터에서는 미세면과 금속성에 대해서 다루게 됩니다. 아무런 순서도 없이 두서없이 글을 진행한 것처럼 보였을지 모르겠지만 나름대로 생각하고 진행했답니다.

이제 PBR 에서의 specular BRDF 에 대해 중점적으로 살펴 보도록 하겠습니다.

MERL 100

Diffuse 및 Specular 모델을 만들 때 그냥 내키는 대로 만드는 것은 아닙니다. 어떤 기준이 있어야 하며 실제로 측정된 BRDF 모델을 사용하는 경우가 많습니다. 그 중 하나가 MERL 100 이라는 것이죠.

그림2. MERL 100. 출처 : [ 2 ].

이것은 100 개의 등방성 재질을 캡쳐한 것으로 페인트, 나무, 금속, 섬유, 돌, 플라스틱, 그리고 다른 합성 재질들을 포함합니다. 이것은 새로운 BRDF 모델들이 나오면 그것의 결과가 얼마나 맞는지 확인하기 위해서 사용됩니다. 자세한 내용에 대해서 알고자 한다면 [ 2 ] 를 확인하시기 바랍니다.

이 MERL 100 을 반드시 이해하실 필요는 없습니다. 지금 우리가 다루고 있는 영역이 매우 물리적인 측정값에 기반하고 있다는 것을 강조하기 위해서 언급했을 뿐입니다.

미세면 분포 함수 : D 함수

미세면( Microfacet ) 모델이라는 것은 폴리곤의 거대면( Mcrosurface )은 그림3 처럼 미세면으로 구성되어 있다는 전제에서 반사나 굴절을 모델링하는 것을 의미합니다.

그림3. Microsurface vs Macrosurface. 출처 : [ 4 ].

여러분은 반짝반짝 빛나는 면들은 매끈하고 빛나지 않는 면들은 거칠다는 것을 경험적으로 알고 계실 겁니다. 물론 코팅을 해 놓아서 빛날 수도 있지만 그 부분은 예외로 두고 이야기하도록 하겠습니다.

하지만 이러한 미세면의 분포는 재질마다 다를 겁니다. 그것을 Albedo 설정하듯이 아티스트가 일일이 설정할 수는 없겠죠. 게다가 미세면이라는 것은 거의 눈에 보이지도 않는 면을 이야기합니다. 

그러므로 몇 가지 매개변수만으로 분포를 계산할 수 있는 함수가 필요하겠죠? 그것이 바로 미세면 분포 함수입니다. Distribution 의 머리글자를 사용해 이 함수를 D 라고 부릅니다. 일반적으로 이 D 함수는 통계적인 기법을 이용하게 됩니다. 여기에서 세부 사항에 대해서 구체적으로 다루지는 않겠습니다. 더 구체적으로 알고 싶은 분들은 참고자료를 확인하세요.

어쨌든 이 D 함수는 Specular Peak 가 어느 방향을 향하게 되는지를 결정하게 됩니다. 우리는 Specular 를 거울면 반사라고 생각하고 있지만, 사실은 입사각과 반사각이 정확하지는 않습니다. 이는 표면의 거칠기( 미세면의 분포 )에 영향을 받게 되죠. 거울면 반사에서 벗어나서 생기는 반사를 "Off-specular reflection" 이라고 부릅니다. 우리 말로 굳이 해석하자면 "거울면 반사( 정반사 )를 벗어난 반사"라고 할 수 있겠습니다.  

그림4 는 서로 다른 미세면 분포를 가진 표면에서 이 off-specular reflection 이 어떻게 달라지는 지 보여 줍니다.

그림4. Off-specular reflection 의 예: 지표각에 가까워질 수록 specular 의 방향( M ) 이 반사각과 달라지는 모습을 보여줌.

D 함수는 거대면 내에서 우리에게 거울면 반사를 보여줄 수 있는 미세면의 양이 얼마나 되는지를 알려주는 것입니다( 여기에 대해서 제가 이해한 바를 정리해 봤는데, 자세히 알고 싶으신 분들은 [ PBR Specular D 의 기하학적 의미 ] 를 참고하세요 ).

미세면 그림자 마스킹 함수 : G 함수

자, 여러분은 렌더링할 때 그림자가 없으면 매우 어색하다는 것을 알수 있습니다. 미세면의 그림자의 경우에는 그 정도 영향력을 가지지는 않습니다. 눈에 거의 보이지도 않는데 알게 뭡니까.

그림5. 그림자 마스킹의 기하학. 같은 미세면 노멀 m 을 사용하는 세 지점을 비교.

두 개는 io 방향에서 보이며, 한 개는 i 방향에서 차폐됨.

하지만! 에너지 보존 법칙을 위해서는 반드시 고려되어야 합니다. 그런데 미세면 그림자 마스킹도 아티스트가 작업할 수 있을만한 건 아니겠죠. 그래서 이것도 함수로 만듭니다. 기하와 관련된 것이므로 Geometry 의 머리글자를 사용해 G 함수라고 부릅니다. 

프레넬 함수 : F 함수

모든 물체의 반사에는 프레넬 법칙이 적용된다고 했습니다. 그러므로 당연히 이것과 관련한 함수도 있겠죠? Fresnel 의 머리글자를 사용해 F 함수라고 부릅니다. 프레넬이 뭔지 기억이 가물가물한 분들은 [ 17. Fresnel 이란 ] 을 참고하세요.

금속일수록 거의 거의 대부분의 각도에서 높은 반사율을 보이며, 비금속일수록 지표각에서 높은 반사율을 가집니다.

모아봅시다

자 위에서 언급한 세 개의 함수를 모아 봅시다. 어떤 빛이 표면에 들어 오면 미세면 분포 함수 D 에 의해서 off-specular reflection 이 결정될 것이고, 기하학적 감쇠 G 함수에 의해 에너지 보존 법칙이 적용됩니다. 그리고 프레넬 함수 F 에 의해 반사율이 결정됩니다.

눈치가 빠른 분들은 DG 가 표면의 거칠기( roughness )와 관련이 있고 F 가 금속성( metallicty )과 관련이 있음을 알 수 있을 겁니다. 이걸 제대로 표현하기 위해서는 매우 많은 공식이 필요하지만 여기에서는 구체적으로 언급하지 않겠습니다. 참고자료를 확인하시기 바랍니다.

그러므로 미세면과 프레넬을 고려한 Specular BRDF 는 기본적으로 식1 과 같은 형태를 띄고 있습니다. 우리가 위에서 언급하지 않은 것들이 분모에 들어 가 있지만 별로 신경쓰실 것은 없습니다. 빛과 표면의 관계 및 에너지 보존을 위해 들어 가 있습니다 :

식1. Specular BRDF.

식1 은 Cook-Torrance 의 BRDF 모델이며, D, F, G 를 위해 어떤 알고리즘을 사용하느냐에 따라 결과가 조금씩 달라집니다. UE4 의 경우에는 D 를 위해 GGX 를, G 를 위해 Smith Approximation 을, F 를 위해 Shilick's approximation 을 사용합니다. 여러 가지 변종들에 대해서 궁금하다면, Graphic Rants 블로그의 [ Specular BRDF Reference ] 를 참조하세요.

여기에서 식을 언급하기는 했지만 굳이 이해하실 필요는 없습니다. 위에서 언급했듯이 roughness 값은 DG 에 영향을 주고, metallic 값은 F 에 영향을 준다는 것만 알고 계시면 됩니다.

Roughness 는 반사의 선명도 및 확산과 관련이 있으며, metallic 은 반사의 세기 및 각도와 관련이 있습니다.

UE4 에서 Metallic

UE4 에서의 Metallic 에 대해서 이야기해 보도록 하겠습니다. 이것은 프레넬과 관련이 있다고 했습니다. 정확하게 말하자면 F0 값입니다. 굴절률( Index Of Refraction, IOR ) 값으로부터 결정됩니다. 이에 대해서는 [ 17. Fresnel 이란 ] 에 자세히 언급했으니 기억이 안 나면 참고하세요. 앞의 링크에는 IOR 을 F0 로 변경하는 공식과 IOR 정보를 알 수 있는 사이트에 대한 링크가 있습니다.

그림6. 프레넬 공식 그래프. 출처 : Real-Time Rendering, 3rd Edition.

금속들은 수직으로 내려다 봤을 때( 즉 0 도일 때 ) 0.5 이상의 F0 값을 가지고 있으며, 보석같은 경우에는 0.2 이하의 F0 의 값을 가지고 있으며, 우리가 자연에서 볼 수 있는 많은 물체들은 0.05 이하의 값을 가지고 있습니다.

낮은 F0 값을 가질 수록 지표각에 가까워져야 반사가 제대로 보입니다. 이 F0 값이 Metallic 값으로 사용됩니다. 즉 높은 metallic 값을 가진다면 아무데서나 봐도 반사가 잘 보이고, 낮은 metallic 값을 가진다면 지표각에 가까워야 반사가 잘 보인다는 의미입니다.

이것의 활용법에 대해서는 아래에서 자세히 다루도록 하겠습니다.

UE4 의 SpecularColor

그런데 여기에서 하나 알고 넘어 가야 할 것이 있습니다. UE4 에서의 SpecularColor 의 개념입니다. 원래 SpecularColor 라는 것은 재질의 색상이 아니라 빛의 색상을 의미해야만 합니다. 하지만 완벽하게 Metallic 이 0 이거나 1 인 경우는 거의 없기 때문에 이 색상이 섞이게 됩니다. 그리고 전에 말씀드렸듯이 금속은 모든 빛을 흡수해서 방출하기 때문에 Diffuse 가 존재하지 않고 Specular 는 금속 특유의 색상이 나오게 됩니다. 그런데 SpecularColor 핀을 추가하는 것은 ( 성능 및 메모리에 ) 부담이 되므로 BaseColor 를 마치 금속 특유의 방출 색상인 것처럼 사용하게 됩니다.

이를 위해 UE4 는 다음과 같이 SpecularColor 와 DiffuseColor 를 적용합니다.

SpecularColor = lerp( 0.08 * Specular.xxx, BaseColor, Metallic.xxx ); 

공식이 어려워 보이겠지만 잘 생각해 보면 그렇게 어렵지는 않습니다. 먼저 SpecularColor 를 결정하는 공식을 보죠. lerp( x, y, z ) 는 x 와 y 값을 z 값으로 선형보간합니다. 알파블렌딩과 유사하다고 보시면 됩니다. z 가 0 이면 x 값이 1 이면 y 값이 나오는 것이죠.

만약 완전한 금속( Metallic = 1 )이라면 BaseColor 를 사용하고, 완전한 비금속( Metallic = 0 )이라면 0.08 * SpecularColor.xxx 를 사용합니다. 여기에서 xxx 라는 것은 rgb 각 채널에 한 값을 반복해서 넣겠다는 의미입니다. 즉 값이 vector 가 아니라 scalar 라는 의미죠. 저 SpecularColor 라는 것은 material node 에 존재하는 "Specular" 핀을 의미합니다.

그림7. Material Specular 핀.

어떤 분들은 여기에다가 Color 를 넣는 경우가 있는데, 핀 이름이 "Specular Color" 가 아니라 "Specular" 인 이유가 있습니다. 이 경우에는 scalar 값이므로 Color 를 넣어도 의미가 없습니다. 만약 color 를 넣게 된다면 R 채널만을 사용하게 됩니다.

그림8. 잘못된 Specular 값 설정. 이 경우에는 R 채널값이 0.839 가 사용됨.

자 이제 다시 본론으로 돌아와서 Specular 값에 0.08 이 곱해져 있으므로 이건 상당히 미세한 값을 의미합니다. Specular 를 설정하지 않으면 기본값이 0.5 이므로 실제로는 0.04 의 값이죠. 다시 말해 Metallic 이 0 이어도 specular 가 0.4 정도의 비율로 반영된다는 의미입니다.

SpecularColor 값은 다음과 같이 결정됩니다.

 Metallic

 Equation

 Result

 0

 0.08 * Specular.xxx * ( 1 - 0 ) + BaseColor.xyz * ( 0 ) 

 0.08 * Specular.xxx

 0.3

 0.08 * Specular.xxx * ( 1 - 0.3 ) + BaseColor.xyz * 0.3

 0.056 * Specular.xxx + 0.3 * BaseColor.xyz

 0.6

 0.08 * Specular.xxx * ( 1 - 0.6 ) + BaseColor.xyz * 0.6

 0.032 * Specular.xxx + 0.6 * BaseColor.xyz

 1.0

 0.08 * Specular.xxx * ( 1 - 1 ) + BaseColor.xyz * 1

 BaseColor.xyz

BaseColor 는 RGB 채널을 모두 쓰고 SpecularColor 는 scalar( 즉 회색 ) 입니다. 그래서 Metallic 이 1 에 가까워지면 SpecularColor 의 색상에 BaseColor 가 많이 묻어 나오고, 0 에 가까워지면 BaseColor 의 색상이 덜 묻어 나옵니다. BaseColor 의 색상이 덜 묻어 나온다는 것은 순수한 라이트의 색상에 가깝다는 의미죠. 대신 SpecularColor 에 0.08 이 곱해져 있으므로 specular higthlight 가 약해집니다.

그림9. Metallic 에 따른 specular color. Diffuse 를 off 시킴.

광원이 흰색이라 차이가 잘 안 드러나죠? 보라색 광원을 하나 배치해 보겠습니다.

그림10. 색상이 있는 광원을 추가했을 때의 결과. 순서는 그림 9와 같음. Diffuse 를 off 시킴.

그림10 을 보면 metallic 이 낮을수록 원래 광원의 색상이 더 반영된다는 것을 확실히 알 수 있습니다.

그런데  비금속( metallic 이 0 이 아님 )인 경우에 specular 를 올리거나 내리고 싶은 경우가 있습니다. 이럴때 바로 "Specular" 핀을 사용하는 것입니다. 그러면 그림11 과 같은 결과가 나옵니다.

그림11. Metallic = 0 일때 Specular 설정 결과 비교. Diffuse 를 off 시킴.

만약 비금속재질에서 반사에 라이트 색상을 보존하고 싶으시다면 SpecularColor 를 구하는 공식을 프로그래머에게 변경해 달라고 요청하시면 됩니다.

UE4 의 Roughness

아마 roughness 는 ( 눈으로 보기에 ) 가장 이해하기 쉬운 개념일 것입니다. 물론 내부적으로는 DG 를 위해서도 사용되기는 하지만 별로 신경을 쓸 필요는 없겠죠.

그냥 아티스트 입장에서는 "거칠면 반사가 뭉개지고 안 거칠면 반사가 또렷해진다" 정도로 이해하면 그만이겠습니다.


그림12. Metallic 이 0.5 일때 Roughness 변화에 의한 결과. Diffuse 를 off 시킴.

에너지 보존 법칙

위에서 specular G 에 대해 언급하면서 에너지 보존 법칙을 이야기했습니다. 하지만 여기에서는 Diffuse 와 Specular 의 관계에 있어서 에너지 보존 법칙을 이야기하고자 합니다.

표면에 들어 온 빛은 일부는 흡수되고, 일부는 반사되고, 일부는 투과됩니다. 이 반사되는 빛은 Diffuse 와 Specular 로 나뉜다는 것은 익히 알고들 계실 겁니다. 그런데 문제는 Diffuse 와 Specular 가 어느 비율로 반사되느냐입니다. 예전 Phong 과 같은 모델에서는 그냥 아티스트가 임의로 설정하게 했습니다. Kd 나 Ks 같은 항이 있었죠. 아티스트가 원하는 결과를 만들려고 하다 보니 과도한 라이팅이 들어 가는 경우가 많았습니다.

사실 조명에 대한 이해가 높지 않으면 적정 값을 설정하기 힘들죠. 그것도 한씬이 아니라 다양한 라이팅 환경이 존재하는 씬에서 맞추는 것은 쉽지가 않은 일입니다.

그림13. 에너지 보존 적용하지 않은 경우. 가장 왼쪽은 과도하게 빛나고 가장 오른쪽은 선명하지 않음. 출처 : Energy Conservation In Game.

그림14. 에너지 보존 법칙이 적용된 경우. 출처 : Energy Conservation In Game.

하지만 PBR 에서는 들어 온 빛의 양보다 나가는 빛의 양이 많아서는 안 됩니다. 그러므로 흡수되거나 투과되는 빛이 없다고 가정할 때 Diffuse + Specular 의 양은 항상 들어 온 빛의 양과 같아야만 하죠. 그래서 UE4 에서는 Metallic 을 가지고 Diffuse 의 양을 조절합니다.

DiffuseColor = BaseColor - BaseColor * Metallic;

Metallic 이 세지면 specular 가 세진다는 의미이고 Diffuse 의 양이 줄어들게 됩니다. 위에서 SpecularColor 를 구할 때 lerp 의 파라미터로 Metallic.xxx 를 넘기고 있기 때문에 Metallic 이 크면 Specular 가 늘어나고 Metallic 이 작으면 Diffuse 가 늘어나는 결과를 내게 되는 것입니다.

이것은 기존의 non-PBR 환경의 작업자들에게는 좀 어색하게 느껴질 수 있습니다만, 물리적으로 올바른 결과이고 라이팅 환경이 달라도 어색함이 적어집니다. 게다가 그 비율을 아티스트가 신경쓰지 않아도 되니 금상첨화입니다.

결론

Specular BRDF 공식은 매우 복잡하지만, 아티스트 입장에서는 metallic 과 roughness 만 알면 대충 재질을 설정할 수 있습니다. 그리고 그 재질들을 위한 물리적 값은 이미 정해져 있고 그것을 데이터베이스로 만드는 것이 아티스트나 팀의 역량이 되겠죠.

막말로 metallic 같은 경우에는 비금속은 0 금속은 1 이라고 설정해도 문제될 것은 없습니다. 대부분 roughness 가 중요한 factor 가 됩니다. 그러므로 특이한 경우( 매우 정교하게 섞인 복합재질 )가 아니라면 metallic 을 위해서 큰 리소스를 할당할 이유가 없습니다. 맵이 거의 단색으로 나온다고 해도 과언이 아닙니다. 만약 맵을 따로 만든다면 metallic 과 관련한 맵만 작게 만드는 것도 최적화를 위해 좋을 것입니다.

시리즈를 마무리하며...

Specular BRDF 는 [ PBR 이란 무엇인가 ] 시리즈에서 이야기하고자 하는 최종 보스라 할 수 있습니다. 이제 외전격의 이야기 몇 개만 제외하면 실질적으로 마지막 글이라고 생각하셔도 무방합니다. 이제 대단원( ? )의 막을 내리게 되겠네요. 제대로 이야기를 못 풀어 나간 것 같아서 아쉽기도 하지만, 이제 저작의 고통에서 벗어날 수 있다는 생각에 시원하기도 하네요. 이런 걸 시원섭섭하다고 하죠 ㅋ.

아티스트도 쉽게 이해할 만한 내용을 쓰고 싶었는데 많은 내용을 담으려고 욕심을 내다가 보니 밸런스를 잘 못 맞춘 것 같아서 아쉽네요. 아티스트도 만족을 못하고 프로그래머나 TA 도 만족을 못하는 그런 글이 되지 않았나하고 자평을 해 봅니다.

다음에 기회가 되면 보충글을 더 올리도록 하겠습니다. 지금까지 긴 시리즈를 읽어 주셔서 감사합니다.

추가 : [ 21. PBR 셰이더 구성 ].

참고자료

[ 1 ] Real Shading in Unreal Engine 4, Biran Karis.

[ 2 ] A Reflectance Model for Computer Graphics, Robert L. Cook and Kenneth E. Torrance.

[ 3 ] Physically-Based Shading at Disney, Brent Burley.

[ 4 ] Microfacet Models for Refraction through Rough Surfaces, Bruce Walter, Stephen R. Marschner, Hongsong Li, Kenneth E. Torrance,.


주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 19. BRDF

오늘은 BRDF 에 대해서 이야기해 보려 합니다. BRDF 는 "Bidirectional Reflectance Distribution Function" 의 머리글자입니다. 우리 말로는 "양방향 반사율 분포 함수"입니다. 이 BRDF 는 Diffuse BRDF 와 Specular BRDF 로 나뉩니다. 한번에 모든 것을 설명할 수 있는 모델이 있으면 좋겠지만, 안타깝게도 현재까지는 ( 필자가 알기로는 ) 상용화된 모델이 존재하지 않습니다.

어쨌든 BRDF 는 그림1 의 파라미터들을 사용해 식1 과 같은 형태의 함수 fr 로 정의됩니다[ 1 ] :

식1. BRDF 함수 형태. 출처 : [ 2 ].

 

그림1. BRDF 함수를 정의하는 다이어그램. 출처 : [ 2 ].

식이 나오니 뭔가 어렵게 느껴지실 수도 있지만 규칙을 알면 어려울 것이 없습니다.

식1 에서 r 이라는 아래첨자( subscrip )는 reflectance 의 머리글자입니다. 함수가 r 에 대한 함수라는 의미죠. ω( 오메가 ) 라는 파라미터( 매개변수, parameter )는 함수의 입력값을 의미하죠. 여기에서는 i 라는 아래첨자는 incident( 입사하는 ) 의 머리글자입니다. 즉 ωi 는 입사광 벡터( 광원을 향하는 벡터 )을 의미하고 ωr 은 반사광 벡터( 관찰자를 향하는 벡터 )를 의미합니다.

자, 정리해 봅시다. 함수 f 는 입사 방향과 반사 방향을 입력으로 받으면, 그 관계에 따라 반사율( 입사광과 반사광의 비율 = 반사광 / 입사광 )을 출력으로 내뱉어 준다는 것입니다.

여기에서 f 는 실제 식을 가지고 있지 않습니다. 형태만을 정의한 것이죠. 다시 말해 다음과 같은 조건을 만족하면 BRDF 라 할 수 있는 것입니다.

    • 반사율 분포( Reflectance Distribution )를 출력으로 내뱉음.
    • 양방향성( Bidirectional )을 가짐: 광원과 관찰자의 관계가 동일하다면 반사율 분포가 변하지 않음.
    • 광원과 관찰자를 입력 파라미터로 받음.
    • 함수( Function )여야 함: 같은 입력에는 항상 하나의 같은 결과가 나와야 함.

그렇다면 여러분은 위의 조건을 만족하기만 하면 구현하는 사람마다 다른 결과를 낼 수 있을 것이라는 사실을 유추하실 수 있을 겁니다. 그래서 BRDF 모델은 참 다양합니다( 그림2 참조 ).

그림2. 다양한 BRDF 모델들. 출처 : [ 1 ].

우리가 많이 들어 본 Cook-Torrance, Oren-Nayar, Phong, Blinn 등 여러 가지 BRDF 모델들이 있군요. Theroical( 이론적인 ) 은 이론적으로는 더 올바른 결과를 내는 모델들을 의미하고, Empirical( 경험적인 ) 은 덜 이론적이지만 실증된 결과를 반영한 것을 의미합니다. 마지막으로 Experimental( 실험적인 ) 은 말 그대로 실험적인 결과를 보여 줍니다. 살색은 결과가 Isotropic( 등방성 ) 이라는 것이고 녹색은 결과가 Anisotropic( 비등방성 ) 이라는 것입니다.

Diffuse BRDF

일반적으로 Diffuse BRDF 는 Lambertian reflectance( 램버트 반사율 ) 를 사용합니다. 복잡한 모델들도 있을 수 있겠지만 diffuse 모델의 경우에는 별 차이가 나지 않습니다.

램버트 반사율은 표면이 이상적인 확산 반사를 보여준다고 가정합니다. 소위 "무광( matte )" 재질을 의미합니다. 모든 방향으로 균일하게 빛을 반사하고 있다는 것이죠.

전에 [ 16. Reflection 에 대한 잘못된 상식들 ] 에서 언급했듯이 diffuse 는 표면에 흡수된 후에 다시 방출되는 것이라서 재질의 색상을 보여 준다고 했습니다.

그림6. Diffuse 의 발생과정. 출처 : [ 4 ].

그런데 이게 어떻게 튈지는 구성요소의 성분과 밀도에 따라 달라지기에 한정된 자원을 가진 현세대 컴퓨터로 이를 제대로 표현하는 것은 힘듭니다. 그래서 전방향으로 균일하게 반사한다고 가정하는 것이 바로 램버트 반사율입니다( 그런 재질을 가졌다고 가정한 상태에서의 표면을 Lambertian surface 라고 부르기도 합니다 ).

하여간 이를 그림으로 표현하면 그림7 과 같습니다.

그림7. Lambertian reflectance. 붉은색이 diffuse. 출처 : [ 4 ].

그런데 글을 차분히 읽으신 분은 여기에서 강한 의문을 표하게 될 것입니다 : "모든 방향으로 균일하게 반사한대며?".

그렇다면 그림7 은 잘못된 것일까요? 그림8 이 맞는 걸까요?

그림8. Lambertian reflectance. 전방향으로 동일하게 반사. 출처 : Optical PTFE from Lake Photonics.

제가 "안 누구누구"는 아니지만 "그림7 일수도 있고 그림8 일수도 있습니다" 라고 대답하도록 하겠습니다.

빛은 그림8 처럼 표면에서 균일하게 반사되어 나가는 것이 맞습니다만, 표면에 들어 온 조도( 빛의 양 )가 다릅니다. [ 5. 조도( illuminance ) 측정 ] 에서 빛을 받는 서피스의 기울기에 따라서 빛을 받는 양이 달라진다고 했던 것이 기억나시나요? 표면에 도달한 빛은 그림8 처럼 모든 방향으로 균일하게 방출되지만, 눈으로 볼 때는 그림7 처럼 기울기에 따라 다른 양의 빛을 받게 되는 겁니다. 램버트 모델에서는 관찰자의 위치에 따라 반사율이 달라질 수는 없지만 조도가 다르기 때문에 기울기가 커지면 점점 어두워 보이게 되는 것입니다.

그림9. 기울기와 조도의 관계. 램버트 코사인 법칙. 출처 : Lambert's Cosine Law, Ocean Optics.

그림9 에서 박스가 눈의 면적만큼의 빛덩이라고 가정합시다. 기울기가 작아지면 같은 면적이라고 할지라도 더 적은 양의 빛이 들어 오게 되는 것을 알 수 있습니다. 이  이것을 수학적으로 정리한 사람이 Lambert 이고 그 결과가 cosine 법칙과 같기 때문에, 이를 램버트 코사인 법칙( lambertian cosine law )라고 부릅니다.

빛을 향하는 벡터와 표면의 노멀을 내적(  dot product )하면 그 결과는 cosine 과 같아집니다. 왜냐하면 N 과 L 은 정규화된( normalized ) 벡터이므로 그 길이가 1 이기 때문입니다.

식2. Diffuse BRDF. 램버트 코사인 법칙.

이것이 소위 말하는 "엔닷엘"입니다. 식2NL 중간에 있는 mid dot( · ) 연산자가 dot product( 내적 )을 의미합니다. N 은 표면의 노멀( Normal ) 벡터이고 L 은 라이트( Light ) 벡터입니다.

그런데 이 시점에서 민감하신 분들은 왜 식1 의 형식과 다르냐고 지적하실 수 있습니다. 여기에서는 ωi 를 입력값으로 받지 않죠. 왜냐하면 전술했듯이, 그림8 처럼 관찰자의 위치와 관계없이 모든 방향으로 균일하게 빛을 반사하기 때문에 관찰자의 위치는 필요하지 않습니다. ωi 를 입력값으로 넣는다고 해도 아무런 변화가 없다는 것입니다. N·L 은 조도계산을 위해서 필요한 것입니다. 

에너지 보존( Energy Conservation ) 법칙

아티스트들과 연구자들은 이 Diffuse BRDF 가 뭔가 이상하다는 것을 깨닫게 됩니다( 사실 물리적으로 올바르지 않으면 자연스럽지도 않습니다. 그것이 얼마나 많이 티가 나느냐는 차이가 있을 뿐이죠. 왜냐하면 우리 눈은 실세계에서 물리적 현상들에 익숙해져있기 때문입니다. 일부러 왜곡하는 경우는 배제하고 이야기하는 것입니다 ).

뭐가 이상한지 찾아 보았더니 들어온 빛의 세기와 나가는 빛의 세기의 합을 해보니 들어온 빛보다 나가는 빛이 더 많다는 것을 알게 된 것입니다.

그림8 을 보시면 모든 방향으로 빛이 나가는 것을 알 수 있습니다. 다른 방향으로 가고 있는 빛은 관찰자에게 도달할 수 없습니다. 그런데 N·L 은 다른 방향으로 가고 있는 빛을 고려하고 있지 않습니다. 단지 빛과 표면의 노멀의 관계만을 고려한 것이죠.

그래서 나가는 빛의 양을 모두 합산한 다음에 그것으로 나눠줍니다. 예를 들어 피자 한 판을 10 조각으로 나누고 내가 한 조각을 먹었다면, 내가 먹은 비율은 1 / 10 이라고 계산하는 것과 같습니다. [ 7. Light intensity 설정 ] 에서 점광원의 광속( lumen )으로부터 광도( lux )를 계산할 때 전체 입체각의 크기인 4π 로 나눠야 정확한 광도가 나온다는 것을 기억하시나요? 그것과 유사합니다.

이걸 증명하려면 미적분이 들어가므로 여기에서 구체적으로 설명을 하지는 않겠습니다. π 로 나눠야 한다는 것만 알려드리도록 하겠습니다. 실제 유도하는 과정이 궁금하시다면 [ 5 ] 의 "Relating peak luminous intensity and luminous flux" 를 참조하시기 바랍니다.

최종 Diffuse BRDF 식은 식3 과 같이 결정됩니다. 이번에는 식1 과 같은 형태로 정리해 봤습니다.

식3. Diffuse BRDF. 에너지 보존 법칙을 고려.

그렇기 때문에 여러분은 PBR 이 적용된 엔진에서는 Diffuse 가 1/3( π = 3.141592... ) 정도 줄어드는 것을 느끼게 될 것입니다.

우리는 Diffuse 맵( 언리얼에서는 Base texture )을 알베도( albedo, RGB 채널당 표면 반사율 )의 개념으로 사용합니다. 알베도는 절대값인 색상이 아니라 비율입니다. 색상이라기보다는 데이터라는 의미죠. 그러므로 PBR 환경에서는 다른 파라미터를 통해서 밝기를 조정하시는 것이 좋습니다( 예를 들면 광원의 밝기 ).

참고자료

[ 1 ] An Overview of BRDF Models, Rosana Montes and Carlos Urena.

[ 2 ] Bidirectional reflectance distribution function, Wikipedia.

[ 3 ] Lambertian reflectance, Wikipedia.

[ 4 ] Diffuse reflection, Wikipedia.

[ 5 ] Lambert's cosine law, Wikipedia.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 18. Distribution Function

그래픽스에 익숙하신 분들이라면 BSDF, BRDF, BTDF 와 같은 용어들을 한 번쯤은 보셨을 겁니다. 뭔진 잘 모르겠지만 DF 라는 머릿글자가 동일하다는 것을 알 수 있습니다. 제목에서 이야기하고 있는 "Distribution Function" 의 머리글자가 바로 "DF" 입니다. "Distribution Function" 은 우리말로는 "분포 함수" 정도로 표현할 수 있습니다.

우리는 여러 3D 저작 도구들에서 BRDF 라는 용어를 볼 수 있습니다.

그림1. 3DS Max 의 BRDF 롤아웃.

그림2. Maya 의 Specular 패널.

그림3. V-RAY for Maya 의 Reflection 패널.

그림4. Anorld for Maya 의 Specular 패널. 여기에서는 "Microfacet Distribution" 이라고 되어 있는데 이것도 BRDF 입니다.

명식적으로 BRDF 라는 용어를 사용하지 않더라도 BRDF 관련 파라미터들을 사용하는 경우가 많습니다. 여러분에게 익숙한 "Glossiness" 라든가 "Specular Power" 같은 용어들을 보셨을 겁니다. 보통 그것은 "Phong" 혹은 "Blinn Phong" 을 위한 BRDF 파라미터죠.

딱히 BRDF 에 대해서 알지 못한다고 하더라도 여러 가지 쉐이딩 모델을 비교하는 글들을 본 적이 있었을 겁니다( 그림5 참조 ).

그림5. BRDF 비교. 출처 : Experimental Analysis of BRDF Models.

이런 쉐이딩 모델들의 차이는 어디에서 발생하는 것일까요? "답정너" 같지만 바로 분포 함수( Distribution Function )의 차이입니다.

함수란?

함수라는 것은 무엇입니까? 그것은 입력이 들어 오면 출력을 내뱉어 주는 기계상자로 비유할 수 있습니다.

그림6. 함수를 기계에 비유함. 출처 : [ 2 ].

그림6 에서 볼 수 있듯이 "x" 라는 입력을 넣을 때 "f(x)" 라는 출력을 줍니다. "f" 는 "function" 의 머리글자입니다. 이때 x 의 값이 될 수 있는 값들의 집합을 정의역이라 하고, f(x) 의 값이 될 수 있는 값들의 집합을 치역이라고 합니다.

그런데 여기에서 제약이 있습니다. 반드시 x 와 f(x) 의 값은 1:1 로 대응해야만 한다는 것입니다. 만약 1:1 로 대응하지 않으면 어떤 일이 발생할까요? 여러분이 쿠킹머신에 재료 "A" 를 넣었는데 음식이 "B" 일 수도 있고 "C" 일 수도 있습니다. 이것을 의도한 것이 아니라고 한다면, 이러한 기계를 신뢰할 수 있을까요?

그래서 x 와 f(x) 의 값은 반드시 1:1 로 대응해야 수학적으로 올바른 함수라고 할 수 있습니다. 이 때 이런 f(x) 값들만 모아 놓은 것을 공역이라고 합니다. 그러므로 공역은 치역의 부분집합이죠( 그림 7 참조 ).

그림7. 정의역, 치역, 공역의 관계. X( 붉은색 ) 는 정의역, Y( 파란색 ) 는 치역, 노란색은 공역.

자 이제 "분포 함수" 에서 함수의 의미를 아시겠죠? 특정 입력에 대해서 특정 결과를 내 주는 것이 바로 함수입니다.

함수 f 가 있고 그것은 "f(x) = x + 1" 라고 정의되었다고 합시다. 그러면 반드시 "f(1) = 2" 여야합니다. "f(1) = 3" 일 수도 있고 "f(1) = -1" 일 수도 있으면 안 되겠죠?

그런데 세상에 안 되는 것이 어디있겠습니까? 음함수( Implicit Function ) 이라는 개념이 있습니다. 대표적인 음함수는 원이죠.

식1. 원을 위한 음함수.

이것을 그래프로 그리면 어떻게 될까요?

그림8. 원의 그래프.

식1 을 보시면 알겠지만 하나의 x 값에 두 개의 y 값이 대응됩니다. 그래서 이를 함수로 만들 수가 없죠. 그러므로 이것을 두 개의 함수( explicit function )로 나눠서 그리게 됩니다( 원을 하나의 함수로 그리는 방법이 있긴 합니다. 바로 매개변수를 도입하는 방법인데요, 이것에 대해서는 나중에 기회가 되면 설명하도록 하겠습니다 ).

어쨌든 중요한 것은 어떤 식의 입력값과 출력값이 반드시 1:1 로 대응해야만 그 식을 함수라고 부를 수 있다는 것입니다.

분포란?

"분포"라는 것은 무엇일까요? 확률이나 통계에서 많이 나오죠? 분포는 어떤 요소들이 일정한 범위에 퍼져 있는 모양을 의미합니다. 이것을 함수로 나타내면 분포함수가 되겠죠.

그림9. 정규분포 그래프. 출처 [ 3 ].

그림10. 주사위 두개를 던질 때의 두 눈의 합 S 에 대한 확률분포. 출처 : [ 3 ].

분포라는 것은 어렵게 생각할 필요가 없습니다. 그냥 어떤 패턴이라고 생각하시면 됩니다. 사실 그래픽스에서의 분포는 해석학 영역에 속하기 때문에 조금 다른 의미를 가지고 있지만, 그냥 "분포는 패턴" 이라고 이해하시는 것이 좋습니다( 여기에서 디랙델타함수[ 4 ]를 다룸으로써 미적분과 양자론에 대해 이야기하고 싶지는 않군요 ㅠㅠ ).

그래픽스에서 분포는 그림11 과 같이 로브( lobe )로 표현되는 경우가 많습니다. 로브라는 것은 어떤 물체의 둥글거나 평평한 부분을 일컽는 말입니다. 쉐이더의 차이점이 궁금해서 검색을 해 본 경험이 있는 분들은 그림11 과 같은 그림을 보신 적이 있을 겁니다.

그림11. 여러 reflection lobe 들에 대한 표현. 출처 : Explain the shape of a specular lobe

위의 그림을 어떤 식으로 이해해야 하는지 알아 볼까요? 그림12 에는 붉은색으로 A, B, C 가 있습니다. 이것은 관찰자의 위치를 나타내는 것이죠. 일단 다른 것은 놔두고 "Standard Phong specular lobe" 에 대해서만 알아봅시다( 녹색 로브 ). 원점을 O 라 할 때 OA, OB, OC 가 녹색로브와 만나게 될때까지의 길이가 바로 specular 의 세기를 의미합니다. OA 와 OB 를 비교해 보면 녹색로브와 만날 때까지의 길이는 OB 쪽이 더 길다는 것을 알 수 있습니다. 이는 관찰자가 A 에 있을 때보다 B 에 있을 때 specular 를 더 세게 받는다는 것을 의미하죠. OC 같은 경우에는 녹색 로브와 만나지를 않는군요. 결국 specular 세기는 0 이라는 의미입니다.

그림12. Lobe 와 관찰자 A, B, C 의 관계.

여러분은 specular lobe 의 모양만 보고도 specular 가 뾰족하게 보일지 퍼져 보일지를 알 수 있습니다.

컴퓨터 그래픽스와 PBR 의 선구자인 Disney 같은 경우에는 툴까지 만들어서 BRDF 를 연구하더군요. BRDF Explorer 라는 툴이 있습니다. 링크에 가면 받을 수 있습니다. 그림13 처럼 2D 와 3D 에서 로브를 확인하거나 할 수가 있습니다. 실제로 BRDF 모델을 만들 수도 있습니다.

어떤 쉐이더를 만들기 전에는 BRDF Explorer 를 통해서 아티스트와 그 결과를 미리 확인해 보는 것도 좋겠죠.

그림13. Disney BRDF Explorer 스크린샷. 출처 : BRDF Explorer.

BRDF 와 BTDF

예전에 [ 6. 휘도 측정 ] 에서 BRDF, BTDF 그림을 보여 준 적이 있습니다.

<p

그림14. BRDF 와 BTDF. 출처 : [ 1 ]

반사되서 나가는 빛의 분포를 다루는 것이 RDF( Reflectance Distribution Function, 반사율 분포 함수 ) 이고 투과되서 나가는 빛의 분포를 다루는 것이 TDF( Transmittance Distribution Function, 투과율 분포 함수 ) 입니다.

쉽게 이야기하면 표면에 들어 온 빛이 얼마만큼 반사되었고 얼마만큼 투과되었느냐를 함수로 나타낸 것이죠. 물론 반사는 diffuse 와 specular 가 존재하기 때문에 Diffuse RDF 와 Specular RDF 로 나뉩니다.

자 우리가 자주 접하는 분산함수들은 앞에 "B" 가 붙었죠? 이것은 "Bidirectional" 의 머리글자입니다. 이게 무슨 말이냐? 그림15 처럼 빛과 관찰자의 위치가 변경되어도 관계만 같으면 결과( 반사율 혹은 투과율 )가 동일하다는 것입니다. 반사로 치면 입사각과 반사각이 같으면 어디에 있어도 반드시 같은 결과가 나온다는 의미입니다.

그림15. Bidirectional 의 의미. 입사각과 반사각의 관계가 동일하면 항상 동일한 결과가 나옴.

그런데 왜 bidirectional 이 필요할까요? 여기에 대해서는 명확하게 정리된 글이 없더군요. 그냥 제 생각을 말씀드리도록 하겠습니다.

컴퓨터 그래픽스에서는 성능( 혹은 속도 )을 상당히 중요한 요소로 보고 있습니다. 특히나 실시간 그래픽스라면 그것의 중요도는 말할 필요도 없겠죠. 만약 관찰자와 광원의 관계에 의해 일정한 결과를 도출할 수 없다면, 매우 복잡한 공식이 필요할 겁니다. 예를 들어 그림16처럼 서피스에 방향성이 있는 결이 있다고 하죠.

그림16. 서피스의 방향성 있는 미세한 결.

그림16 와 같은 서피스를 고려한다면 그림15 와 같은 결과를 기대할 수 있을까요? 사용자가 원하는 결과를 얻을 수는 있겠지만 재질이나 기하학적 위치에 따라 공식이 틀려져야 할 것입니다. 아티스트가 이런 것을 모두 관리하기도 힘들 뿐더러 공식이 복잡해지면서 성능도 저하되겠죠.

물론 PBR 에서는 눈에 거의 보이지 않는 미세면( microfacet )이라는 것을 고려하기는 하지만 그림16 처럼 특정 방향성으로 쏠려 있는 미세면이 아닙니다. 일정한 분포를 가지고 있는 미세면들입니다. 그것을 "Microfacet Model" 이라고 부릅니다. 이것에 대해서는 나중에 다루도록 하겠습니다.

어쨌든 일정한 분포를 가진 미세면들을 고려하면 빛과 관찰자의 관계에 의한 반사율은 일관된 방식으로 정의됩니다. 즉 bidirectional 한 성격을 띄게 되며, 하나의 재질에 대해 빛과 관찰자의 관계에 따른 여러 가지 공식을 가지고 있을 필요가 없겠죠.

P.S. "그렇다면 BRDF 로 방향성을 가진 결을 만들 수는 없나요?" 라는 질문을 하실 수 있습니다. 안 되는 게 어디 있겠습니까? NormalMap 등을 사용해서 Normal 을 왜곡시킴으로써 결을 만들어낼 수 있습니다. 하지만 이것은 관찰자와 빛의 관계에 의해 일관된 결과가 나온다는 대전제를 깨는 것은 아닙니다.

참고자료

[ 1 ] Bidirectional scattering distribution function, Wikipedia.

[ 2 ] 함수, 위키백과.

[ 3 ] 확률분포, 위키백과.

[ 4 ] 분포 (해석학), 위키백과.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] Fresnel 이란?

프레넬 공식이란?

앞서 [ [ 번역 ] 모든 것은 프레넬을 가집니다 ] 와 [ Reflection 에 대한 잘못된 상식들 ] 에서 프레넬( Fresnel )이라는 용어가 자주 나옵니다. 대체 이게 무엇이길래 PBR 에서는 그토록 중요한 것일까요?

모든 빛은 매질( media )을 만나면 반사, 흡수, 굴절이라는 과정을 거치게 됩니다. 이때 프레넬 공식을 사용해서 빛의 움직임을 계산하게 됩니다.

"프레넬"이라는 것은 "오귀스탱 장 프레넬" 이라는 프랑스 과학자의 이름을 의미합니다( 그림1 ).

그림1. Auguistin-Jean Fresnel. 출처 : [ 2 ].

이 프레넬이라는 사람은 서로 다른 굴절률( refractive index )를 가진 매질( media ) 사이에서 빛이 움직일 때의 동작을 설명했습니다. 빛의 반사를 예측하는 공식을 만들었고 이를 프레넬 반사라고 합니다[ 1 ]. 그러므로 일반적으로 "프레넬" 이라고 이야기하면 "프레넬 공식( Fresnel Equation )" 을 말하는 것입니다.

인간과 빛 ] 에서 빛은 전자기파( electromagnetic wave )라고 이야기한 것이 기억나실 겁니다. 여러 가지 전자기파로 구성된 집합이 빛이죠. 빛이 프리즘을 통과하면서 여러 가지 파장으로 분리되는 것을 기억하고 계실 겁니다( 그림2 ).

그림2. 빛이 프리즘을 통과하면 여러 파장으로 분리됩니다. 출처 : [ 3 ].

이런 일은 왜 벌어지는 것일까요? 지금부터 알아 보도록 하겠습니다.

굴절률( Refractive index )

굴절률은 빛이 진공에서 특정 매질( media )로 이동할 때 속도가 얼마나 느려지는지 그 비율을 측정한 것입니다. 일반적으로 과학 문서에서는 "Index of refraction( IOR )" 이라는 표현이 많이 사용됩니다. "Refractive index" 와 "Index of refraction" 은 같은 의미입니다. "index" 는 사전적 의미로 "지수" 라는 뜻을 가집니다. "물가지수", "임금지수" 이런 표현을 할 때 사용하죠. 즉 우리 말로 억지로 번역하자면 "굴절지수" 정도가 되겠습니다. 그냥 굴절률이라고 생각하시면 됩니다.

빛의 속도는 초당 지구 일곱바퀴 반을 돌 수 있는 매우 빠른 속도( 299,792,458 m/s )입니다. 지구에서 달까지 1 초면 갈 수 있죠. 그런데 이것은 진공( vaccum ) 기준에서의 속도이며, 실제로는 어떤 매질을 만났을 때 속도가 감소합니다. 왜 감소하는지에 대해서는 설명하지 않겠습니다. 왜냐하면 이를 설명하기 위해서는 글이 좀 어려워질 수 있고 이 문서의 주제를 벗어나기 때문입니다. 에너지 보존 법칙과도 관계가 있는데요, 만약 궁금하시면 위상 속도( phase velocity ) 문서를 참고하시기 바랍니다.

어쨌든 매질을 만나면 빛의 속도가 줄기 때문에 빛의 방향도 바뀝니다. 이를 좀 쉽게 설명하려면 바퀴의 예를 들 수 있습니다( 그림3 )( 빛에 대해서 이해하고 싶으신 분들은 뉴턴 하이라이트의 "빛이란 무엇인가" 라는 책을 필독하실 것을 권장합니다. ).

그림3. 속도가 다르면 빛이 꺾이는 이유. 출처 : [ 5 ].

그림3 에서 볼수 있듯이 포장도로에서 모래로 바퀴가 진입하면 마찰력때문에 한쪽바퀴의 속도가 줄어들죠. 그런데 다른쪽 바퀴는 여전히 같은 속도로 움직이므로 몸체의 방향이 틀어집니다. 그런데 만약 바퀴가 작다면 더 많이 회전해야 하므로 그 동안 느린쪽 바퀴의 방향은 더 틀어지겠죠. 반대로 바퀴가 크다면 더 적게 회전하므로 다른쪽 바퀴가 덜 틀어지겠죠.

바퀴의 크기는 주파수와 연관해서 생각할 수 있습니다. 그림2 를 다시 보죠( 스크롤이 귀찮으니 밑에 이미지를 복사해 넣었습니다 ).  

파장이 긴( 바퀴가 큰 ) 붉은 빛은 덜 꺾이고, 파장이 짧은( 바퀴가 짧은 ) 보라색 빛은 많이 꺾이는게 보이시죠? 굴절률이 제대로 계산되기 위해서는 파장별로 처리되어야 합니다. 하지만 대기 산란( atmospheric scattering )처럼 파장별 산란 결과가 중요한 분야가 아니라면 그냥 대충 퉁쳐서 처리하곤 합니다.

스넬의 법칙( Snell's law )

과거에 사람들은 매질이 다르면 빛이 꺾인다는 것 까지는 알게 되었지만 얼마나 꺾이는 지까지는 모르고 있었습니다. 이것을 공식화 한 사람이 바로 스넬( Snell )입니다. "스멜~" 이 아니라 "스넬" 입니다. 이 스넬의 법칙은 고등학교 때도 배워서 들어는 보셨을 겁니다.

그림4. 서로 다른 굴절률을 가진 매질에서의 빛의 굴절. 출처 : [ 6 ].

그림 4에서 붉은색 라인은 빛의 경로를 의미합니다. 매질의 경계( interface ) 에서 빛이 굴절합니다. 표면의 노멀( normal )과 입사광( incident light )의 각은 θ1 입니다. 그리고 노멀과 굴절광( refracted light )의 각은 θ2 입니다. v 는 속도( velocity )를 의미하고, λ 는 파장( wavelength )를 의미합니다. 그리고 n 은 굴절률( IOR )을 의미하죠. 이것들의 관계를 설명한 것이 바로 스넬의 법칙입니다( 식1 ).

식1. 스넬의 법칙. 출처 : [ 6 ].

이런 현상 때문에 기름과 물을 컵에 채워놓고 파동을 만들면 그림5 와 같은 결과가 나오게 됩니다.

그림5. 스넬 법칙에 따른 파동의 변화. 출처 : [ 6 ].

그런데 이 굴절과 관련해서 좀 재밌는 현상이 있습니다. 빛이 굴절률이 다른 매질을 만나게 되면 특정 각도에서는 굴절을 하지 않고 완전히 반사를 하는 경우가 있다는 겁니다( 그림7 ).

그림7. 빛의 굴절 패턴. 특정 각도에서는 전반사가 발생함( 오른쪽 ). 출처 : [ 7 ].

위의 그림에서 Critical angle 이라고 된 각도를 넘어서면 전반사가 발생합니다. 임계각을 구하는 공식은 식2 와 같습니다.

식2. 전반사각 구하는 공식. 출처 : [ 7 ].

아크릴 병 내부에서 바깥쪽으로 빛이 전반사되는 예를 들면, 대기의 굴절률이 1.0 이고 아크릴의 굴절률이 약 1.50 이므로 전반사 각도는 41.8 도입니다.

식3. 아크릴 병의 전반사각 계산. 출처 : [ 7 ]

프레넬 공식( Fresnel equation )

자 이제 우리는 어떤 매질에서 여행하고 있던 빛이 다른 매질을 만나게 되면 반사하거나 굴절하게 된다는 것을 알게되었습니다. 물론 흡수될 수도 있지만 여기에서는 다루지 않겠습니다.

우리가 그래픽스에서 반사와 굴절을 계산하기 위해서는 얼마만큼의 빛이 반사되고 얼마만큼의 빛이 굴절되는지 알아야 합니다. 그것을 알려주는 공식이 바로 프레넬 공식입니다.

프레넬 공식을 그래프로 나타내면 다음과 같은 결과가 나옵니다.

그림8. 프레넬 공식 그래프. 출처 : Real-Time Rendering, 3rd Edition.

그림이 좀 어려워 보이죠? 가로축이 눈과 노멀방향의 각도이고 세로축이 반사율입니다.보시면 알겠지만 물이나 풀과 같은 비금속 물질들은 수직으로 봤을 때( 0 도 ) 매우 낮은 반사율을 보이며, 수평으로 봤을 때( 90 도 ) 매우 높은 반사율을 보입니다. 비금속같은 금속같은 경우에는 어디에서 보든 0.5 이상의 반사율을 보여 주죠.

그런데 우리가 모든 각도에서의 굴절률( IOR )을 알 수는 없습니다. 그러므로 대충 근사계산을 하는 식( 일반적으로 Shilick's approximation, 식4 )을 사용합니다. 그리고 입력값으로 물체를 수직에서 바라본( 0 도 ) 반사율값을 넣는 근사 계산식을 사용합니다. 위의 "프레넬 공식 자세히 보기" 를 펼쳐 본 사람들을 위해서 설명을 드리자면, R0 값이 바로 그림8 에 있는 그래프에서 0 도의 반사율 값이라 생각하시면 됩니다. 대부분의 엔진이나 문서에서는 F0 라고 표현을 합니다( 아마도 "Fresnel at Degree 0" 의 약자겠죠 ).

만약 정확한 값을 넣고자 한다면, 모든 매질의 굴절률 값을 수집한 다음에 계산을 하시면 됩니다. 일반적으로는 관찰자가 대기 속에 있다고 가정하기 때문에 어떤 매질의 굴절률이 n 이라고 할 때 다음과 같이 계산됩니다.

식5. F0 계산.

물의 예를 들어 보죠. 물의 경우에는 1.33 의 굴절률을 가지고 있습니다. 이를 식5 에 넣어 보면 F0 는 식6 과 같이 계산됩니다.

식6. 물의 F0 계산.

각 매질의 굴절률( IOR )은 [ IOR LIST ] 라는 페이지에 정리되어 있습니다. PDF 로 정리된 것도 있습니다[ IOR_Table.pdf ].

일반적으로 이 F0 를 "Metallic" 핀에다가 넣어 주시면 됩니다.

UE4 의 프레넬 노드

프레넬 공식은 림라이트나 실루엣을 만들기 위한 공식이 아닙니다. 하지만 그런 효과를 원하시는 분들을 위해서 Fresnel 노드가 따로 존재하기는 합니다[ 10 ].

그림9. 프레넬 노드. 출처 : [ 10 ].

하지만 이것을 사용하는 것에 대한 책임은 본인이 지셔야 합니다. 왜냐하면 Metalic 으로서 반영되는 Fresnel 은 그 의미가 명확하지만, 이 노드를 사용하는 것은 그냥 효과이기 때문입니다. 이 노드를 사용하게 된다면 비물리적인 결과를 산출할 수 있습니다. 보통 이 노드를 사용할 때는 Metalic 을 제거하고 Emissive 를 사용합니다.

그림10. UE4 프레넬 노드의 사용. 출처 : [ 10 ].

참고자료

[ 1 ] Fresnel equation, Wikipedia.

[ 2 ] Auguistin-Jean Fresnel, Wikipedia.

[ 3 ] Light, Wikipedia.

[ 4 ] Refracitve index, Wikipedia.

[ 5 ] 빛이란 무엇인가? 10 page, Newton Highlight. 일본 뉴턴프레스.

[ 6 ] Snell's law, Wikipedia.

[ 7 ] Refraction, Wikipedia.

[ 8 ] Schlick's approximation, Wikipedia.

[ 9 ] Real Shading in Unreal Engine 4.

[ 10 ] 머티리얼에 프레넬 사용하기, UE4 Document.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 16. Reflection 에 대한 잘못된 상식들

사전적 의미

우리는 일상적으로 diffuse reflection( 확산방사 ) 과 specular reflection( 정반사 ) 이라는 용어를 사용합니다. 그런데 정말로 그 의미를 알고 사용하고 계시나요?

일단 diffuse 의 사전적인 의미를 살펴 보도록 하겠습니다.

1. ( 빛, 열, 냄새 따위를 ) 발산[ 방산( 放散 ) ]하다.

2. ( 지식을 ) 넓히다, 보급시키다, ( 정서 따위를 ) 충만시키다.

3. [ 理 ] ( 기체나 액체를 ) 확산( 擴散 )시키자; [ 理 ] ( 빛을 ) 산란시키다.

출처 : 네이버 사전.

여러분이 알고 있는 뜻과 일치하나요?

이제 specular 의 사전적 의미도 살펴 보도록 하겠습니다.

1. 거울 같은, 비추는, 반사하는, 반영하는

2. ( 광학 ) 정( 正 )반사성의

출처 : 네이버 사전.

이것도 여러분이 알고 있는 뜻과 일치하나요?

이제 저런 사전적인 의미가 실제적인 의미와 얼마나 일치하는지 살펴 보도록 합시다.

Diffuse 반사는 표면의 거칠기 때문에 발생한다?

많은 분들이 diffuse reflection 이 표면의 거칠기 때문에 발생한다고 생각합니다. 특히 PBR 에 있어 중요한 요소인 미세면( microfacet )을 생각하면 그렇게 생각하는 것도 당연합니다. 하지만 diffuse 는 대부분 표면의 거칠기 때문에 발생하는 것이 아닙니다. 물론 일부는 그렇게 발생합니다.

사전적인 의미로 봤을 때 diffuse 는 "발산", "확산" 이라는 의미를 가지고 있습니다. 즉, 단순하게 표면에 부딪혀서 반사되어 나오는 요소가 아니라는 의미입니다.

[ 1 ] 에 의하면, diffuse 가 발생하는 원리는 다음과 같습니다. 글의 일부를 번역해 보았습니다.

Solids( 인공물 )에서  diffuse reflection 은 일반적으로 표면의 거칠기 때문에 발생하지 않습니다. 물론 평평한 표면에서 specular reflection 이 발생하지만, 그렇다고 해서 그것이 diffuse reflection 이 발생하는 것을 막지는 않습니다. 하얀 대리석을 매우 연마( polishing )해도 하얀색은 남습니다; 아무리 연마를 해도 그것이 거울이 되지는 않습니다. 연마는 약간의 specular reflection 을 산출하지만, 나머지 빛은 여전히 확산되게 반사됩니다.

어떤 표면이 diffuse reflection 을 제공하는 가장 주요한 원리에서, 그것은 정확하게는 표면이라는 개념을 포함하고 있지 않습니다: 대부분의 빛은 아래 그림에서 보이는 것처럼 표면 아래 존재하는 scattering center( 산란 센터, 역주 : 전자기파가 산란되는 곳 )들의 영향을 받습니다.

물론 매우 일부이기는 하지만 산란없이 diffuse reflection 을 보여 주는 경우는 존재합니다. 아래 그림처럼 표면 아래로 빛이 흡수되지는 않았는데 그 표면이 매우 거칠어서 여러 반향으로 반사가 되었다면 그것도 현상적으로 봤을 때는 diffuse 라고 이야기할 수 있겠죠.

비균일 표면으로부터의 diffuse reflection. 출처 : [ 1 ].

굳이 이러한 원리에 대해서 이야기하는 이유는 무엇이라 생각하시나요? "쓰는 사람 입장에서 그러든지 말든지 상관없잖아요?" 라고 하시는 분들 계실 수도 있습니다.

하지만 이 이야기를 하는 이유는 albedo( 반사율 ) 에 대해서 이야기하기 위함입니다. 우리가 흰색 빛을 물체에 쐈을 때 사과는 붉은색으로 보이고( 물론 녹색 사과도 있지만 딴지는 걸지 말아 주세요 ㅠㅠ ), 나뭇잎은 녹색으로 보입니다. 보통 이에 대해서 설명할 때 붉은색을 반사했다고 표현하는데, 사실은 표면 아래도 들어가 산란이 일어나면서 일부 파장을 흡수하고 나머지 파장이 방출된 것입니다.

자! 그럼 그냥 표면에서 반사해 버린 빛과 표면 아래에서 산란시켜서 반사해 버린 빛의 차이가 보이나요? Specular reflection 은 반사되었을 때 자신의 빛의 파장을 그대로 유지하지만, diffuse reflection 은 재질의 구성에 따라서 반사되었을 때 자신의 빛의 파장을 유지하지 못합니다. 그러므로 specular reflection 은 빛의 색을 그대로 유지하고 diffuse reflection 은 빛의 색을 유지하지 못하는 것입니다.

일반적인 경우에 표면 아래에서의 산란을 계산하기에는 너무 복잡하고 계산비용이 비쌉니다. 그래서 이를 albedo 라는 개념으로 퉁치는 거죠. 

그런데 여기에서 한가지 의문이 들 수 있습니다. 왜 specular 도 albedo 의 영향을 받느냐는 겁니다. 실제로 UE4 같은 엔진을 사용해 보면 Yellow( = Red + Green ) 라이트를 Green 재질에다가 쐈을 때 specular 성분에 순수한 Green 색상이 포함됩니다. 그냥 순수한 Yellow 가 나와야할 것 같은데 말이죠... 그 이유는 위의 위키피디아 글에서도 언급되어 있듯이 평평한 면이라고 하더라도 diffuse 를 막을 수 없기 때문입니다. 세상에는 순수하게( 혹은 이상적으로 ) 매끈한 평면이란 존재하지 않습니다. 이 부분은 Fresnel 과 관련이 있는데 나중에 자세히 다루도록 하겠습니다.

모든 물체는 diffuse reflection 을 가진다?

그렇지 않습니다. 금속( metal ), 빛이 들어갈 수 없는 물질, 개스( gas ), 액체( liquid ), 유리( glass ), 투명 플래스틱( transparent plastic ), 일부 보석( gem )들이나 소금 결정( salt crystal )과 같은 단결정( single crystal ) 물질들, 그리고 티슈( tissue )나 수정체( lens of a eye ) 같은 매우 특별한 재질들은 diffuse reflection 을 가지지 않습니다[ 1 ].

사실 이러한 재질들에 대해서 모두 설명하는 것은 어렵기 때문에 우리가 가장 흔하게 접하게 되는 금속에 대해서만 설명을 드리도록 하겠습니다.

금속은 모든 빛을 흡수합니다. 즉 albedo 는 0 이라고 할수 있습니다. 그런데 어떻게 반사가 생기는 걸까요? 금속 내부의 자유전자는 에너지를 받으면 아래 그림처럼 방출됩니다. 그래서 금속은 자신을 구성하고 있는 원자에 따라서 고유의 색상을 가지게 되는 거죠.

금속의 반사의 본질.

그러면 금속은 어느 방향으로 반사를 시킬까요? 여기에서 구체적으로 언급하지는 않겠지만 그것은 Fresnel 과 관련이 있습니다. 나중에 자세하게 다루도록 하겠습니다. 

Specular reflection 은 입사각과 반사각이 같을 때 가장 세다?

우리는 일반적으로 거울면 반사, 즉 정반사는 입사각과 반사각이 같을때 가장 세다고 알고 있습니다. 하지만 그것은 사실이 아닙니다. 이는 표면의 roughness 에 따라 달라집니다. 이 역시 Fresnel 과 관련이 있습니다. 이 역시 나중에 자세하게 다루도록 하겠습니다.

어쨌든 일반적인 재질에서 specular 는 거울면 반사를 하지 않고 약간 벗어나서 반사를 합니다. 이를 off-specular reflection 이라 부릅니다. 가장 센 곳을 off-specular peak 라고 부르죠. 굳이 우리말로 번역하자면 "정반사를 벗어난 반사" 정도 되겠습니다.

Off-specular reflection 의 예: 지표각에 가까워질수록 specular 방향( M )이 정반사의 각과 달라짐. 출처 : [ 2 ].

참고자료

[ 1 ] Diffuse reflection, Wikipedia.

[ 2 ] A Reflectance Model for Computer Graphics, Robert L. Cook and Kenneth E. Torrance.

주의 : 이상한 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.

주의 : 번역이 개판이므로 이상하면 원문을 확인하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

원문 : Everything has Fresnel

이번에는 지난 시간에 이어 specular 현상이 왜 발생하는지에 대해서 다루는 John Hable 의 글을 번역해 보았습니다. 쉐이더 코드가 일부 들어 가 있지만 같이 나오는 다이어그램을 보시면 이해하기가 크게 어렵지는 않을 것입니다.


[ PBR 이란 무엇인가 ] 15. [ 번역 ] 모든 것은 프레넬을 가집니다

이 포스트는 "모든 것은 빛납니다" 라는 포스트의 2탄이라고 생각하셔도 됩니다. 표준 specular 라이팅이 게임에서 매우 자주 사용되지만, 우리가 게임에서 거의 보기 힘든 효과는 바로 프레넬( fresnel )입니다.

여러분은 이제 specular 가 무엇인지 알고 있습니다. 비디오 게임에서 가장 일반적인 specular 모델은 Blinn-Phong 이며 다음과 같이 정의됩니다.

 H = normalize( V + L )
 specVal = pow( saturate( dot( H, N ) ), power );

이 경우 V 는 뷰 벡터이며, L 은 라이트 벡터입니다. 그리고 N 은 노멀 벡터이고, power 는 specular 요소입니다. H 는 유도된 하프 벡터이며, 이 벡터는 뷰 벡터와 라이트 벡터의 절반을 의미합니다.

이것은 어떻게 동작하는 것일까요? 여기 다이어그램이 있습니다.

여러분은 뷰, 라이트, 노멀 벡터를 볼 수 있습니다. 자, 이 함수를 사용하면, specular value peak( specular 값이 가장 큰 부분 ) 는 어디에 생길까요? 직관적으로 볼 때, 여러분은 뷰 벡터가 라이트 벡터에 대한 반사 벡터일 때 specular 함수가 최대이기를 원할 겁니다. 그러면 무슨 일이 벌어질까요? 이 함수는 하프 벡터가 노멀에 정확하게 정렬되었을 때 최대값이 되는데, 이는 뷰 벡터가 라이트 벡터에 대한 정확한 ( 거울같은 ) 반사 벡터일 때 발생합니다.

여기에 다른 경우가 있습니다:

역시 뷰 벡터는 라이트 벡터로 반사됩니다. 이 경우에 specular highlight 가 더 밝을까요, 아니면 더 흐릿할까요, 아니면 첫 번째 경우랑 같을까요? 글쎄요, 그것은 같습니다( 역주 : 계산 결과로만 보자면 같다는 의미 ). 왜냐하면 여러분은 두 경우에 모두 specular highlight 의 최대 값을 보고 있는 것입니다. 이것이 실세계에서는 어떻게 동작을 하는 것일까요? 짧은 답은 NO 입니다.

여기에 벽돌 그림이 있는데, 서로 다른 카메라 각도에서 촬영한 것입니다. 위의 이미지에서 빛과 카메라는 모두 아래쪽을 향하며, 이것은 첫 번째 경우를 표현합니다. 두 번째 줄에서는, 빛이 지표각( grazing angle )에서 비추고 있으며, 이는 두 번째 경우를 표현합니다. 필자는 specular 와 diffuse 를 편광필터로 분리했으며, 그래서 왼쪽에 있는 것은 diffuse 이며, 오른쪽에 있는 것은 specular 입니다. 벽돌을 체크해 보죠.

어쩌라고!!! 빌어먹을 벽돌처럼 단순한 재질에 대해서도 specular 에 대한 Blinn-Phong 모델은 완전 잘못된 결과를 냅니다. 그리고 이러한 일이 발생한 이유는 프레넬이라 불리는 자명한 것 때문입니다.

다른 두 가지 경우의 specular 를 살펴 보도록 합시다. Blinn-Phong 에 의하면, 그것들은 동일한 세기를 가지지만, 현실에서는 지표각에 가까울수록 훨씬 밝아집니다( 역주 : 필자가 무슨 의도로 그림을 더 첨부했는지 모르겠지만 첨에 나왔던 그림과 동일합니다. 차이가 뭔지 알아 보려고 노력하실 필요는 없습니다. 그냥 스크롤 하지 말라고 그랬나 봅니다 ).

 

이 효과를 다루려면, 여러분은 프레넬을 사용할 수 있습니다. 프레넬을 근사계산하는 매우 좋은 실시간 근사계산은 바로 Schlick Fresnel 입니다. From the GPU Gem 3 chapter on skin:

 float base = 1 - dot( V, H );
 float exponential = pow( base, 5.0 );
 float fresnel = exponential + F0 * ( 1.0 - exponential );
 specVal *= fresnel;

왠지는 모르겠지만 대부분의 사람들은 물, 유리, 금속과 같이 정말 밝게 빛나는 표면에서만 프레넬이 나오기를 원하는 경향이 있습니다. 하지만 실제로는 프레넬은 거의 모든 재질에 존재하는 강한 효과입니다. 사실 필자는 프레넬은 덜 빛나는 재질에서 가시적으로 더욱 중요한 역할을 한다고 주장하고 싶습니다. 여기 PVC 파이프의 일부가 있습니다.

분명히, PVC 는 프레넬을 가집니다. 그러나 필자의 관점에서는 프레넬이 PC 보다는 벽돌에서 더 가시적으로 중요한 효과를 가진다고 이야기하고 싶습니다. 아무 것도 없는 데서 강한 specular 가 나오는 것이 높은 specular 를 더 높게 만들어 주는 것 보다는 더 중요합니다. 그게 더 중요한 효과가 아닐까요? 필자에게 있어, 물, 유리, 금속을 위해서만 프레넬을 고려하는 것은 잘못된 것이라고 봅니다. 왜냐하면 그것은 덜 빛나는 표면에서 엄청난 가시적 차이를 만들기 때문입니다. 여기에 몇 가지 예제가 더 있습니다.

싸구려 판지. 매우 오해를 받고 있습니다. 그것은 항상 "순수 diffuse 재질"로서 참조되고 있습니다. 심지어는 그것이 실제로는 그것의 빛나는 친구들과 어울려 다닐 자격이 있음에도 불구하고 말이죠. Specuar 는 직각에서 중요합니다. 왜냐하면 그것이 미묘한 채도 감소( subtle desaturation )를 추가하기 때문입니다. 하지만 판지는 지표각에서 매우 밝은 specular 반사를 보여 줍니다.

여러분이 아침에 일하러 가기 위해 운전을 할 때 왜 더 밝은지 생각해 본 적이 있으신가요? 대부분의 사람들은 태양이 자신들의 눈에 들어 오고 있기 때문이라고 생각합니다. 사실 그 밝음의 주요 원인은 포장도로가 매우 강한 프레넬을 가지고 있기 때문입니다. 다음에 운전할 때 태양이 눈에 들어 오면, 사이드 미러를 확인해 보십시오. 그러면 사이드 미러에 보이는 포장도로가 당신의 전면에 있는 포장도로보다 얼마나 어두운지 알 수 있을 것입니다.

여기에 어떤 천이 있습니다. Ikea 에서 가지고 온 수건입니다. 거친 면재질 천은 여러분이 집 주변에서 볼 수 있는 일반적인 재질보다 더 적은 specular 를 가집니다. 이러한 비교는 썩 좋지는 않은데, 두 번째 이미지가 전체적으로 더 밝기 때문입니다. 그래서 specular 에서 diffuse 로 상대적으로 변환하는 것을 보기가 힘듭니다. 만약 더 좋은 예를 원하신다면, 그것은 독자의 경험으로 남겨 두겠습니다.

그리고 재미로 X-Rite 컬러 체커를 확인해 봅시다. 컬러 체커를 사용할 때, 여러분은 카메라로부터 수직으로 그것을 배치하는 것이 좋습니다. 왜 그렇게 해야 하는지 저에게 물어볼 필요가 없어졌으면 좋겠군요.

프레넬 만세!

주의 : 잘못된 내용이 있을 수 있으므로 이상하면 참고자료를 확인하세요.

주의 : 번역이 개판이므로 이상하면 원문을 확인하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

원문 : Everything is Shiny, Jonh Hable.

지난 시간까지는 조도( illuminance )에 대한 내용들을 중점적으로 다뤘지만, 이번 시간부터는 휘도( luminance )에 대한 내용을 중점적으로 다루게 됩니다. 

PBR 라이팅 모델에서 휘도계산을 하는데 있어서 기존의 라이팅 모델들과 다른 점은 여러 가지가 있지만, 아티스트들의 입장에서 가장 크게 느껴지는 부분은 diffuse 와 specular 가 계산되는 방식일 겁니다. 예전에는 diffuse 와 specular 의 세기를 아티스트가 직접 설정해야만 했습니다. 물론 완벽하게 이해하고 사용하는 것은 아니지만 대충 값을 조정하다가 보면 원하는 결과가 나오곤 했습니다.

그런데 PBR 로 오면서 metalicity( 금속성 ) 와 roughness( 거칠기 ) 라는 항을 통해 diffuse 와 specular 성분을 조정하게 됩니다. 물리에 기반한 개념이므로 아티스트가 처음에 이해하기는 어렵습니다. 하지만 그 값들은 매우 명확한 물리적 의미를 가지고 있기 때문에 전체적인 통일성을 높일 수 있으며, 값들을 ( 라이팅 종류에 따라 ) 건별로 조정할 필요가 없기 때문에 작업 생산성이 증가하게 됩니다.

그러므로 PBR 이 휘도를 계산하는 데 있어 배경으로 깔고 있는 개념들에 대해서 적절히 이해하는 것이 올바른 재질을 설정하는 데 있어 도움이 될 것 이라 생각합니다. 보통 PBR 을 처음 접하시는 분들이 diffuse map 에 그린대로 결과가 나오지 않는다는 이야기를 많이 하시는데, 이것은 diffuse 와 specular 가 어떤 식으로 반영되고 있는지를 이해하지 못하고 있기 때문에 나올 수 밖에 없는 질문이며, 매우 당연한 질문입니다.

휘도를 다루는 데 있어 반사의 성질 및 구성요소를 이해하는 것은 매우 중요합니다. 그런데 첨부터 에너지 보존법칙이니 metalicity 니 roughness 니 하는 것들을 이야기하는 것은 잘 와닿지도 않고 어려울 수 있습니다. 그래서 이러한 개념에 대해서 쉽게 설명하고 있는 John Hable 의 글을 두 개 번역하기로 했습니다. 오늘은 첫 번째 주제인 "Everything is Shiny" 입니다.


[ PBR 이란 무엇인가 ] 14. [ 번역 ]모든 것은 빛납니다

가끔씩 필자는 초심자용 온라인 문서나 논문에서 specular 에 대해서 언급하는 것을 보게 됩니다. 그리고 "옷이나 판지( cardboard )와 같은 일부 재질들은 스펙큘러를 가지지 않는 순수한 diffuse surface 들입니다" 라는 줄을 보게 됩니다. 이는 거짓말입니다. 실세계에 존재하는 모든 물체는 specular 를 가지고 있습니다. 심지어는 매우 오래된 옷이나 판지라도 specular 를 가집니다. 이것을 집에서 만든 편광 설정을 통해서 이를 확인했습니다. 편광 필터를 수작업으로 만들고 있었기 때문에, 여기에서 보여주는 구분이 완벽하지는 않습니다만, 충분히 잘 동작하는 것으로 보입니다.

먼저, 면직물 셔츠로 시작할 것입니다. 이는 필자가 구할 수 있는 가장 diffuse 한 것입니다. 거의 대부분의 면직물 셔츠들은 더 많은 specular 를 가지고 있습니다.

 Main:

 

 Diffuse:

 

 Specular:

 

이제 어떤 데님( 역주 : 청바니 만들 때 쓰는 푸른색 질긴 면직면. 출처 : 네이버 사전 )을 살펴 봅시다. 좀 더 빛나는 옷 재질입니다.

 Main:

 

 Diffuse:

 

 Specular:

 

다음으로 어떤 판지를 살펴 봅시다. 엡! 그것은 빛납니다.

 Main:

 

 Diffuse:

 

 Specular:

 

비교를 위해서, 여기에 내 팔레트중 하나를 가지고 왔습니다. Specular highlight 가 매우 밝습니다.

 Main:

 

 Diffuse:

 

 Specular:

 

여기에 몇 가지 다른 것들이 있습니다. 벽돌이 얼마나 많은 specular 를 가지고 있는지를 확인해 보세요.

 Main:

 

 Diffuse:

 

 Specular

 

마지막으로 보도에 깔린 콘크리트 조각이 있습니다. 보도의 콘크리트는 포장도로보다는 덜 빛납니다.

 Main :

 

 Diffuse:

 

 Specular:

 

 

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 참조하세요.


[ PRB 이란 무엇인가 ] 13. UE4 GI : Lightmass & Mobility

개요

UE4 에서는 공식적으로는 Dynamic GI 를 지원하지 않습니다. LightPropagationVolume( LPV ) 이 있기는 하지만, 아직도 experimental 로 분류됩니다. 그러므로 여기에서는 다루지 않도록 하겠습니다. 그리고 이 문서는 Mobility 의 차이를 설명하는 데 중점을 두고 작성되었으므로 Lightmass 사용법이나 구현에 대해서는 다루지 않겠습니다.

UE4 를 처음 접하는 분들이 가장 헷갈려하는 개념이 Mobility 입니다; Static, Stationary, Movable.

기본적으로 Mobility 라는 것은 개체가 게임 실행중에 움직이냐 그렇지 않느냐를 의미합니다. 그렇다면 솔직히 Static 과 Dynamic 만 존재해도 됩니다. 하지만 UE4 는 굳이 Stationary 와 Movable 이라는 개념을 추가했습니다. 이렇게 구분한 이유는, 각 Mobility 마다 GI 처리 방식이 다르기 때문입니다.

그림1. UE4 Mobility.

[ Global Illumination & Indirect Lighting ] 에서는 GI 에서는 빛을 크게 direct lighting( 직접광 ) 과 Indirect lighting( 간접광 )으로 나눈다고 했습니다. 단순하게 표현하면 표면에 닿은 빛이 바로 눈에 들어 오면 direct lighting 이고, 그것이 다른 곳에 반사해서 눈에 들어 오면 indirect lighting 입니다( 눈으로 바로 들어 오는 빛도 direct lighting 이라 할 수 있겠죠. 사실 scattering 을 거쳐서 들어 오기는 하지만 여기에서는 무시하도록 하겠습니다 ).

그림2. Direct lighting( 붉은색 ) 과 Indirect lighting( 녹색 ).

자! 본론으로 돌아와, 이제 각 Mobility 설정에서 GI 가 어떤 식으로 처리되는지 알아 보도록 합시다.

씬 구성

아무것도 배치되지 않은 씬에다가 바닥( Static )과 6 개의 박스( 3 개는 Static, 3 개는 Stationary, 3 개는 Movable ), 그리고 3 개의 라이트( R 은 Movable, G 는 Stationary, B 는 Static )를 배치합니다. 그리고 그 주변에 "Lightmass Importance Volume" 을 적절히 설정해 줍니다. 최종 품질을 반영하기 위해서 Production 으로 빌드합니다. 오브젝트의 재질은 모두 color=white, metalic=0.2, roughness=0.5 로 설정했습니다.

그림3. 씬구성. 바닥과 왼쪽 열은 static, 중간 열은 stationary, 오른쪽 열은 movable. 붉은색 광원은 movable, 녹색 광원은 stationary, 파란색 광원은 static.

Object Moblity

여기에서 먼저 확인해 볼 것은 오브젝트의 mobility 입니다. 이를 명확히 확인하기 위해서는 라이트맵을 살펴 보는 것이 좋습니다. 뷰포트에서 "Optimiztion Viewmodes >> Lightmap Density" 를 선택하시면 라이트맵 밀도를 볼 수가 있습니다.

그림4. 라이트맵 밀도.

그림4 를 통해 여러분이 알 수 있는 것은 오브젝트가 static 이 아니라면 라이트맵을 가지지 않는다는 것입니다. 이게 무슨 말인가 하면 stationary/movable 오브젝트는 indirect lighting 성분을 indirect lighting cache 에서 가지고 온다는 것입니다.

확인을 위해서 뷰포트에서 "Lighting Features >> Indirect Lighting Cache" 를 off 합니다.

그림5. Indirect Lighting Cacahe 메뉴.

그러면 그림6 과 같이 stationary/movable 오브젝트에서 indirect 성분이 배제되는 것을 확인할 수 있습니다.

그림6. Indirect Lighting Cache 를 off 하면 Stationary/Movable 오브젝트의 Indirect 성분이 없어짐.

Light Mobility

이제 라이트의 mobiltiy 를 살펴 보도록 하겠습니다. 일단 다시 Indirect Lighting Cache 를 on 합니다.

Static Light

Static 라이트는 Direct Lighting, Direct Shadowing, Indirect Lighting 성분을 모두 Lightmap 과 Indirect Lighting Cache 에 저장합니다.

뷰포트에서 "Lighting Components" 항목으로 간 다음 서브메뉴에서 "Dynamic Shadows", "Glboal Illumination" 을 모두 off 합니다.

그림7. Dynamic Shadows 와 Global Illumination 을 off.

그러면 그림8 처럼 Direct lighting 성분만 남습니다.

그림8. Direct Lighting 만 남겨 둠.

여기서 특이한 점을 발견하실 수 있습니다. Static 오브젝트에 Static 라이트는 반영되지 않고 그림자는 반영된다는 것입니다. 즉 Static 오브젝트의 그림자는 Direct 성분이라는 거죠.

그럼 이제는 반대로 "Glboal Illumination" 을 on 하고 "Direct Lighting" 을 off 합니다. 그러면 그림9 처럼 Indirect Lighting 성분만 남습니다.

그림9. Indirect Lighting 만 남겨 둠.

여기에서 알 수 있는 사실은 무엇입니까? Static 라이트의 direct/indirect lighting 성분은 모두 indirect lighting 으로 취급된다는 것입니다.

UE4 에서 이렇게 처리하는 이유는 무엇일까요? Lightmass 를 빌드하고 게임에 들어 가면 게임에서는 Static 라이트가 생성되지 않습니다. 그러므로 Static 라이트에 의한 direct 및 indirect 성분을 모두 indirect 로 취급하는 거죠. 이를 direct 와 indirect 로 구분하기 위해서는 라이트맵이 두 장씩 필요하고 direct lighting cache 같은 걸 만들어야겠죠. 개념적으로는 올바르지만 최적화 관점에서는 쓸데없는 짓입니다.

그래서 "LIGHTING NEEDS TO BE REBUILT" 라는 것이 나오면 성능이 저하됩니다.

왜냐! Lightmass 에서 Static 라이트와 Static 오브젝트가 빌드되기 전에는 Shadow 를 실시간 계산하고 Indirect 성분을 Indirect Lighting Cache 에서 가지고 오기 때문입니다.

Stationary Light

Stationary Light 는 Indirect Lighting 성분은 Lightmap 맵과 Indirect Lighting Cache 에 저장하고 Direct Shadowing 성분은 ShadowMap 에 저장하고 Direct Lighting 성분은 실시간에 계산합니다. 여기서 헷갈리지 말아야 할 것은, 대상 오브젝트가 static 이 아니라면( 라이트맵을 가지지 않는다면 ) direct shadowing 은 실시간에 계산된다는 것입니다.

Static 과 결정적인 차이는 Direct Lighting 성분을 실시간에 계산한다는 점인데, 이 때문에 specular reflection 처리가 가능합니다.

그림10. Specular reflection. R 은 Movable, G 는 Stationary, B 는 Static.

그림10 을 보면 Static 라이트에 대한 specular reflection 이 생기지 않는다는 것을 알 수 있습니다. 왜냐하면 diffuse 같이 뷰에 독립적인( view independent ) 성분은 어디에서 봐도 동일한 결과를 내기 때문에 미리 계산하는 것이 가능하지만, specular 와 같이 뷰에 종속적인( view dependent ) 성분들은 보는 위치에 따라 결과가 달라지기 때문에 미리 계산할 수가 없습니다.( 그림11 참조 ).

그림11. Diffuse 분산과 Specular 분산. Diffuse 는 모든 방향으로 동일하게 분산되지만, Specular 는 방향성을 가집니다.

물론 밸브( Valve )의 RNM( Radiosity Normal Map ) 라이트맵처럼 세 개의 기저벡터를 사용해서 라이트맵을 구우면 specular 를 표현할 수 있기는 하지만[2], 기저벡터마다 라이트맵을 만들어야 하므로 용량의 압박때문에 잘 사용하지는 않습니다. 

Movable Light

Movable 라이트는 Direct lighting 성분만을 가집니다. 실시간 GI 알고리즘을 사용하지 않는다면 Indirect 성분은 없습니다. Light Propagation Volume 을 사용한다면 라이트의 "Dynamic Indirect Lighting" 속성을 on 시켜 indirect 성분을 처리할 수 있습니다.

Movable 라이트는 GI 처리를 하지 않기 때문에 품질이 떨어진다는 단점을 가지고 있기는 하지만, 라이트를 움직일 수 있다는 장점이 있으므로 제한적으로 사용됩니다.

결론

지금까지 언급했던 것들을 정리하면 다음과 같습니다. 물론 HQ 라이트맵에서의 조건입니다. LQ 에서는 모든 것을 라이트맵에 넣습니다. "Indirect Lighting Cache" 는 "ILC" 라는 머리글자로 표기하도록 하겠습니다.

 

 Static Light

 Stationary Light 

 Movable Light

 Static Object

 Direct Lighting : Ligthmap.

 Direct Shadowing : ShadowMap.

 Indirect Lighting : Lightmap.

 Direct Lighting : Realtime.

 Direct Shadowing : ShadowMap.

 Indirect Lighting : Lightmap.

 Direct Lighitng : Realtime.

 Direct Shadowing : Realtime.

 Indirect Lighting : None.

 Staionary Object

 Direct Lighting : ILC.

 Direct Shadowing : None.

 Indirect Lighting : ILC.

 Direct Lighting : Realtime.

 Direct Shadowing : Realtime.

 Indirect Lighting : ILC.

 Direct Lighitng : Realtime.

 Direct Shadowing : Realtime.

 Indirect Lighting : None.

 Movable Object

 Direct Lighting : ILC.

 Direct Shadowing : None.

 Indirect Lighting : ILC.

 Direct Lighting : Realtime.

 Direct Shadowing : Realtime.

 Indirect Lighting : ILC.

 Direct Lighitng : Realtime.

 Direct Shadowing : Realtime.

 Indirect Lighting : None.

참고자료

[1] 간접광 캐시, 언리얼 문서.

[2] Half-Life(R) 2 / Valve Source(TM) Shading, GDC2004.

 

주의 : 잘못된 내용이 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 12. UE4 GI : Reflection Capture

기본 개념

오늘은 UE4 에서 가장 흔하게 사용되는 IBL 요소인 Reflection Capture 에 대해서 알아 보도록 하겠습니다.

아티스트들은 일반적으로 "반사( reflection )" 를 "정반사( specular reflection )" 라고 받아들입니다. 하지만 이것은 잘못된 것입니다. 반사는 난반사( diffuse reflection )와 정반사( specular reflection )으로 나뉩니다.

하지만 UE4 에서의 reflection capture 에서의 reflection 은 indirect specular reflection 을 의미합니다. 사실 indirect diffuse refleciton 도 반영해야 정확한 결과가 나오겠지만 UE4 에서는 specular 성분만을 반영합니다. 그렇게 하는 이유는 diffuse 성분까지 반영하기에는 메모리 부하와 성능 부하가 너무 커지기 때문인 것으로 보입니다.

UE4 의 reflection capture 는 지역적인 결과를 반영하고 있습니다. 즉 주변에 어떤 라이트와 메쉬가 배치되어 있느냐에 따라 결과가 달라집니다. 그러므로 매우 많은 reflection capture 를 사용해야만 아티스트가 원하는 결과에 근접한 결과가 나옵니다. 그래서 diffuse 성분까지 반영하기에는 메모리 측면이나 성능측면에서 부담이 될 수 있습니다. 

리플렉션 캡쳐는 indirect 성분을 저장한다고 했습니다. 그러므로 라이트매스를 빌드해야 제대로 된 결과가 나온다는 것을 잊지 마십시오.

Cubemap Array

이 섹션은 약간 기술적인 내용을 담고 있습니다. 이해를 못하셔도 사용하는 데는 지장이 없습니다.

하나의 씬에서는 총 341 개까지의 리플렉션 캡쳐를 렌더링할 수 있으며, 각 리플렉션 캡쳐의 큐브맵의 한 면의 해상도는 128 X 128 입니다. 리플렉션 캡쳐의 렌더링 개수가 341 개로 제한된 이유는 렌더링을 위해 큐브맵의 면을 D3D11 의 Texture Cubemap Array 를 사용하기 때문입니다. 일종의 texture pool 이라 생각하시면 됩니다. 저장은 개별 리플렉션 캡쳐의 큐브맵에다가 하지만 렌더링은 texture array 를 통해 하는거죠.

그림1. 리플렉션 캡쳐의 각 큐브맵의 면은 텍스쳐 배열에 올라갑니다.

D3D11 의 texture array 의 최대 요소 개수는 2048 개입니다. 그런데 큐브맵은 면을 6 개를 가지게 되죠. 그러면 341 X 6 = 2046 이기 때문에 341 개가 최대 캡쳐 개수가 되는 겁니다. 그냥 여러분은 그냥 "하드웨어 제약이다" 정도로 이해하시면 될 것 같습니다.

그런데 왜 UE4 는 번거롭게 하나의 texture array 에다가 큐브맵의 면들을 올리는 것일까요?

사실 ShaderModel 5( SM5 ) 아래 환경에서는 texture array 를 사용하지는 않습니다. 이 글을 보고 계신 분들은 적어도 SM5 이상을 사용한다고 가정하고 작성된 글입니다. SM5 에서는 Tiled-Deferred-Imaged-Based_Reflection 이라는 기법을 사용하는데, ComputeShader 를 사용하게 됩니다. 이때 texture array 를 넘겨서 빠르게 cubemap 들에 접근하게 됩니다. 리플렉션 캡쳐의 개수가 동적이기 때문에 쉐이더에 파라미터로 일일이 넘기는 것은 어렵습니다. 그러므로 cubemap texture array 의 index 로 각 리플렉션 캡쳐를 식별하게 되는 것이죠.

이 개념을 매우 단순하게 설명하면 아래 그림과 같습니다.

그림2. Tiled deferred imaged based refleciton 을 단순화함. 

먼저 씬의 렌더링 정보를 캡쳐합니다. 그리고 나서 씬을 여러 개의 타일 그룹( 기본값은 8 X 8 그룹 )으로 분할합니다. 그렇다면 각 타일에는 "width / 8height / 8" 개의 픽셀이 있겠죠. 각 픽셀의 중심 위치를 구하고 각각의 reflection capture 들과의 포함관계를 계산합니다. 그리고 나서 해당 reflection capture 의 데이터를 texture array 로부터 읽어 옵니다. 만약 cubemap texture 에 두 개의 요소를 넣었다면, 파란색 영역은 array index 0 이고 보라색 영역은 array index 1 이라고 할 수 있겠죠. 녹색은 겹치는 영역을 의미합니다.

자세한 내용을 언급하지는 않았지만 대충 개념은 이해하실 수 있을거라 생각합니다. 분석을 원하는 프로그래머들을 위해 첨언하자면, TReflectionEnvironmentTiledDeferredCS 템플릿을 참조하시기 바랍니다.

UE4 에는 두 종류의 reflection capture 가 있어서 사람을 혼란스럽게 합니다. 그것은 "Box Reflection Capture" 와 "Sphere Reflection Capture" 인데요, 이름이 말해 주듯이 리플렉션 캡쳐 바운딩의 모양을 의미합니다. 그 이외에는 큰 차이는 없다고 보시면 됩니다.

Reflection Capture 블렌딩

"Default" 레벨 템플릿으로부터 씬을 하나 생성해 크롬 바닥을 배치해 보도록 하죠.

좀 더 넓은 영역을 확보하기 위해 바닥 메쉬의 XY 스케일을 10배로 만듭니다. 그리고 지난 시간에 만들었던 크롬 재질을 반영합니다. 머티리얼을 바닥에 드래그&드랍하시면 됩니다. 크롬재질은 basecoor = white, metalic = 1, roughness = 0 을 설정한 것을 의미합니다. 혼란을 방지하기 위해서 일단 ScreenSpaceReflection 은 끕니다; Viepwort 의 "Show >> Lighting Features >> Screen Space Reflection" 을 off 시킵니다.

그러면 여러분은 그림3 과 같은 놀라운 결과를 확인하게 됩니다.

그림3. 아무런 설정없이 크롬 바닥을 배치했을 경우의 결과.

그림3 에서 완전히 검은색이 나오는 것은 metalic 이 1 인 경우에는 diffuse 가 0 이 되기 때문입니다. 금속은 모든 빛을 흡수하고 방출하기 때문인데, 이에 대해서는 다음 시리즈에서 설명하도록 하겠습니다.

여기에 Box Reflection Capture 를 배치해 봅시다. 와우!!! 뭔가 반사가 나옵니다.

그림4. BoxReflectionCapture 배치.

그런데 그림4 에 보면 바운딩 박스가 두 개 나옵니다. 1 번은 전체 바운딩 박스를 의미하고 2 번은 블렌딩 영역의 바운딩 박스를 의미합니다. 2 번을 조정하려면 "Reflection apture" 카테고리의 "Box Transition Distance" 를 조정하시면 됩니다.

그림5. "Box Transition Distance" 속성.

이것을 0500 으로 설정해 차이를 확실하게 확인해 봅시다.

그림6. "Box Transition Distance" 가 0 일때( 상 )와 500 일때( 하 )의 차이.

 

이것만 봐서는 잘 구분이 안 가시죠? 이 리플렉션 캡쳐의 "Box Transition Distance" 가 0 인 것과 500 인 것 두 개를 배치해서 겹쳐봅시다. 그 결과가 그림7 에 나와 있습니다.

그림7. 두 개의 리플렉션 캡쳐를 블렌딩. 오른쪽이 0 왼쪽이 500.

0 인 것의 리플렉션 캡쳐가 위쪽에 나오는 것을 볼 수 있습니다. 그러면 0 이던 것을 700 으로 바꿔볼까요?

그림8. 두 개의 리플렉션 캡쳐를 블렌딩. 오른쪽이 700 왼쪽이 500.

그림8 을 보면 "Box Transition Distance" 가 높은 것이 밑에 깔리는 것을 볼 수 있습니다. 그러면 "Box Transition Distance" 의 값이 Order 를 설정하는 것일까요?

질문을 하면 언제나 그렇듯이... 답은 "NO" 입니다.

그림8 에 배치된 것 중에서 오른쪽의 스케일 X 를 400 으로 바꿔봅시다.

그림9. 두 개의 리플렉션 캡쳐를 블렌딩. 오른쪽이 BoxTranstionDistance = 700, ScaleX = 400. 왼쪽이 각각 500, 1000.

그림9 의 결과를 보면서 뭔가 감을 잡은 분들이 계실 겁니다. 박스의 부피와 BoxTransitionDistance 의 관계는 반비례합니다. 이러한 것을 잘 고려해서 리플렉션 캡쳐의 우선순위를 결정할 필요가 있습니다.

Sphere Reflection Capture 같은 경우에는 일반적으로 Scale 을 사용하지 않습니다. 대신에 "Influence Radius" 속성을 사용합니다.

그림10. Sphere Reflection Capture 의 "Influence Radius" 속성.

Scale 이 동일하다면 "Influence Radius" 값이 낮은 것이 위에 나온다고 보시면 됩니다.

그림11. "Influence Radius" 에 따른 우선순위. 오른쪽이 1000, 왼쪽이 1001.

이런 결과를 볼 때 UE4 가 의도하는 것은 명백합니다. 볼륨이 작을수록 그리고 블렌딩 팩터가 작을 수록 더 메인으로 렌더링되게 하겠다는 것입니다.

한계 및 대안

자 이제는 구형 리플렉션 캡쳐를 하나 배치하고 그 영역 안에서 바닥 위에 박스 메쉬를 하나 올려보도록 하겠습니다. 그런데 결과가 안 나옵니다.

그림12. 구형 리플렉션 영역 안에 박스 메쉬 배치했지만 결과가 반영이 안 됨.

여기에서 "저는 나오는데요?" 하시는 분들은 Screen Space Reflection 안 끄신 분들입니다.

본론으로 돌아가서... 왜 안 나오는 걸까요? 대부분의 IBL 씬 캡쳐들은 주변 환경이 바뀌었을 때 캡쳐를 갱신해 줘야 합니다. 리플렉션 캡쳐의 TM 을 변경하면 자동으로 캡쳐가 갱신되지만 그렇지 않고 외부 요인을 바꿨을 때는 반드시 "Update Captures" 를 해 줘야 합니다.

그림13. "Update Captures" 버튼.

하지만 그림14 처럼 별로 좋은 결과가 나오지는 않을 겁니다.

그림14. "Update Captures" 결과.

그러면 그림14 의 결과가 매우 잘못된 걸까요? 이 리플렉션 캡쳐라는 것은 사용할만한 물건이 아닐까요?

여기에서는 리플렉션 캡쳐를 바라보는 관점을 전환시킬 필요가 있습니다. IBL 은 Planar reflection capture 와는 다르게 사용자가 오브젝트를 바라 봤을 때 반대쪽 결과를 보는데 특화된 것입니다.

그림15. 리플렉션 캡쳐의 결과가 그나마 올바르게 나오기 위한 조건.

사실 Parallax Correction 이라는 알고리즘[1]을 사용해서 이를 개선하는 것은 가능합니다. 하지만 UE4 에서는 비용이 비싸서 그런지 다른 이유때문인지 이를 구현하지는 않았습니다.

이를 보정해 주는 것이 "Screen Space Reflection( SSR )" 입니다. 아까 껐던 SSR 을 다시 켜 봅시다.

그림16. Screen Space Reflection 과 Reflection Capture 의 조합. 

물론 이것도 한계가 있습니다. 왜냐하면 ScreenSpace 기법들은 화면을 벗어난 것에 대한 처리를 할 수 없기 때문에 그림16 에서 보듯이 뷰 방향에 따라 다른 결과가 나오기 때문입니다. 하지만 이 샘플에서처럼 극단적으로 반사를 하는 경우는 많지 않기 때문에 큰 문제는 되지 않습니다.

하지만 샘플처럼 바닥이 거의 평평한데 거울과 비슷하게 반사한다면 어떻게 해야 할까요? 이때는 "Planar Reflection"[2] 을 사용할 수 있습니다.

Indirect Specular Reflection

위에서도 언급했듯이 리플렉션 캡쳐는 간접광( indirect lighting )을 다루기 때문에 반드시 lightmass 를 빌드해야 합니다. 이제 포인트라이트 하나를 배치하고 "Update Captures" 를 해 보도록 하겠습니다. 그러면 그림17 과 같은 결과를 볼 수 있습니다. 이것은 옳은 결과인가요?

그림17. Direct 성분만 반영된 캡쳐 결과.

그렇지 않습니다. Point light 에 대한 indirect 성분이 전혀 반영되지 않았기 때문에 박스 바닥이 검게 나오는 것을 알 수 있습니다. Lightmass 빌드를 하면 그림18 과 같은 결과를 얻을 수 있습니다.

그림18. Indirect 성분까지 반영된 캡쳐 결과.

참고자료

[1] Image-based Lighting approaches and parallax-corrected cubemap, Sebastien Lagarde.

[2] 플레이너 리플렉션, UE4 Document.

주의 : 잘못된 내용이 있을 수 있으므로 이상하면 참고자료를 참조하세요.


[ PBR 이란 무엇인가 ] 11. UE4 GI : Sky Light

UE4 IBL 의 종류

일단 이미지 소스를 광원으로 사용한다면 그것은 IBL 이라 할 수 있습니다. UE4 에서의 IBL 은 Sky Light, Reflection Environment( Box Reflection Capture, Spehre Reflection Capture ), Ambient Cubemap( Post Process Volume ) 등이 있습니다. 오늘은 Sky Light 에 대해서 다뤄 보도록 하겠습니다.

주의 : 여기에서는 Stationary 환경을 중심으로 설명하도록 하겠습니다.

먼저 각 light 요소들의 영향력을 평가하기 위해 사용할 옵션들에 대해서 설명드리도록 하겠습니다.

Viewport 의 "Show" 풀다운 메뉴에는 "All Show Flags" 라는 섹션이 있습니다. 거기에 있는 "Light Types" 메뉴와 "Lighting Components" 메뉴를 사용해서 기능을 on/off 하면서 결과를 살펴 볼 것입니다.

그림1. "Light Types" 옵션과 "Lighting Components" 옵션.

Sky Light 란

아웃도어 환경을 고려하는 개발자라면 가장 먼저 배치하는 것이 direcitonal light, sky sphere( atmostpheric sky ) 같은 요소일 것입니다.

Sky sphere 같은 경우에는 directional light( 일반적으로 태양 ) 에 의한 Rayleigh scattering 과 Mie scattering 을 처리합니다. 이것을 IBL 소스로 쓴다면 매우 좋겠죠. 하지만 보통 그런 개체를 구현할 때 IBL 을 고려하고 만들지는 않습니다.

그래서 Sky sphere 를 IBL 로서 사용할 수 있는 방법이 필요합니다. 이를 도와 주는 액터가 바로 Sky Light 액터입니다. Mode 툴바에 보면 "Lights" 카테고리에 "Sky Light" 액터가 있습니다. 이를 씬에 배치하면 됩니다. 이때 액터의 위치는 대충 설정해도 됩니다. 그 이유는 뒤쪽에서 설명하도록 하겠습니다.

SkyLight 를 배치했을 때와 그렇지 않았을 때의 차이는 매우 큽니다. "Light Types >> Sky Lighting" 을 껐다가 켜 보면 그 차이를 볼 수 있습니다. 그림자가 진 영역에 대해서 "Sky Light" 성분이 반영되는 것을 알 수 있습니다.

 

 그림2. 이미지 슬라이더가 보이는 경우에는 왼쪽이 SkyLight 없을 때이고 오른쪽이 SkyLight 있을 때임. 이미지 슬라이더가 안 보이는 경우에는 위쪽이 SkyLight 있을 때이고 아래쪽이 SkyLight 없을 때임.

Sky Occlusion

그런데 SkyLight 를 배치할 때 한 가지 주의할 점이 있습니다. SkyLight 의 차폐 성분은 Lightmass 빌드시에 SkyOcclusion 이라는 아틀라스 텍스쳐에 포함되므로 Lightmass 를 빌드하기 전까지는 차폐 성분이 반영되지 않습니다.

그림3. Lightmass 의 SkyOcclusion.

그러므로 Lightmass 빌드 전에 박스를 옮겨 보면 그림4 처럼 차폐 영역에 SkyLight 가 그대로 뭍어 나오는 것을 알 수 있습니다.

그림4. Lightmass 빌드 전에는 SkyLight 에 대한 차폐가 발생하지 않음.

하지만 Lightmass 를 빌드하면 그림5 처럼 차폐된 영역에 SkyLight 가 들어 오지 않습니다.

그림5. Lightmass 빌드 후에는 SkyLight 에 대한 차폐가 발생함. 주의 : Preview 빌드에서는 샘플 개수의 부족으로 차폐가 제대로 반영되지 않을 수도 있습니다.

UE4 에서 SkyOcclusion 은 벤트노멀( Bent-Normal )과 입체각( Solid-Angle )을 사용해서 계산됩니다. 입체각이 뭔지 기억이 안 나시는 분은 [ 3. 빛의 감쇠 ] 를 참조하세요. 벤트노멀이라는 것은 어떤 벡터들의 평균벡터를 의미합니다.

그림6. Bent Normal. 출처 : How could I use bent normal map.

그림6 에서 보이듯이 서피스의 어떤 점으로부터 반구내에서 사방으로 레이를 쏘면 다른 서피스와 충돌하지 않고 나아가는 레이들이 있습니다. 그러한 레이들의 벡터들을 모두 더해서 평균을 내면 BentNormal 이라는 것이 나옵니다. 그리고 BentNormal 을 중심으로 얼마나 열려있는지를 구할 수 있고 그것을 입체각 단위로 저장합니다.

그러면 그림7 에서와 같이 어떤 점에서 하늘에 대한 차폐 정도를 알 수 있죠. 그러면 BentNormal 은 specular reflection 과 diffuse reflection 을 위해 이미지를 샘플링하기 위한 중심벡터가 되고, 입체각은 차폐 정도를 판단할 수 있는 기준이 되죠.

그림7. 여러 지점에서 BentNormal 과 SolidAngle 을 구함. 붉은색, 녹색, 보라색 순으로 차폐 정도가 덜함을 알 수 있음.

SolidAngle 을 알게 되면 반구의 면적이 pi 이므로 SolidAngle / 2pi 를 하면 [0, 1] 범위의 값이 나오며, 그것이 SkyVisibility 가 되는 것입니다 .SkyOcclusion 아틀라스 텍스쳐의 rgb 채널에는 BentNormal 이 a 에는 1 - SkyVisibility 가 들어 갑니다( 사실 실제 Lightmass 구현에서는 일일이 SolidAngle 을 구하지는 않고, 차폐된 ray 의 개수를 사용해 occlusion 을 구합니다. 여기에서는 설명의 목적으로 SolidAngle 을 사용했으나 개념상으로는 큰 차이가 없습니다. 정확도의 차이는 있겠지만 비슷한 비율이 나옵니다 ).

Indirect specular reflection & indirect diffuse reflection

SkyLight 의 경우에는 indirect specular reflection 과 indirect diffuse reflection 을 모두 반영합니다. 씬에 크롬볼과 화이트볼을 하나 배치해 보도록 합시다. 그리고 SkyLight 성분을 확실하게 보기 위해서 "Light Types >> Directional Light" 를 off 합니다. 그리고 나서 "Light Types >> Sky Lighting" 을 on/off 해 봅니다.

그림8. SkyLight 가 반영된 상태.

그림9. SkyLight 가 반영되지 않은 상태. SkyLight 를 제외한 reflection 성분은 나중에 이야기할 Reflection Capture 로부터 온 것입니다.

다음으로는 SkyLight 를 켠 상태에서 "Light Components >> Diffuse" 와 "Light Components >> Specular" 를 on/off 해 봅니다.

그림10. Diffuse 만 활성화. 크롬볼은 metalic 이 1 이고 roughness 가 0 이므로 전혀 diffuse 성분을 안 먹습니다. 원래 완전한 금속은 diffuse 가 0 이기 때문인데 그 이유에 대해서는 시리즈의 뒷부분에서 설명하도록 하겠습니다.

그림11. Specular 만 활성화. 화이트볼은 metalic 이 0 이고 roughness 가 1 이지만 fresnel 효과에 의해 약간의 specular 를 먹습니다. 그 이유에 대해서는 시리즈의 뒷부분에서 설명하도록 하겠습니다.

Capture

이제 directional light 와 sky sphere 의 설정을 변경해서 초저녁 환경을 만들어 봅시다. 하지만 Sky Light 의 capture 는 변경되지 않습니다.

그림12. 환경을 변화시켜도 SkyLight 에 반영되지 않음.

 이때 빠르게 분위기를 확인하고자 한다면 SkyLight 액터의 "Sky Light" 카테고리에서 "Recapture" 를 누르시면 됩니다.

그림13. Recapture 를 통해 환경 반영.

하지만 그림13 에서 크롬볼에 반사되는 일부 메쉬들이 여전히 파란색 스카이 컬러를 먹고 있는 것을 알 수 있습니다. 앞에서 언급했듯이 specular 성분 중에서 Sky 를 제외한 다른 부분은 Reflection Capture 로부터 온 것입니다. Reflection Catpure 에서 "Update Captures"` 를 실행해 줘야 모든 specular 성분에 Sky 색상이 제대로 반영됩니다.

Capture 대상

여러분은 이 시점에 "어떤 대상을 SkyLight 로 캡쳐하는 것일까" 궁금해 하실 겁니다. 사실 대상이 정해져 있는 것은 아닙니다. SkyLight 액터가 배치된 위치로부터 일정 거리 이상에 존재하는 요소들을 Sky 로 취급합니다. SkyLight 액터의 "Light" 카테고리에는 "Sky Distance Threshold" 라는 속성이 있습니다. 이 값을 조정하시면 됩니다.

SkyLightActor 를 액터를 벽에 붙여 놓고 "Sky Distance Threshold" 를 1.0 으로 설정하고 "Recapture" 를 하면 그림14 와 같은 결과를 얻을 수 있습니다.

그림14. Sky Distance Threshold 를 작게 잡았을 때의 결과. 하늘이 나와야 할 부분에 벽이 나오는 것을 확인할 수 있습니다.

이 값은 기본적으로 150000 센티미터( 1.5 KM )로 잡혀 있습니다. 매우 큰 값이므로 SkyLight 액터를 아무 곳에나 배치해도 상관이 없는 것입니다. 만약 여러 분이 SkyLight 에 하늘 이외의 원경이 반영되었으면 좋겠다고 생각하신다면 이 문턱값을 조정하시면 됩니다. 물론 SkyLight 액터도 적절한 위치에 배치해야겠죠.

Sky Light 의 개수

이제 이 시점에서 여러 개의 Sky Light 를 배치해 다양한 효과를 내 보겠다는 생각을 하시는 분이 있을 수 있습니다. 하지만 현재 구현에서는 하나의 월드에 여러 개의 SkyLight 를 사용하는 것이 불가능합니다. Lightmass 빌드를 하면 다음과 같은 에러를 확인할 수 있습니다.

그림15. 여러 개의 SkyLight 사용시 lightmass 에러 발생.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 10. Image Based Lighting

Global Illumination & Indirect Lighting ] 에서는 GI 를 위해 indirect light 가 고려되어야 한다고 했습니다. 

광원이 있는 경우라면 그것을 통해 indirect light 를 계산할 수 있죠. 하지만 현실적으로 모든 light 를 배치하는 것은 힘듭니다. 그렇기 때문에 이를 근사계산하기 위해 그래픽스 연구자들은 indirect light 를 image 로부터 얻어 오는 방법에 대해서 고민했고, 요새 자주 사용되는 Image Based Lighting( IBL ) 이라는 개념을 생각해 냈습니다.

이 문서에서는 이 기법이 어떻게 발전해 왔는지, 구체적으로 어떤 개념인지에 대해 다루도록 하겠습니다. UE4 에서 IBL 이 사용되는 방식에 대해서는 시리즈의 다음 문서에서 다루도록 하겠습니다.

아티스트 분들은, 글 내용 중에 이상한 개념들이 나오는데, 너무 어렵게 생각하지 마시고 그냥 그런게 있다고 생각하고 넘어가시기 바랍니다. 언급을 안 하기도 그렇고 하기도 그렇고 그래서 대충 개념만 썼는데, 어려울 수 있습니다. 그냥 기본 설명과 그림을 위주로 보시기 바랍니다. 어려운 개념들은 몰라도 크게 상관은 없는 것들입니다.

Cubemap

그래픽스 카드들은 큐브맵이라는 것을 지원합니다. 큐브맵은 어떤 시점을 중심으로 둘러싼 환경들을 미리 렌더링해서 저장할 수 있는 텍스쳐입니다. 보통 특정 위치에서 여러 방향으로 사진을 찍은 다음에 그것을 보정해서 합치는거죠. 이러한 큐브맵이 실시간 그래픽스에서 가장 먼저 사용된 곳이 SkyBox 와 SkySphere 였습니다.

그림1. 스카이 큐브맵. 출처 : Rendering a skybox using a cube map with opengel and glsl.

그림2. 그림1 의 렌더링 결과. 출처 : 그림1 과 같음.

보통 원경에다가 사용했기 때문에 거리에 의한 왜곡의 영향도 덜 받았으며 가시 품질도 나름 괜찮았죠.

Environment Mapping

그런데 텍스쳐를 이용해 금속의 반사 소스로 활용하려는 움직임이 있었습니다. 1976 년에 Blinn 과 Newell 이 "Texture and reflection in computer generated images" 라는 논문에서 이 개념에 대해 발표한 바가 있고 80 년와 90 년대 초반에 여러 사람에 의해 사용되고 발전해 왔습니다( 자세한 내용에 대해 알고 싶으시다면 [1] 의 문서를 확인하세요 ).

이러한 방식을 Environment Mapping( 환경 매핑 ) 혹은 Reflection Mapping( 반사 매핑 ) 이라 부릅니다. 특히 그래픽스 하드웨어가 지원하는 큐브맵을 이용하면 이를 쉽게 표현할 수 있습니다.

그림3. Environment Mapping 예제. 출처 : Environment Mapping, Han-Wei Shen.

큐브맵의 좌표는 그림4 처럼 큐브( 정육면체 )의 중심을 원점으로 하는 좌표계로 표현됩니다.

그림4. 큐브맵 좌표계. 출처 : CS 354 Texture Mapping.

그렇기 때문에 그림5 에서 볼 수 있듯이, 표면의 normal 과 viewer 를 향한 vector 를 알게 되면 반사벡터를 쉽게 알 수 있습니다.

그림5. 환경 매핑 좌표 구하기. V 는 View 에서 서피스까지의 벡터, N 은 노멀, Vr 은 반사 벡터. 출처 : Mapping Techniques.

그림5 에서 큐브가 아니라 구가 나와서 헷갈리는 분도 계실 수 있지만, 구는 그림6 처럼 큐브에 매핑될 수 있습니다. 벡터는 길이는 달라도 방향이 동일하면 정규화( normalize )했을 때 같은 벡터가 됩니다. 그것을 큐브맵의 좌표로 사용합니다.

그림6. sphere 와 cube 에서 벡터.

이때까지는 EnvironmentMapping 이라는 것이 금속의 반사를 표현하기 위한 소스의 역할만 하고 있었습니다.

Image Based Lighting

그렇지만 하드웨어 성능이 더 발전하면서 Environment Mapping 을 한 단계 더 발전시켜 광원으로 만드려는 시도가 있었으며, 이것이 바로 Image-Based Lighting( IBL, 이미지 기반 조명 ) 개념입니다. 이것에 대해 주도적으로 연구한 사람은 Paul Debevec 이라는 분인 것 같더군요[2]( [2] 에 가면, 2003 년까지의 HDR 및 IBL 관련 자료들에 대한 링크가 많습니다. 관심있는 분들은 확인해 보시기 바랍니다 ).

IBL 과 Environment Mapping 의 가장 큰 차이는 이미지 소스가 광원으로서 사용되느냐 그렇지 않느냐에 있습니다.

IBL Diffuse

표면에 들어 온 빛은 그림7 처럼 반사( reflected ), 투과( transmitted ), 흡수( absorbed )됩니다. 

 

그림7. 빛의 반사, 투과, 흡수. 출처 : Waves, KaiserScience.

그 중에서 반사 성분은 그림8 처럼 크게 diffuse reflection( 난반사 ) 과 specular reflection( 정반사 ) 로 나뉘죠. 다들 이 개념에 대해서는 익숙할 것입니다. 그런 현상이 왜 발생하는지는 시리즈의 뒷부분에서 다루도록 하겠습니다.

그림8. Diffuse reflection & Specuar reflection. 출처 : Diffuse reflection, Wikipedia.

어쨌든 기존 environment mapping 에서는 큐브맵을 specular 성분으로만 사용했습니다. 앞서 말했듯이 금속을 표현하기 위한 용도였죠. 하지만 이를 제대로 된 광원으로서 사용하기 위해서는 diffuse 성분도 고려되어야 하며, GI 까지 생각하면 그림9 처럼 주변광들까지 고려가 되어야 합니다. 주변광까지 고려해서 큐브맵으로부터 서피스에 들어 온 빛들은 서피스 입장에서 보면 조도( illuminance, irradiance )라 할 수 있겠죠. 그래서 이러한 정보를 담고 있는 것을 irradiance map 이라고 부릅니다.

그림9. IBL 에서 irradiance. 출처 : [3].

이 irradiance map 은 해당 지점에서 오는 난반사 성분을 받아야 하기 때문에 원래 이미지보다는 뭉개진 느낌이 나겠죠.  그림10 의 오른쪽에 보이는 큐브맵이 irradiance map 입니다.

그림10. Irradiance map 샘플. 출처 : [3].

그런데 여기에서 한 가지 문제가 발생합니다. 큐브맵 텍스쳐를 샘플링( 텍스쳐에서 텍셀( texel )값을 가지고 오고 필터링( filtering )하는 작업 )하는 것은 그렇게 비용이 싼 작업이 아닙니다. 게다가 그림9 에서처럼 매우 많은 영역을 샘플링해야 합니다. 그림9 에서는 예를 들기 위해서 화살표 몇개만 그려주고 2D 로 보여줬지만 3D 에서 엄청난 텍셀을 샘플링해야 합니다. 물론 하나만 할 수도 있겠지만, 그럼 주변광( indirect lighting )을 받는다는 GI 원칙에서 어긋나겠죠. [3] 에 따르면 한 면이 128 X 128 해상도인 큐브맵에서 diffuse 를 구하기 위해서는 50,000 만큼의 샘플링이 필요하다고 하네요.

그래서 연구자들은 이를 좀 단순하게 계산하는 방법을 찾았습니다. 그것이 바로 Spherical Harmonics( SH, 구면 조화 )입니다. 이름부터 무시무시합니다. 어디선가 한번씩은 들어 보셨을 거라 생각합니다. 이 주제에 대해서는 저도 완전히 파악하고 있지 않기 때문에 나중에 시간이 나면 자세히 다루도록 하겠습니다.

SH 는 구면에서 뭔가 튀어나오거나 들어 간 물체의 형태를 그림11 처럼 수학적으로 표현하는 것입니다. 그런데 계수( l )가 얼마나 크냐에 따라서 좀더 디테일한 모양이 나오는 것이죠. 이 함수에다가 각도같은 걸 넣으면 원하는 형태를 얻을 수 있습니다. 솔직히 이해하기 힘드니 "그냥 그렇구나" 하시면 됩니다.

그림11. Spherical Harmonics 예제. 출처 : Opinions on Spherical harmonics.

그런데 이걸 어디다 쓰느냐구요?

예를 들어 그림10 의 irradiance map 을 구에다가 매핑한 다음에 밝기에 따라 튀어 나오게 하면 그림12 같은 느낌이 되겠죠(그냥 개념적으로 쉬운 설명을 위한 용도로 만들었으므로 정확한 것은 아닙니다 ).

그림12. 그림10 의 irradiance 를 구에 매핑했을 때의 느낌.

그럼 이 모양에 SH 를 적용해서 단순한 함수로 만듭니다. 그림11 에서 봤듯이 어떤 계수를 사용하느냐에 따라 좀 더 많은 모양이 나오고 결과가 정확해지겠죠. 대체적으로 "l = 3" 정도면 그럴싸한 모양이 나온다고 합니다.

어쨌든 이런 식으로 각 텍셀을 SH 함수로 만들면 빛이 나가는 경향과 세기가 결정됩니다. 아티스트 분들은 그냥 "최적화 함수구나" 라고 이해하시면 됩니다. 우리가 사용하는 irradiance map 은 단순히 diffuse 를 저장한 것이 아니라 SH 를 저장한 것이라는 것만 알고 계시면 됩니다.

이러한 IBL diffuse 를 적용하면 그림13 과 같은 결과가 나옵니다.

그림13. IBL Indirect Diffuse. 출처 : [3].

IBL Specular

Specular 성분은 Environment Mapping 에서 다뤘던 것과 큰 차이는 없습니다. 하지만 PBR 에서는 roughness( 거칠기 ) 라는 개념을 도입했고, 같은 금속이라도 얼마나 연마되었느냐에 따라서 그림14 에서 볼 수 있듯이 매끈함의 정도가 틀립니다( roughness 에 대해서는 시리즈의 뒤쪽에서 설명하겠습니다 ).

그림14. Roughness 에 따른 매끈함의 변화.

일반적으로 거칠기에 의해 blurring 이 먹는 것을 표현하기 위해 그림15 처럼 mipmap 을 만들어 처리합니다. LOD 레벨이 높아질수록 Roughness 가 높은 것으로 취급합니다.

그림15. 반사맵 밉맵. 출처 : [3].

Roughness 0.1 일 경우에 specular 만 출력한 예가 그림16 에 나와 있습니다.

그림16. Roughness 01 에서 IBL Indirect specular 의 예. 출처 : [3].

정리

IBL 은 이미지를 광원으로 취급해서 indirect light 성분을 획득하는 방식입니다. 실시간 GI 를 구현하기 힘든 상황에서 대안으로 사용합니다. 사실, 실시간 GI 를 사용한다고 해도 모든 광원을 배치하는 것은 불가능하기 때문에, 같이 사용하는 경향이 있습니다.

실제 엔진에서는 importance sampling 이라든가 하는 복잡한 방식을 사용합니다. 왜냐하면 diffuse 처럼 specular 로 일정 영역을 샘플링해야 제대로 된 결과가 나오기 때문입니다. 이 기법은 반사, Area light, Ray-tracing, 적분( integral ) 등의 주제와 관련이 있으므로 여기에서 설명하기에는 좀 주제가 무겁습니다. 그러므로 나중에 따로 주제를 잡아서 이야기하도록 하겠습니다( 만약 자세한 내용을 알고자 한다면, "IBL Importance Sampling" 이나 "IBL Filtered Importance Sampling" 등의 키워드로 검색해 보십시오.

UE4 의 경우에는 Split Sum Approximation 과 Prefiltered Environment Map 이라는 기법을 사용해 IBL specular 를 구현한다는 것만 언급하고 넘어가겠습니다. 자세한 내용은 [ Real Shading in Unreal Engine 4 ] 의 [ Image based lighting ] 항목을 참조하세요 ).

참고자료

[1] The Story of Reflection Mapping.

[2] HDRI and Image-Based Lighting, SIGGRAPH 2003.

[3] Physcally Based Rendering - Part Three.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 9. Global Illumination & Indirect Lighting

빛의 경로

지금까지는 빛이 서피스에 반사되어 들어 오는 경우만을 이야기했습니다. 하지만 빛이 눈에 들어 오는 경로는 그림1 처럼 매우 복잡합니다. 산란( scattering ), 투과( Transmission ), 반사( Reflection ), 흡수( Absorbtion )가 모두 고려되어야 매우 자연스러운 결과가 나옵니다.

그림1. 다양한 경로로 눈에 들어 오는 빛.

Local Illumination

컴퓨팅 파워의 한계 때문에 실시간 그래픽스에서 그림1 에 나오는 모든 요소들을 처리할 수는 없습니다. 그래서 PBR 이전에는 빛이 직접적으로 닿는 부분만 고려해 렌더링을 했습니다. 그렇게 되면 빛이 직접적으로 닿지 않는 부분은 어두워지겠죠. 그렇지만 우리는 실세계에서는 완벽하게 어두운 부분은 존재할 수 없음을 알고 있습니다. 왜냐하면 한 서피스에 도달하는 빛은 여러 서피스로부터 반사된 후에 올 수 있다는 것을 알고 있기 때문입니다. 그래서 주변광( ambient light ) 라는 개념을 만들어서 어두운 부분을 대충 밝혀 줍니다.

Ambient 를 얼마만큼 밝혀줘야 하느냐? 그것은 아티스트의 감에 달려 있었습니다. 그래서 global ambient 와 material ambient 가 나뉘어 있었습니다. 오브젝트가 놓여 있는 환경이 다르다보니 어쩔 수 없는 선택이었죠.

이런 방식을 local illumination( 지역 조명 ) 이라고 부르며, 그 결과는 그림2 와 같습니다.

그림2. Local Illumination. 출처 : [1]

Global Illumination

사람들은 Local Illumination 이 부자연스럽다는 것을 알고 있습니다. 서피스에 들어 온 빛은 다시 다른 서피스를 위한 광원으로 사용될 수 있습니다. 물론 투과되는 빛도 다른 서피스를 위한 광원으로 사용될 수 있습니다. 이렇게 서피스에서 반사되거나 굴절되는 모든 빛을 새로운 광원으로 삼는 것을 Global illumination 이라 부릅니다.

그림3. Global Illumination. 출처 : [1]

그림3 을 보시면 그림2 와 비교했을 때 굴절과 반사가 제대로 제대로 적용되고 있음을 확인할 수 있습니다. 우리가 실세계에서 익숙하게 볼 수 있는 복잡한 결과가 나오게 되는겁니다.

이제 여기에서 여러분에게 GI 의 핵심 성분들에 대해서 이야기하도록 하겠습니다.

그림4. 눈에 들어 온 GI 성분들. 출처 : [2]

    • Direct light 는 광원에서 표면으로 직접 들어 온 빛을 의미합니다.

    • Indirect light 는 표면에 들어 온 빛이 반사되어 새로운 광원처럼 사용되는 경우를 의미합니다.

만약 direct light 성분만 계산을 하게 되면 그림5 와 같은 결과가 나옵니다.

그림5. Direct light Only. 출처 : [3].

바닥에 비춰진 빛이 반사되어( bounced ) 광원( indirect light )으로 작용하면, 그림6 과 같은 결과가 나옵니다.

그림6. Direct light + 1-bounced indirect light. 출처 : [3].

그렇다면 광원에서 나와서 한 번 반사된( 1-bounced ) 빛이 한 번 더 반사되면( 2-bounced ) 어떻게 될까요? 다시 다른 오브젝트나 바닥으로 반사되는 빛들도 존재하겠죠? 그러면 그림7 처럼 됩니다.

그림7. Direct light + 2-bounced indirect light. 출처 : [3].

이러한 bounce 가 많으면 많을수록 더 자연스러운 결과가 나오게 됩니다.

하지만 실시간 그래픽스에서 이런 계산을 하는 것은 너무 힘듭니다. 그래서 이를 근사계산하기 위해서 LPV( Light Propagation Volume ), SVOGI( Sparse Voxel Octree Global Illumination ) 등의 실시간 GI 알고리즘들과 Image Based Lighting( IBL ) 과 같은 개념들이 나오게 되었습니다.

Indirect Lighting Bounce 설정

UE4 에서는 LPV 를 적용하지 않는 이상 Static 과 Stationary 에 대해서만 GI 를 적용해 줍니다. UE4 에서는 이를 "Lightmass Global Illumination" 이라고 표현합니다.

툴바에 있는 "Settings" 풀다운 버튼에는 "World Settings" 메뉴가 있습니다.

그림8. WorldSettings 메뉴.

거기에 보면 "Lightmass" 카테고리가 있죠. 그 중에 "Num Indirect Lighting Bounces" 항목이 있습니다. 위에서 언급했듯이, 광원에서 나온 빛이 반사되서 나오는 횟수를 의미합니다. 이것이 0 이라면 direct light 성분만을 고려하겠다는 겁니다.

그림9. Direct light only.

이제 bounce 를 2 와 4 로 주고 결과를 확인해 보도록 하겠습니다.

그림10. Direct Light + Indirect Light. Bounce 2 일 때와 4 일 때의 결과.

Bounce 가 2 일 때와 4 일 때 미약하지만 영향을 주는 범위가 넓어지는 것을 알 수 있습니다. 하지만 2 일 때와 4 일 때의 차이는 범위가 조금 넓어졌다는 것 말고는 큰 차이가 없습니다. 반사를 하면 할수록 빛이 감쇠되기 때문에 너무 높은 값을 잡아 봐야 별로 소용이 없습니다. 그러므로 2 정도의 값이 적절합니다. 이는 Lightmass 빌드 속도에도 영향을 주므로 신중하게 결정할 필요가 있습니다.

Indirect Lighting Intensity 설정

하지만 기대했던 것처럼 Indirect light 의 영향력이 크지 않아 실망하시는 분들이 계실겁니다. 이 때 사용할 수 있는 것이 "Indirect Lighting Intensity" 속성입니다. UE4 의 광원들에는 "Light" 카테고리에 "Indirect lighting Intensity" 라는 항목이 있습니다.

앞의 "Lightmass" 카테고리의  설정은 전역 설정이지만 "Light" 카테고리 설정은 개별 설정입니다. 이 값을 2 로 해 놓고 결과를 확인해 보도록 하겠습니다.

그림11. Direct Light + Indirect Light. Bounce 2 일 때와 Intensity 값을 2 배로 늘려서 결과 비교.

Intensity 를 올리면 굳이 bounce 를 올리지 않더라도 더 멀리까지 영향을 주는 것처럼 보일 수 있습니다. 물론 가까운 곳에서 indirect lighting 의 영향이 세지기는 하겠죠.

Direct Light 와 Indirect Light 의 관계

그런데 실무를 하다가 보면 이상한 의문이 드는 분들이 계실 겁니다. "Light intensity 를 내렸더니 direct lighting 성분이 내려 가고 indirect lighting 성분이 올라 가요!!!", "Lighting build 를 했더니 갑자기 결과가 너무 달라져요!!!"

그림11 까지의 스샷들은 5000 루멘을 기준으로 찍은 것입니다. 그림11 의 두 번째 환경에서 light intensity 만 100 으로 고쳐보겠습니다.

그림12. 5000 루멘에서 100 루멘으로 내렸을 때

이상한 결과가 나왔지만 매우 당연한 것입니다. Indirect lighting 이라는 것은 Lightmass 빌드를 돌려야만 계산되는 것입니다. 그래서 intensity 를 바꾸게 되면 direct lighting 성분에는 즉각 반영이 되지만, indirect lighting 성분은 이전에 계산했던 값 그대로 남아 있게 됩니다. 그러면 direct light 성분이 낮아졌으므로 indirect light 성분은 ( auto exposure 에 의해 ) 상대적으로 밝아지는 것이죠. 그러므로 stationary light 의 Intensity 값을 변경하면 반드시 Lightmass 빌드를 해 주셔야 합니다. 물론 Static 도 그래야 합니다.

이러한 사실을 이용하면 재밌는 비주얼 디버깅을 해 볼 수 있습니다. Intensity 값을 0 으로 해 버리면 direct light 성분이 평가되지 않으므로 indirect light 성분만 볼 수가 있습니다. 실제 영향을 준 범위가 어디까지인지 알 수가 있겠죠.

그림13. Intensity 를 0 으로 만들어 Indirect 성분만 확인.

Indirect light 성분을 조정하는 것은 direct light 성분에 전혀 영향을 주지 않습니다. 단지 상대적인 관계가 달라 보이는 것입니다.

Lighting Quality 와 메쉬

Lightmass 를 preview 로 빌드하면 indirect lighting 결과가 상당히 이상하게 나올 수 있습니다.

그림14. Lighting Quality 설정.

그림15 는 indirect light 가 테이블을 뚫고 나오는 것을 보여 줍니다.

그림15. Preview 에서 잘못 나오는 indirect lighting 결과.

제가 lightmass 구현을 안 봐서 잘 모르겠지만, 아마도 volume 에다가 illuminance 나 luminance 를 저장하는 것이 아닌가 싶습니다. 그리고 preview 에서 product 로 품질이 올라갈 수록 그 volume 의 크기가 조밀해지는 것이 아닌가 싶습니다. Ray 샘플 개수나 photon 개수 및 밀도 등 여러 요소들이 달라지기 때문입니다. 그렇기 때문에 샘플링되지 않은 부분들은 보간이 됩니다.

그래서 테이블의 두께를 3 배 정도로 해 봤습니다. 그랬더니 그림16 에서 볼 수 있듯이 preview 에서도 차폐가 거의 제대로 되는 것을 확인할 수 있었습니다.

그림16. 테이블의 두께를 3 배로 늘렸을 때의 결과.

사실 그림16 도 완벽한 결과는 아닙니다. Production 으로 빌드했을 때는 완벽하게 차폐가 됩니다.

여기에서 이야기하고자 하는 것은 메쉬의 두께가 얇으면 preview 에서 잘못된 결과를 산출할 수 있기 때문에 이를 고려하면서 작업을 하셔야 한다는 것입니다. 사실 너무 얇으면 production 에서도 문제가 발생합니다.

그러므로 가급적이면 너무 얇은 메쉬들은 안 만드는 것이 좋습니다. 만약 어쩔 수 없이 그런 메쉬들을 만들어야 한다면, bounce 를 1 로 설정하고 production 이나 high 품질에서 라이팅 결과를 확인하시는 것이 바람직할 것이라 생각합니다.

PostProcessVolume

전체 indirect lighting 성분을 전반적으로 올리고 싶은 경우가 있습니다. 그런 경우에는 PostProcessVolume 을 설치하시면 됩니다. "Rendering Features" 카테고리에 보면 "Global Illumination" 이라는 하위 카테고리가 있습니다.

"IndirectLightingColor" 는 전체 indirect light 성분의 색상에 곱해지며, "Indirect Lighting Intensity" 는 전체 indirect light 성분의 세기에 곱해집니다. 이런 설정은 전역적이므로 함부로 건드리지는 않는 것이 좋습니다. 라이트 설정을 다 해 놨는데 공식이 바뀌어서 전반적으로 intensity 가 달라졌다든가 하는 경우나 게임 그래픽스 컨셉상 이상한 조명을 만들고 싶다든가 하는 경우에만 사용해야겠죠.

그림17. PostProcessVolume 을 사용한 indirect 성분 조정.

여러분은 그림17 에서 보이듯이 이런 설정은 direct lighting 성분에 전혀 영향을 주지 않는다는 점을 이해해야만 합니다. Direct lighting 성분은 여전히 흰색으로 보이고 있음을 기억하세요.

참고자료

[1] Global illumination, Wikipeida.

[2] PRACTICAL REAL-TIME VOXEL-BASED GLOBAL ILLUMINATION FOR CURRENT GPUS, Alexey Panteleev, NVIDIA.

[3] Real-time Global Illumination Using Voxel Cone Tracing, Fredrik Prantare.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 8. Attenuation Radius 설정

거리 감쇠

3. 빛의 감쇠 ] 에서는 빛의 감쇠가 1 / dist2 으로 이루어진다고 했습니다. 하지만 실질적으로 컴퓨터 프로그램에서는 그런 식을 사용할 수 없습니다. 왜일까요?

dist = 0 인 상황이라면 결과가 1 / 0 이 됩니다. 그러면 컴퓨터는 이를 inf( 무한대, infinity ) 라고 평가하게 됩니다. 그래서 보통은 기본 감쇠 공식은 거리가 0 이 될 수 없다고 가정하고 계산을 하게 됩니다. 게다가 가장 가까울 때의 빛이 원래 빛의 밝기보다 밝아서는 안 되는 원칙( 에너지 보존 법칙 )도 지켜줘야겠죠.

그래서 UE4 에서는 거리 감쇠를 위해 식1 을 사용합니다.

식1. UE4 에서의 거리 감쇠 공식.

DistanceBias 라는 것이 갑자기 튀어 나와서 놀라셨겠지만, 이것은 쉐이더에서 그냥 1 로 정해져 있습니다.

식만 봐서는 잘 모르겠죠? 이를 그래프로 보면 그림1 과 같습니다.

 

그림1. 1 / dist2 과 1 / ( dist2 + 12 ) 의 비교. 거리( x 값 )가 0 이 되면 파란 그래프는 최대값이 1 이 됩니다.

하지만 여전히 이 감쇠 그래프는 문제점을 가지고 있습니다. x 값이 엄청나게 커져도 0 이 되질 않습니다. 즉 빛은 그 세기가 다를뿐 무한대의 거리까지 퍼져나간다는 의미입니다.

감쇠 반경 마스크

대부분의 엔진들에서 광원들은 "Attenuation Radius" 라는 속성을 가지고 있습니다. 이는 광원이 영향을 미치는 거리를 강제로 줄여버리는 역할을 합니다.

그림2. UE4 의 Attenuation Radius 속성. Source Radius 는 area light 의 속성입니다. 

왜 이런 일을 할까요? 사실 이유는 별게 아닙니다. 컴퓨팅 파워가 부족하기 때문입니다.

그림3 을 보시면 어느 정도 거리가 멀어지면 빛의 거의 영향을 미치지 못하는 것을 볼 수 있습니다.

그림3. 눈으로 보면 일정 거리 이상에 빛이 닿지 않는 것처럼 보입니다. 하지만 사실은 그림1 에서 확인할 수 있듯이 매우 약한 빛이 닿고 있는 것이죠.

씬 내에는 수 백개 많으면 수 천개의 광원이 존재할 수 있는데, 이를 모두 계산하기에는 비용이 너무 비쌉니다. 그래서 특정 광원이 미치는 범위를 조절하게 됩니다. 그것이 바로 감쇠 반경( Attenuation Radius )인 것이죠. 이를 UE4 에서는 내부적으로 "Light Radius Mask" 라고 부릅니다.

이는 식2 와 같이 계산됩니다.

식2. LightRadiusMask 공식.

식이 어렵죠? 이해하시려고 노력하실 필요는 없습니다. 저도 잘 이해가 안 갑니다. 여기에서 saturate() 라는 함수는 0 보다 작은 값은 0 으로, 1 보다 큰 값은 1 로 잘라주는 함수입니다.

어쨌든 그래프로 느낌만 이해하면 됩니다. 예를 들어 Radius 가 1 인 경우와 2 인 경우를 살펴 봅시다. 그럼 그래프는 그림4 와 같은 모양을 가집니다.

그림4. LightRadiusMask 그래프. Radius 가 1 이면 Dist 가 1 이 넘어갈 때 밝기가 0 이 되고, Radius 가 2 이면 Distance 가 2 가 넘어갈 때 밝기가 0 이 됩니다.

거리 감쇠와 감쇠 반경의 결합

이제 위에서 언급한 두 개의 식( 식1식2 )을 곱한 것이 최종 감쇠 공식입니다.

식3. 최종 감쇠 공식.

식을 봐봐야 머리만 아프니 그래프를 살펴 보죠. 이것의 형태는 그림5 와 같습니다. 그래프의 차이를 좀 더 명확하게 보기 위해서 빛의 밝기를 10 이라고 가정했습니다.

그림5. 빛의 밝기가 10 일 때 최종 감쇠 그래프.

여러분은 그림5 를 보면서 Radius 가 크면 클수록 Attenuation Radius 를 적용하지 않은 원래의 감쇠 공식과 비슷해진다는 것을 알 수 있을 겁니다. 그러므로 과도하게 적은 Radius 를 잡으면 감쇠가 이상한 형태로 나오는 결과를 산출하게 됩니다.

잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요


[ PBR 이란 무엇인가 ] 7. Light intensity 설정

개요

지금까지는 광도측정( photometry ) 관점에서 빛을 살펴 봤습니다. 사실 보면서 이게 "실무랑은 무슨 관계가 있나" 라는 의문을 가지시는 분들이 꽤 있었을 겁니다. 그러므로 딱히 이론적인 부분에 관심이 있는 분이 아니라면 지루하실 수도 있었을 겁니다. 이번 장부터는 앞에서 언급한 이론들을 UE4 를 사용해 실제로 적용해 보도록 하겠습니다.

[ 광원의 밝기( 광속 ) ] 에서는 광원의 밝기는 전방향으로 향하는 빛의 총량이라고 했습니다. 그리고 [ 조도( illuminance )측정 ] 에서 조도라는 것은 서피스에 들어 온 빛의 양을 의미한다고 했습니다. 그런데 PBR 로 오면서 조명의 개념이 약간 확장되었습니다. Area light 라는 개념이 생긴 것이죠. 말 그대로 범위를 가진 광원에서 나오는 빛을 의미합니다. 반대로 punctual light 는 point light, spot light 등 볼륨을 가지지 않는 기존 방식의 조명들을 의미합니다. 사실 우리가 매일 접하게 되는 실세계 조명들은 그림1 처럼 거의 다 area light 라 봐야겠죠. 

그림1. 실세계 조명들. 출처 : [1].

"Punctual" 이라는 것은 "시간을 엄수하는", "( 시간에 맞게 ) 정확한" 등의 뜻을 가지고 있습니다. 이것을 왜 area 의 반대 개념으로 사용하고 있는지는 저도 잘 모르겠습니다. Max, Maya, Frostbite 같은 프로그램/엔진들에서는 punctual light 를 photometric light 에 포함시켜 이야기하기도 합니다. 그림 2 에서 보이듯이 광원이 복잡한 IES( Illumination Engineering Society, 조명 공학회 ) profile 을 가지지 않는다면, 그냥 point light 나 spot light 가 되겠죠. 그런 것을 그냥 Simple/Isotropic profile 이라 부르는 것 같습니다. 

어쨌든 punctual light 를 사용하게 되면, ( GI 를 고려하지 않는다고 가정할 때 ) 한 광원에서 나오는 빛은 한 서피스에 한 번만 도달합니다.

그림2. Punctual light. 출처 : [1].

Puncutal light 와는 다르게 area light 는 그림3 에서 볼 수 있듯이 한 서피스에 대해 여러 번 빛을 방출하게 됩니다.

그림3. Area light. 출처 : [1].

여러 분은 그림2 의 punctual light 와 그림3 의 area light 를 보면서, "각각의 광원마다 빛의 세기( 밝기 )를 설정하는 방식이 달라야 한다" 고 느끼셨나요?

네 당연히 달라야 합니다. 왜냐하면 puncutal light 는 광도( luminous intensity, cd ) 관점으로 설정해야 하며, area light 는 광속( luminous flux, lumen ) 관점으로 설정해야 하기 때문입니다. Puncutal light 의 경우 특정 방향으로 가는 빛만이 서피스에 도달하므로, 전체 빛의 양을 의미하는 광속을 설정해서는 안 되겠죠. 광도와 광속의 차이가 이해가 안 가시면, [ 광원의 밝기( 광속 ) ]을 보고 오세요.

아티스트가 여러 단위를 써 가면서 이런 부분을 제어하는 것은 좀 스트레스를 받는 일이겠죠. 하지만 punctual light 의 경우에는 빛을 세기를 광도 단위로 설정하는 것이 좀 더 직관적일 수는 있습니다. 그냥 "얼마만큼의 빛이 특정 방향으로 전달되어야 해"라고 생각하는 것이 편하니까요. 그래서 프로스트바이트의 경우에는 단위를 직접 설정( 광속, 광도, 조도 )할 수 있도록 하고 있더군요[1]. CryEngine 3.6 같은 경우에는 조도 단위로 설정하도록 하고 있구요.

하지만 빛의 세기를 일괄적으로 광속 단위로 설정하더라도 이를 광도나 조도 단위로 변환하는 것은 엔진 내부에서 수행될 수 있습니다. 그러므로 이에 대해서 크게 걱정할 필요는 없습니다.

점광원의 광속을 기준으로 광도를 계산하는 경우를 생각해 봅시다. 구의 겉면적이 4π 이므로, 구의 단위 입체각을 통해서 나가는 빛의 양은 식1 과 같습니다.

식1. 점광원의 광도 계산.

그러면 점광원을 위해 설정한 설정한 광속( luminous flux )을 I 라 할 때( 원래는 φ( phi [fai] -- 'f' 발음 잘 안되니 '파이' 와 구분하기 위해 '화이' 라고 읽거나 그리스 발음인 '피' 라고 읽기도 합니다 )로 표기해야 하는데 여기에서는 그냥 I 로 표기하겠습니다 ), 조도( illuminance ) E 는 식2 와 같습니다.

식2. 점광원의 조도 계산.

식2 에서 곱하기 앞쪽은 이해하기 어렵지 않습니다. 방금 이야기한 부분이니까요. 그런데 뒤의 식이 갑자기 붙어 있으니 머리가 살짝 아파지실 겁니다. r 은 광원에서 서피스까지의 거리이고, θ 는 광원과 서피스 노멀( normal )과의 각도입니다.  [ 조도( illuminance )측정 ] 에서 조도에 영향을 주는 부분은 거리 및 기울기라고 이야기했던 걸 기억하시나요?

광원과 서피스의 거리가 멀어지면 빛의 양이 1/r2 으로 줄어들고, 기울기가 달라지면 빛의 양이 cos(θ) 만큼 줄어듭니다. 이럼 감쇠항들을 식에다가 넣으면 식2 의 형태가 되는거죠.

공식이 나오니 좀 당황스럽겠지만, 차분하게 생각해 보세요. 앞의 시리즈에서 언급했던 것을 공식으로 나타낸 것 뿐입니다

주의 : 아래 그림에서 한 점이라고 표현했는데, 단위 입체각을 의미합니다. 그림을 수정해야 하는데 귀찮아서 그냥 둡니다.

그림4. Illuminance 공식의 구성. 주의 : 그림에서 한 점이라고 표현했는데, 단위 입체각을 의미합니다. 그림을 수정해야 하는데 귀찮아서 그냥 둡니다.

그런데 실제 UE4 에서의 설정은 어떨까요?

이노무 언리얼!!!

지금부터는 UE4 를 까는 이야기를 할 겁니다. 가끔 UE4 구현을 보면 "이게 뭔 삽질인가" 라는 느낌이 들 때가 있습니다. 뭔가 구현은 해 놨는데 엉망으로 해 놨다는 느낌입니다. Frostbite 보다 그래픽스 품질이 떨어지는 것은 어쩔 수 없는 것 같습니다. 제대로 검증도 안 하고 구현하는듯...

어쨌든 본론으로 들어가, UE4 의 경우에는 광속 단위로 빛의 밝기를 설정하고 있습니다. 뭐 여기까지는 OK 입니다. Punctual light 의 경우에는 이를 엔진 내부에서 광도로 변환해 주면 되기 때문입니다.

하지만! 버뜨! 아놔! UE4 는 4π 로 광속을 나누는 것을 빼 먹었습니다. 게다가 미친 삽질까지 하나 더 합니다. 4.9 버전에서 "Correction for lumen units" 라는 작업을 한 것 같습니다. Inverse square falloff( 거리 제곱분의 1 로 감쇠 )를 사용하는 경우에, 빛의 밝기에 16 을 곱합니다.

16 이라는 속임수 값은 point light 가 거리의 제곱분의 1 로 감쇠될 때 기본 노출( exposure )에서 합리적인 밝기로 보일 수 있도록 하기 위해 추가한 X 같은 거야. Point light 감쇠를 위해 1/(4pi) 는 계산 안 해.

- Brian Karis, Epic Game, Inc.

- 출처 : UDN.

정말 할 말이 없습니다. Physically based 인데 완전 지 맘대로 값을 설정하고 있습니다. 에너지 보존 법칙을 위배한 데다가, 임의의 값을 곱하기까지 합니다. 이것 때문에 혼란스러워하는 사람들이 있는데, 그냥 씹어버립니다.

우리는 당신이 검토하고 있는 부분에 대해서 그리 많은 노력을 들이지 않았어. ( 중략 ) 요걸 좀 명확하게 정리하는 시간을 가지고 싶은데, 내 할 일 목록에 있는 다른 것들을 처리하느라 바뻐.

- Brian Karis, Epic Games, Inc.

- 출처 : UDN.

벌써 4.17 이 다가 오고 있는데, 검토는 안 하나 봅니다.

이 때문에 촛 불의 밝기 12.57( 혹은 15 ) 을 설정해도 촛불같지가 않습니다. 물론 UE4 는 100 이 1m 이므로, 1257 을 설정해 주긴 해야겠죠. 그렇다고 해도 촛불같지 않습니다.

그리고 감쇠 거리 설정을 어떻게 해야 할지 감을 잡기가 힘들 겁니다.

그럼 어떻게?

이런 상황에 대응하는 세 가지 자세가 있습니다.

    1. 현실을 인정하고, 감으로 값을 때려 넣는다.
    2. 현실을 인정하고, 적절한 값을 넣는다.
    3. 현실을 부정하고, 제대로 고친다.

뭐 1 번이야 알아서 하고 계실테고, 2 번과 3 번에 대해서 이야기하도록 하겠습니다.

현실 인정 -> 적절한 값 넣기

먼저 2 번 자세입니다. 앞에서 UE4 가 4π 로 나누는 것을 누락시키고 16 을 곱했다고 했습니다. 그러므로 값을 넣을 때 한 번 더 계산을 해 주는거죠.

내가 어떤 차트에서 I 루멘이라는 값을 가지고 왔다고 칩시다. 그러면 입력할 때 거리 팩터를 곱해주면 100 * I 루멘이 됩니다. 이걸 엔진 내부에서 다시 16 을 곱해서 최종적으로 1600 * I 루멘이 되죠. 그러면 식3 과 같이 현재값과 기대값 사이의 변환을 할 수 있습니다.

식3. 현재값과 기대값의 변환. 현재 넣는 값에 0.004973 을 곱해주면 됩니다. 물론 감쇠거리 계산도 적절히 해야겠죠.

현실 부정 -> 제대로 고치기

3 번 자세입니다. 그냥 제대로 고치는 겁니다. 물론 엔진 프로그래머가 고쳐줘야겠죠. [2] 번과 동일하게 고치면 별 문제가 없을 것이라 봅니다.

그림5 : 다양한 광속( luminous flux, luminous power ). 출처 : [2]. 태양의 경우에는 거리감쇠가 없으므로 바로 조도( lux )로 표시. UE4 에서는 거리 팩터( 100 = 1m )를 적용해 각각 1500, 120000, 260000 으로 넣어 줘야 합니다. 물론 그냥 루멘값을 넣으면 내부적으로 100 을 곱해주는 것도 방법이겠죠( 그림6 참조 ).

그러면 여러 차트에 있는 값들을 그냥 가져다 쓸 수도 있고, 감쇠 거리도 계산하기 편해집니다. 예를 들어 10 미터까지 도달하는 라이트를 설정하고 싶다면 제곱하면 됩니다. 즉 10 X 10 = 100 루멘을 설정하는 거죠. 반대로 루멘을 통해 감쇠거리를 계산하고 싶다면 root 를 씌우면 됩니다( 제곱근을 구하면 됩니다 ). 앞의 예로 보면 100 루멘짜리 라이트는 10 미터를 가는 것이죠.

그림6. UE4 엔진 코드를 수정하고, 두 개의 촛불을 넣음( 천장에 있는 등불도 촛불 밝기 ). 각각 15 루멘( 촛불 하나의 밝기 ) 설정. 15 루멘 입력하면 100 / ( 4 * pi ) 를 자동으로 적용해서 칸델라로 변환합니다. Eye-Adaptation 이 완전히 적용된 상태입니다.

그림7. 비교 자료. 실제 촛불 하나의 느낌. 출처 : DevianArt.

정리

현재 UE4 엔진은 조도계산 시에  4π 로 나누는 것을 누락시키고 16 을 곱했습니다. 그래서 외부 차트의 값을 가져다 쓰기도 애매하고 감쇠거리를 설정하기도 애매합니다. 뭘 기준으로 계산을 해야 할지 부정확하기 때문입니다.

게다가 directional light, punctual light, area light 의 라이트 세기 설정 방식이 전부 다릅니다. 그냥 이쪽 프로그래밍한 사람 맘대로입니다. 정말 한 대 쥐어 박고 싶군요.

개인적으로 PBR 을 도입하는 데 있어서 중요한 부분이 "단순성과 일관성" 에 있다고 봅니다. 아티스트가 값을 결정하는 데 있어서 의구심을 가질만한 요소가 적어야 한다고 봅니다. 그리고 아티스트가 외부 자료들을 보고 쉽게 자신만의 설정값 데이터베이스를 구축할 수 있어야 하겠죠.

그러므로 엔진을 고치든지 제대로 된 값을 계산해서 넣든지 해야 할 것이라 생각합니다. 아니면... 감쇠거리로부터 루멘을 계산해 주는 유틸리티를 추가하는 것도 방법이겠죠. 일반적으로 아티스트들에게는 일정 거리까지 도달하는 빛을 만드는 것이 목적일테니 말이죠.

참고 자료

[1] Moving FROSTBITE to PBR, Sebastien Lagarde & Charles de Rousiers.

[2] Moving Frostbite to Physically Based Rendering 3.0, Sebastien Lagarde & Charles de Rousiers.

잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 6. 휘도( luminance ) 측정

휘도

오늘은 드디어 빛이 여행하는 최종단계를 다룹니다. 광원에서 방출되어 표면에 도달한 빛은 표면의 재질( 속성 )에 따라 여러 방향으로 반사됩니다. 그리고 나서 그 빛 중의 일부는 우리의 눈에 도달하게 됩니다.

그림1. 조도와 휘도의 관계.

여러 분이 인터넷에서 광속( luminance flux ), 조도( illuminance ), 휘도( luminance ) 등에 대해서 검색을 하게 되면, 휘도에 대해서 검색했을 때 가장 많은 자료들이 나오는 것을 확인할 수 있습니다. 인간은 눈에 들어 온 빛만을 인지할 수 있기 때문에 당연한 것이겠죠. 그만큼 중요하며 대부분의 쉐이딩( shading ) 이론들이 이 휘도와 관련이 있습니다.

휘도는 다음과 같이 정의됩니다.

휘도는 특정 방향으로 이동하는 단위 면적당 광도( luminous intensity )를 측정한 것입니다. 그것은 특정 영역에서 방출되거나 반사되어 주어진 입체각 안에 들어 온 빛의 양을 의미합니다. 휘도의 국제 단위는 제곱미터 당 칸델라( candela per square meter( cd/m2 ) )입니다.

뭐 어렵게 써 놨지만 그냥 그림2 처럼 눈에 들어 온 빛의 양을 측정하는 것입니다. 개념 설명을 위주로 할 것이기 때문에 여기에서 공식은 자제하겠습니다. 사실 이 휘도라는 것은 매우 복잡하기 때문에 모델도 다양하고 여기에서 바로 다루기에는 어려운 부분이 있습니다. 앞으로의 재미로 남겨 두기로 하죠.

그림2. 특정 면적을 가진 표면에 대한 조도와 휘도.

거대 표면( macro-surfce )과 핀홀( pin-hole ) 카메라

지금까지 우리는 조도와 휘도를 이야기할 때 매우 큰 면적을 가진 표면과 큰 면적을 가진 눈을 중심으로 이야기했습니다. 하지만 그러한 관점에서 설명하면 이해하기가 어렵고 실제로 계산이 복잡해집니다. 그러므로 이쯤부터는 미세 표면과 핀홀 카메라를 중심으로 이야기를 하도록 하겠습니다.

만약 우리가 관심을 가지는 표면의 크기가 우리가 겨우 인지할 수 있을만한 점에 가깝다고 가정해 봅시다. 점에 가깝다는 것이 중요합니다. 완전히 점은 아닙니다. 이것을 거대 표면( macro surface )이라고 부르는데요, 여기에 이의가 있는 분들이 있을 수 있습니다. "Macro" 는 "거대한" 이라는 뜻인데, 점에 가깝다고 해 놓고서는 거대하다고 이야기하니 짜증나실테지만, 이는 "Micro" 와 대비되는 상대적인 개념입니다. 우리가 점처럼 보고 있는 면적보다도 더 눈에 잘 안 보이는 매우 작은 면적을 가진 표면을 미세 표면( micro surface 혹은 micro facet ) 이라 부르고 있기 때문에, 상대적으로 큰 것을 거대 표면이라 부른 것 뿐입니다.

PBR 이 도입되기 이전에는 거대 표면을 대상으로 라이팅을 계산했죠. 이에 대해서는 나중에 다루도록 하겠습니다. 어쨌든 앞으로 "점에 가까운 표면"을 그냥 "표면" 이라고 부르고 더 작은 표면을 "미세 표면" 이라고 부르도록 하겠습니다.

거대표면과 미세표면. 우리 눈에는 거대 표면마저 점처럼 보입니다. 출처 : [2].

그런 관점에서 보면 특정 표면에 들어 빛들의 각도차이가 거의 없으니 그냥 선처럼 보이겠죠. 그러면 조도와 휘도의 관계는 그림3 처럼 표현될 수 있습니다.

그림3. 점에 가까운 면적을 가진 표면에 대한 조도와 휘도.

여기서 말하고자 하는 것은 무엇일까요? 휘도가 관심을 가지는 것은 오직 눈에 들어 온 빛의 양이라는 점입니다. 그림2 의 관점에서 바라보든 그림3 의 관점에서 바라보든 차이는 없습니다. 그림2 같은 경우에는 그림3 보다 더 많은 점들을 대상으로 하고 있는 것일 뿐이죠. 사실 그래픽스 영역에서는 그림3 의 관점을 가지고 조도와 휘도 관계를 계산하는 것이 좀 더 편하긴 합니다.

하지만 아직도 복잡합니다. 눈이 면적을 가지고 있다고 가정하고 있기 때문에 들어 오는 빛을 계산하기도 힘들죠. 그래서 대부분의 실시간 그래픽스에서는 바늘구멍 카메라 모델을 사용합니다. 그림4 처럼 눈에 면적이 있는 것으로 보는 것이 아니라 그냥 점으로된 구멍이 있는 것처럼 생각하는 것입니다. 

그림4. 핀홀 카메라 모델. 출처 : Pinhole camera(DIY/homemade).

그러므로 모든 빛은 한점에 수렴한다고 가정하죠. 이 경우, 눈으로 들어 온 빛들의 각도 차이가 거의 없으므로 선에 가깝게 표현되겠죠. 그러면 조도와 휘도는 그림5 의 관점에서 설명됩니다.

그림5. 점에 가까운 면적을 가진 표면과 점에 가까운 면적을 가진 눈에 대한 조도와 휘도.

우리가 보통 실시간 그래픽스 이론에서 보고 있는 눈, 표면, 빛의 관계는 그림5 의 표현에 가깝습니다.

왜 조도와 휘도를 구분하나요

어떤 표면에 들어 온 빛은 사람의 눈에 모두 들어 오지 않습니다. 왜냐 모든 표면은 빛을 흡수( Absorbtion ), 반사( Reflection ), 투과( Transmission )시키기 때문이죠. 게다가 이 반사 성분은 확산반사( diffuse reflection ) 성분과 정반사( specular reflection, 거울면 반사 ) 성분으로 나뉩니다.

출처 : Waves, KaiserScience.

이 중에서 사람의 눈에 들어 올 수 있는 성분은 반사와 투과입니다. 그리고 우리가 앞으로 다루게될 모든 렌더링 이론들은 대부분 이 두가지 성분과 관련이 있습니다. Albedo( 표면 반사율 ), BRDF( Bidriectional Reflectance Distribution Function, 양방향 반사도 분산 함수 ), BTDF( Bidirectional Transmittance Distribution Function, 양방향 투과도 분산 함수 ) 등은 그림6 처럼 표면에 들어 온 빛이 얼마나 반사되고 투과되는지를 함수로서 표현한 것들입니다.

그림6. BRDF 와 BTDF. 출처 : [3].

그리에서 여기에서 산란( Scattering )이라는 용어가 나오는 것이 약간 불편한 분들이 있을 것 같아서 부가설명을 하자면, 산란이라는 것은 쉽게 이야기하면 전자기파가 모종의 이유로 자신의 방향으로 가지 못하고 다른 방향으로 가는 현상을 의미합니다. 반사와 투과 등의 모든 개념을 파동 관점에서 설명한 것이죠. 자세한 것은 시리즈의 뒷 부분에서 자세히 설명하도록 하겠습니다.

정리

표면에 들어 온 빛( 조도 )은 전부 눈( 휘도 )으로 들어 오지 않습니다. 그 이유는 표면이 빛을 흡수, 반사, 투과시키기 때문입니다. 사람이 눈으로 볼 수 있는 빛은 반사되거나 투과된 빛들입니다. 얼마만큼의 빛이 반사되고 투과되었는지를 결정하는 함수들이 Albedo, BRDF, BTDF 입니다. 대부분의 렌더링 이론들은 이와 관련이 있습니다.

지금까지는 빛과 그것의 양을 계산하는 것과 관련한 기본 개념 및 용어들을 설명하느라 시간을 보냈습니다. 마치 활용할 데가 없는 수학 공식을 배우듯이 지루하셨을거라 생각을 하지만, 이러한 용어들은 앞으로 자주 반복해서 나올 것이기 때문에 글을 읽느라 보낸 시간이 아깝지는 않을 것이라 기대해 봅니다. 

다음 시간부터는 본격적으로 PBR 에 대한 이야기를 풀어 나가보려고 합니다. 가급적이면 실제 예제들을 중심으로 렌더링 결과를 비교한다든가 하는 식으로 진행하려고 생각하고 있습니다.

참고 자료

[1] Luminance, Wikipedia.

[2] Microfacet Modles for Refraction through Roufh Surfaces, Bruce Walter, Stephen R. Marschner, Hongsong Li, Kenneth E. Terroance.

[3] Bidirectional scattering distribution function, Wikipedia.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 5. 조도( illuminance ) 측정

조도

오늘은 조도에 대해 이야기하고자 합니다. 여러분은 [ 2. 조도와 휘도 ] 에서 조도와 휘도의 개념에 대해 공부했습니다. 여기에서는 조도와 휘도를 어떻게 측정하는지에 대해서 다루도록 하겠습니다. 하지만 수학적인 계산보다는 단위와 개념을 이해할 수 있도록 하는데 치중했기 때문에, 이를 구현하고자 하는 사람에게는 좀 부족한 글이 될 수 있습니다.

조도( illuminance )라는 것은 조명이 비추는( illuminate ) 빛이 얼마나 표면( surface )에 도달하느냐를 측정한 값입니다.

이를 광속 개념을 통해 정의하면 다음과 같습니다.

조도는 단위 면적( 제곱미터, m2 )당 광속( luminous flux )입니다. 이는 입사광이 표면을 얼마만큼 비추고 있는지를 측정하는 것입니다[1].

( [ 4. 광원의 밝기( 광속 ) ] 에서 광속( luminous flux, luminous power )은 광원이 방출하는 전체 빛의 양이라고 했습니다. )

말이 좀 어렵나요? 이럴땐 그림을 봅시다.

어떤 표면이 있고 거기에 빛을 비춘다고 해 봅시다. 그러면, 그림1 에서 보이듯이, 그 표면의 1m2 내에 들어 온 빛의 양이 조도이며, 그것을 1 럭스( lux, lx )라고 합니다.

림1. 조도. 단위 면적당 광도.

광속의 단위는 루멘( lumen, lm )이고 단위 면적은 제곱미터( square meter, m2 )이므로 럭스는 다음과 같이 계산됩니다.

식1. 럭스 계산.

조도와 거리( 감쇠 )

그런데 눈치가 빠르신 분들은 뭔가 문제가 있다는 것을 깨달으셨을 겁니다. 실세계에서는 빛과 광원간의 관계가 위의 그림에 있는 것처럼 편리하게 빛과 1 미터 떨어져서 존재하는 것이 아닙니다.

우리는 [ 3. 빛의 감쇠 ] 에서 빛의 양은 거리가 멀어질 수록 감쇠하게 되어 있으며, 1 / distance2 의 비율로 감쇠한다고 배웠습니다. 

그렇기 때문에 조도를 계산할 때는 거리를 고려해야 합니다.

구의 중심이 광원이라고 가정해 봅시다. 반지름이 r 일 때 r2 만큼의 겉면적을 커버하는 원뿔형의 입체각을 1 스테라디안이라 한다고 했습니다. 여기에서 r 을 오브젝트와의 거리라고 가정해 봅시다. 그리고 오브젝트의 면의 방향( 노멀, normal )은 구의 중심을 바라보고 있다고 가정해 봅시다.

만약 r 이 1 m이라면 면적은 1 m2 이고 식1 에서 나온 것과 같은 결과를 냅니다. 하지만 r 의 값이 1 보다 커질수록 r2  만큼 넓은 면적을 커버해야 하며 1 / r2 만큼 받는 빛이 약해지겠죠. 반대로 r 이 1보다 작아지면 더 좁은 면적을 커버해야 하며 빛이 강해지겠죠. 이를 좀 더 쉽게 이해할 수 있도록 그림2 에 평면도로 표현해 보았습니다.

그림2. 거리에 따른 조도의 변화. 중간의 면( 붉은색 )은 빛과 1 스테라디안의 입체각을 이룸.

그림2 를 보면서 좀 헷갈리는 사람이 있을 수 있습니다. 가장 좌측의 입체각이 크고, 가장 우측의 입체각이 작습니다. 1스테라디안당 N 개의 광자를 쏘았다고 하면, 가장 좌측은 N 개보다 많은 광자를 받았고, 가장 우측은 N 개보다 적은 광자를 받은 것입니다.

조도와 기울기

눈치가 빠른 분들은 다른 문제도 있다는 것을 깨달았을 것입니다. 실세계에서는 면이 광원을 마주보고 있는 경우가 거의 없습니다.

조도를 계산할 때 고려해야 할 다른 부분은 면의 기울기입니다. 면적이 같은 두 개의 평면이 존재할 때, 하나는 면의 노멀이 빛 방향과 수직이고, 다른 하나는 수직이 아니라고 합시다. 이 경우 수직이 아닌 면은 그림3 처럼 빛을 덜 받게 됩니다.

그림3. 기울기에 따른 조도의 변화.

이러한 기울기에 따른 차이를 고려해서 조도의 양을 계산하는 것이 램버트 코사인 법칙( Lambert's Cosine Law )입니다.

그림4. 램버트 코사인 법칙. 출처 : Lambert's Cosine Law, Ocean Optics.

사실은 이 코사인 법칙을 증명( ? )하려 했는데, 너무 어려운 글이 될 것 같아서 생략했습니다. 가능한한 쉽게 쓰려고 하는데 자꾸 프로그래머 본능이 꿈틀대네요.

정리

조도라는 것은 표면에 들어 온 빛의 양을 의미합니다. 이것을 시리즈의 앞 부분에서 언급한 광도측정 단위들을 사용하면, "단위 면적당 광속"이라고 표현할 수 있습니다. 이 조도의 단위는 럭스( lux )이며 lux 혹은 lx 로 표기합니다.

조도는 면과 광원의 거리 및 기울기에 영향을 받습니다. 거리에 의한 영향은 빛의 감쇠 공식에 의해 계산되며, 기울기에 의한 영향은 램버트 코사인 법칙에 의해 계산됩니다.

참고로 태양빛의 경우에는 거리에 의해 감쇠되지 않는다고 가정합니다. 모든 빛이 평행하게 들어오고 있다고 가정하기 때문이죠. 다시 말씀드리지만 거리가 멀어졌을 때 감쇠되는 것은 커버해야 할 면적이 늘어나기 때문이지 단순히 거리가 늘어났기 때문이 아닙니다. 태양빛은 평행하다는 가정을 깔아 버리면, 거리가 멀어지더라도 커버해야 할 면적에 변화가 없기 때문에 감쇠가 되지 않는 것입니다.

참고자료

[1] Illuminance, Wikipedia.

 

잘못된 내용이 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 4. 광원의 밝기( 광속 )

개요

3. 빛의 감쇠 ] 에서는 좀 지루한 수학과 기하에 대해서 이야기했습니다. 거리, 호도( radian, 단위 : rad ), 입체각( solid angle, steradian, 단위 : sr ) 등에 대해서 이야기한 것은 바로 오늘의 주제인 빛의 측정단위에 대해서 이야기하기 위함이었습니다.

노파심에 다시 이야기하지만 우리는 방사측정( radiometry )가 아니라 광도측정( photometry )의 관점에서 빛을 측정하는 단위에 대해서 이야기할 것입니다. 광도측정은 빛을 구성하는 다양한 파장 중에서 가시 파장에 대해서 다루는 측정방법입니다.

지금부터는 약간의 수식이 나올 수 있습니다. 하지만 원리를 이해한다면 크게 어렵지 않을 것이라 생각합니다. 이해가 안 가면 질문을 주세요. 모르는 것이 부끄러운게 아닙니다. 알려고 하지 않는 것이 부끄러운거죠. 지금은 어렵게 느껴지지만 가면 갈수록 익숙해질 것이고, 지금 고민하고 공부한 것들이 나중에는 큰 차이를 만들어낼 것입니다.

광선속( 광속, Luminous Flux, Luminous Power )

광선속( 光線束 ) 혹은 광속( 光束 )이라는 것은 속도를 의미하는 것이 아닙니다. 빛 광( 光 )과 묶을 속( 束 )입니다. 말 그대로 빛다발이죠. 빛의 속도를 의미하는 광속( 光速 )이 아닙니다. 요새는 사람들이 한자를 잘 모르니 영어로 표현하면, luminous 는 "빛나는" 이란 뜻이고 flux 는 "흐름" 이라는 뜻입니다.

일단 단어의 구성은 그렇구요, 광속이란 단위시간에 광원에서 나오는 빛( 가시광선 )의 총량입니다. Radiometry 관점에서 보면 Radiant Flux( 방사속 ) 라는 용어가 이에 대응됩니다.

그림1. 광속은 광원에서 나오는 빛의 총량입니다. 출처 : Watts, Lumens, Candles and Lux.

여러분이 어떤 조명을 보고 "저 조명의 밝기는 XX 입니다" 라고 말할 때 사용하는 것이 바로 광속입니다. 단위는 루멘( lumen )이죠. 루멘은 라틴어로 빛이라는 뜻이며, 기호로는 lm 을 사용합니다.

요즘 조명기구 회사에서는 밝기를 표기할 때 루멘( lm )으로 표기합니다. 기존에는 와트( 일률, W ) 단위를 많이 표기했는데, 와트는 에너지를 얼마나 소비하느냐를 의미하는 것이지 얼마나 밝냐를 의미하는 것이 아니기 때문입니다.

조명 회사의 LED 제품 소개의 예. 출처 : CREE.

그렇다면 루멘은 어떻게 결정되는 것일까요? ( 이것과 관련한 글이 없어서 저의 추측으로 소설을 써 봤습니다. )

우리는 아주 옛날부터 초( candle )라는 것을 사용해서 빛을 비춰왔습니다. 그래서 과학자들은 촛불을 기준으로 해서 빛의 밝기를 측정하려고 한 것 같습니다. 이러한 관점에서 보면 촛불이 방출하는 전체 빛의 양을 1 루멘이라고 하는 것이 편리하겠죠.

하지만 LED 처럼 빛이 방출되지 않는 영역이 존재하는 경우도 있습니다. 게다가 일반적으로 측정기를 광원을 완벽하게 둘러싼 형태로 만들어내기가 어렵습니다. 보통 한 방향에서 일정 영역만큼을 측정한 값을 가지고 전체 결과를 추정하는 경우가 많죠. 그렇기 때문에 촛불의 빛의 양을 1 루멘이라고 하면, 다른 광원들의 빛의 양을 측정하기가 조금 곤란할 것입니다.

뭔가 기준이 되는 단위가 필요했을 것이고, 1 sr( 스테라디안을 ) 기준으로 삼았을 것입니다.

만약 1 sr 만큼의 입체각으로 방출되는 빛의 양을 알게 된다면, 빛을 비추지 않는 영역은 배제하고 빛을 비추는 영역만을 모아서 빛의 양을 수집하는 것이 쉽겠죠.

[2]에서는 광도( luminous intensity )를 다음과 같이 정의하고 있죠.

광도는 점 광원에서 특정 방향으로 단위 입체각( solid angle, 1 스테라디안 )당 방출되는 광속( luminous power )입니다. 광도의 단위는 칸델라( candela, cd )입니다.

그림3. 광도( luminous 칸델라. 출처 : Watts, Lumens, Candles and Lux.

이를 수식으로 표현하면 식1 과 같습니다. 여기에서 광도를 X, 광속을 Y, 빛을 방출하는 전체 입체각을 Z 라 하겠습니다 :

식1. 칸델라의 정의. 1 스테라디안당 광속.

점광원 같은 경우에는 전방향으로 빛을 방출하기 때문에 단위 입체각은 1/4pi 가 됩니다( 단위구의 최대입체각이 4pi 입니다 ). 그러므로 점광원에서 광도( 칸델라 )를 구하는 식은 식2 와 같습니다.

식2. 점광원에서의 광도 계산.

광속( 루멘 )은 다음과 같이 정의됩니다.

식3. 루멘의 정의. 광도 X 입체각.

만약 점광원이라면 그것의 광속은 다음과 같이 계산되는 거죠.

식4. 점광원에서의 광속 계산.

뭔가 순환논리같다는 생각이 듭니다. 여기에서 엄청나게 헷갈리는거죠. 광속은 칸델라를 사용해서 정의되는데, 칸델라는 광속을 사용해 정의됩니다.

이에 대한 자료는 지금까지 찾지 못했는데요... 그래서 그냥 소설을 써 보겠습니다( 제 친구 햄짱과 같이 쓴 소설입니다 ).

과학자들은 처음에 촛불을 1 루멘이라고 불렀다가, 위에서 언급했던 것처럼 전방향으로 빛을 방출하지 않는 광원이 나오면서, 전방향에서 방출한 빛의 양을 기준으로 삼는 것은 어렵다고 생각했을 것입니다. 그래서 특정방향으로 일정 범위( 단위 입체각 ) 안에서 방출되는 빛의 양을 기준으로 삼아야겠다는 생각을 했을 것입니다. 그리고 그것을 빛의 양을 측정하는 기본 단위인 광도( luminous intensity )라 정의했을 것입니다.

그런데 촛불의 광속이 1 루멘이라고 하면, 그것의 광도는 1 보다는 작은 소수점 아래 단위의 값이 될 것입니다( 구의 전방향을 커버하는 면적보다는 1 스테라디안이 커버하는 면적이 훨씬 적겠죠 ) . 이를 피하기 위해서 최소단위인 광도를 1 칸델라로 맞췄을 것이라고 생각합니다. 

머리가 아파 보이지만 1 칸델라는 국제 표준으로 정의된 빛의 양입니다. 1 리터( l )라든가 1 그램( g )이라든가 하는 정해져 있는 양입니다. 이제 칸텔라가 뭔지 알게 되었으니 초의 광속( 루멘 )을 계산해 보죠. 초가 전방향으로 빛을 방출한다고 하면, 그것의 입체각은 4π 스테라디안입니다( 반지름이 r 인 구의 겉면적이 4πr2 이고 1 스테라디안은 r2 만큼의 겉면적을 커버하는 입체각이므로 구의 전체 입체각이 4π 스테라디안이 되는 것입니다 ).

그러면 이제 촛불의 밝기( 광속 )를 계산해 볼까요?

식3. 촛불의 광속 계산.

실제로 촛불 하나의 광속은 12.57 루멘입니다.

정리

특정 방향으로 1 스테라디안 영역에서 방출된 촛불의 빛의 양을 광도( luminous intensity )라 하면 단위는 칸델라( candela, cd )입니다.  1 스테라디안( steradian, sr ) 범위에서 방출된 칸델라를 루멘( lumen, lm )이라 합니다. 루멘을 사용해 광원의 전체 빛의 양을 측정한 것을 광속( luminous flux, luminous power )이라 합니다.

참고자료

[1] Lumious flux, Wikipedia.

[2] Candela, Wikipedia.

주의 : 잘못된 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 3. 빛의 감쇠

개요

시리즈의 3 번째입니다. 지난번에 [ 2. 조도와 휘도 ] 에서 방사측정( Radiometry )과 광도측정( Photometry )의 차이에 대해 언급했습니다. 기억이 잘 안 나시는 분들을 위해 복습하자면 방사측정은 빛의 모든 파장 영역의 에너지( power )를 측정하는 것이고, 광도측정은 빛의 가시 파장 영역이 밝기( brightness )를 측정하는 것입니다.

그런데 모든 물리단위들은 기준이라는 것이 있어야 합니다. 우리가 물리기반( Physically-based )를 이야기하고 있으니, 당연히 물리적으로 납득할 수 있는 기준과 단위들이 필요하겠죠.

UE4 엔진의 경우에는 포인트/스포트 라이트의 세기를 설정하는 기준 단위가 루멘( lumen )이라고 이야기하고 있습니다[1]. 세기( intensity )를 밝기( brightness )라고 표현하기도 합니다.

그림1. UE4 에서의 빛의 세기를 설정하는 속성. 루멘단위.

요새 다른 PBR 엔진들도 루멘을 사용하는 추세이죠. 이렇게 된 이유는 광원의 세기를 아티스트의 기분에 따라 설정하지 말고 어떤 기준을 잡고 설정하라는 의미일 것입니다. 그래서 아티스트들이 루멘이 무엇인지 이해할 필요가 있습니다. 루멘이 무엇인지 이해하는 것은 빛에 대해서 더 깊게 이해할 수 있는 기반을 제공할 것입니다.

이 문서에서는 어떤 조명( 광원 )의 광속( luminous flux ), 광도( luminance intensity ), 조도( illuminance ), 휘도( luminance )가 어떤 의미인지 이해하기 위한 선행학습 과정에 대해 다룰 것입니다. 여기에서부터는 약간의 기하와 산수가 나오기 때문에 조금 짜증나실 수는 있습니다. 하지만 여러분은 이 개념들에 대해서 무작정 외우려고 하실 필요는 없습니다, 어떤 원리인지를 이해하고 단위만 잘 기억하시면 됩니다.

그렇게 어려운 내용은 아니니 차분히 읽어 보시면 이해하실 수 있을 거라 생각합니다.

빛은 왜 감쇠할까요?

일반적으로 우리는 빛이 감쇠( attenuation )한다고 알고 있습니다. 강한 빛도 멀리 갈 수록 약해집니다. 여기에서 주의하실 점은 감쇄( reduction )가 아니라 감쇠( attenuation )라는 것입니다. 감쇠는 힘이나 세력이 약해짐을 의미하고, 감쇄는 힘이나 세력이 약해져서 최종적으로는 없어짐을 의미합니다. 지금은 왜 뜬금없이 차이를 이야기할까 싶으시겠지만 뒤에 좀더 설명을 할 것입니다.

빛이라는 것은 전자기파들의 조합이기는 하지만( 파동성 ), 어떤 경우에는 입자들처럼 보일 때가 있습니다( 입자성 ). 입자처럼 보일 때의 빛을 광자( photon, 포톤 )라고 합니다. 그냥 그러려니 하시면 됩니다. 여기에서 더 들어 가면 저도 잘 모르는 양자론에 대해 주절거려야 하기 때문에 더 나아가지는 않겠습니다. 대신에 빛이라는 것을 대충 이런 식으로 이해하시면 됩니다( 정확하지는 않지만 그러려니 하십시오 ).

그림2. 광자의 느낌? 여러개의 전자기파의 묶음을 입자의 관점에서 볼 때 광자라 부릅니다.

어쨌든 광자의 개념에서 빛이 발산하는 모습을 생각해 봅시다.

진공상태라고 가정하면 다른 입자( 먼지, 대기중의 분자들 )들에 의한 산란( 투과, 흡수, 반사 )이 발생하지 않습니다. 그러므로 눈에 들어 오기 전까지는 영원히 직진하겠죠.

그림3. 진공상태에서의 광자의 이동.

눈치가 빠르신 분들은 이 시점에서 한 가지 의문을 가지게 될 겁니다; "그럼 왜 거리가 멀어지면 빛이 감쇠하나요?".

우리는 태양광에 대해서는 평행하게 빛이 도달한다고 생각합니다.

그림4. 태양에서 오는 빛은 평행하다고 가정합니다.

이것이 사실일까요? 그렇지 않습니다. 태양과의 거리는 엄청나게 멀기 때문에 지구에서 사는 사람의 입장에서는 상대적으로 빛이 평행하게 오는 것처럼 느껴질 뿐입니다( 그림5 참조 ). 단지 그래픽스 영역에서는 그 차이가 무시할 수 있을 정도로 의미가 없을 뿐이죠.

그림5. 같은 크기를 가진 물체가 광원에서 멀어졌을 때의 들어 오는 빛들의 각도차이의 변화.

자, 그럼 여러분은 이제 포인트/스포트 라이트와 태양광과의 차이를 아실 수 있습니다. 그냥 거리의 차이입니다. 빛을 받는 오브젝트들의 거리가 너무 가깝기 때문에 각도의 차이가 커집니다. 태양광의 경우에는 엄청나게 많은 광자를 내 뿜고 있으며 태양과 지구와의 거리가 너무 멀기 때문에 거의 평행하게 광자들이 도달합니다. 그래서 우리는 태양광에 대해서 따로 감쇠 거리를 설정하지 않는 것입니다. 하지만 포인트/스포트 라이트들은 내뿜는 광자의 개수가 상대적으로 적으며 가까운 오브젝트가 가까운 거리에서 빛을 받기 때문에 감쇠 거리라는 것이 중요해진 것입니다.

그런데 이 각도가 감쇠라는 것과는 무슨 상관일까요?

세상이 2차원의 평면이고 광원이 점광원이라고 가정합시다. 이 광원은 16 개의 광자를 내뿜을 수 있는 능력을 가졌는데, 광자의 속도가 초당 1 m 라고 가정합시다( 그냥 가정입니다. 광자의 속도는 빛의 속도입니다 ). 1 초 단위로 깜박인다고 가정해 봅시다. 그러면 모든 방향으로 빛을 내 뿜겠죠? 2초 뒤에 광자의 위치는 어떻게 될까요? 시간의 추이에 따라 어떻게 변하는지 그림6 에서 설명하고 있습니다.

그림6. 시간의 변화에 따른 광자의 위치. 2초후에 보면 처음 발사한 광자들은 2 m 를 이동했고, 두번째로 발사한 광자들은 1m 를 이동했습니다.

여러분은 그림6 을 보고 어떤 생각을 하셨나요?

광원으로부터의 거리가 멀어질 수록, 광자끼리의 거리도 멀어집니다. 결국 같은 각도 내에 존재하는 광자의 개수는 동일하지만, 그것이 커버해야 하는 면적이 넓어졌습니다. 이것을 3D 관점에서 보면 그림7 과 같은 느낌이 됩니다.

그림7. 3D 에서 빛의 감쇠. 출처 : [2].

r 의 거리에서 한칸에 해당하는 면적에 광자가 3( = 3/1 ) 개가 있었다면, 2r 의 거리에서는 에서는 한칸에 평균적으로 3/4 의 광자가 존재합니다. 물론 광자의 위치에 따라 3 개나 2 개가 있을 수 있겠죠. 그림7 에서는 2 개가 있는 것으로 나왔군요.  3r 의 거리에서는 한칸에 평균적으로 1/3( = 3/9 )의 광자가 존합니다. 그림7 에서는 1 개로 나왔구요. 그물을 잡아 당겨서 늘리면 구멍이 커지는 느낌으로 생각하시면 됩니다.

이렇게 면적당 광자의 개수관계를 생각하면, 거리에 따라 빛의 밝기가 감쇠하는 것과 관련한 공식을 다음과 같이 쓸 수 있습니다. 일단 여기에서는 광자 1 개당 세기를 1 이라고 가정했습니다.

식1. 거리에 따른 빛의 세기의 감쇠. 거리의 제곱에 반비례합니다.

수학을 좀( ? ) 배우신 아티스트들은 이 공식을 보면서 의문을 가지게 될 것입니다; "언제 빛의 세기가 0 이 되나요?".

Distance 가 무한대가 되더라도 0 에 수렴할 뿐 0 이 되지는 않습니다. 즉 거리가 멀어질 수록 세기가 기하급수적으로 낮아지기는 하지만 아예 영향력이 없는 것은 아니라는 것이죠. 그러므로 대부분의 엔진들의 광원에는 UE4 에서와 같은 "Attenuation Radius( 감쇄 반경 )" 라는 속성이 있습니다[1]. 광원의 영향력을 모든 오브젝트에 반영한다는 것은 현실적으로 힘들기 때문입니다( 라이팅 계산이 무겁기 때문에 현재 하드웨어에서는 힘듭니다 ). 게다가 인간의 눈은 성능이 별로( ? ) 안 좋기 때문에 0 에 가까운 밝기를 인지하지 못합니다. 계산해 봐야 크게 의미가 없는 것입니다. 그래서 아티스트가 보기에 이 정도까지만 라이팅을 처리해도 괜찮겠다 싶은 거리를 지정하게 하는 것입니다. 쓸데없이 거리를 길게 잡게 된다면, 눈에는 거의 안 보이는데 처리를 해야 해서 계산비용이 늘어나겠죠.

예전에는 감쇠를 위해서 "Light Radius" 혹은 "Source Radius" 라는 용어를 사용했지만, area light 라는 개념이 나오면서 "source radius" 는 광원 자체의 반지름을 의미하는 것으로 바뀌었습니다. 그러므로 "Attenuation Radius" 와 "Source Radius" 를 혼동하지 마시기 바랍니다.

감쇠는 어떻게 계산된 것인가요?

앞에서 감쇠된 빛의 세기는 거리의 제곱에 반비례한다는 결론을 냈습니다. 물론 그림7 에서 볼 수 있듯이 거리가 1r 일 때 1칸, 2r 일때 4 칸, 3r 일때 9 칸, 이런 식으로 하면 거리의 제곱에 반비례한다는 사실이 유추되기는 합니다. 하지만 그림7 은 단순화해서 표현한 것일 뿐입니다.

이것이 어떻게 유도되었는지를 명확하게 이해해야 앞으로 나올 개념들을 이해하는데 도움이 됩니다. 이를 위해서는 입체각( solid angle )이라는 개념에 대해 먼저 알아야 합니다.

호도법

입체각에 대해 알려면 호도법에 대해 먼저 이해하는 것이 편합니다. 입체각이라는 것은 3차원에서의 각을 표현하는 것이기 때문에 2차원에서의 각인 호도법을 살펴 봄으로써 좀 더 쉽게 이해할 수 있기 때문입니다.

사람들은 평면에서 각을 표현할 때 도( degree )라는 단위를 선호합니다. 그래서 아티스트가 접하게 되는 대부분의 단위는 도 단위로 표현이 됩니다. 하지만 수학적인 영역으로 들어 가면 도 단위보다는 호도( radian ) 단위를 선호합니다. 매우 직관적이고 편하기 때문입니다.

여러분은 학교에서 반지름( radius )이 1 인 원의 둘레는 2π( pi, 파이 ) 라고 배우셨을 겁니다. π 는 순환하지 않는 무한소수로 원주율이라고 불립니다. 그 값인 3.1415926... 을 열심히 외우셨을테구요. 이때 질문이 들어갑니다. 각도가 a° 일 때 만들어지는 부채꼴의 호의 길이( arc length )는 얼마일까요?

그림8. 반지름 1인 원에서 각도가 a 도일 때의 부채꼴의 호의 길이는?

360 도일 때 원의 둘레가 2π 였기 때문에 비례식을 쓰면 a 도일때의 부채꼴의 호의 길이를 알 수 있죠.

식2. 반지름 1인 원에서 a 도인 부채꼴의 호의 길이 x 구하기.

좀 더 응용해 봅시다. 반지름이 r 일 때는 원의 둘레가 2πr 입니다. a 도일때의 부채꼴의 호의 길이는 무엇일까요? 식2 에서처럼 비례식을 사용해 값을 구할 수 있습니다.

식3. 반지름이 r 인 원에서 a 도인 부채꼴의 호의 길이 x 구하기. 

반대로 해 봅시다. 반지름 r 인 원에서 부채꼴의 호의 길이가 x 일 때 부채꼴의 각은 몇 도인가요? 식2, 3 에서 처럼 비례식을 써서 구할 수 있습니다.

식4. 반지름이 r 인 원에서 호의 길이가 x 인 부채꼴의 각 a 구하기. 

뭔가 숫자를 외워야 하고 나눗셈이 들어갑니다. 이건 매우 귀찮은 작업이며 실수의 여지가 있습니다. 그래서 수학자들은 이를 쉽게 할 수 있는 방법을 찾게 되었고, 호도법이라는 것이 나오게 되었습니다( 1714 년에 Roger Cotes 라는 사람이 호의 길이를 각처럼 사용하자는 제안했다고 합니다[3] ). 호도법이라는 것은 반지름이 r 일 때 부채꼴의 호의 길이가 r 인 경우를 1 라디안( radian )이라고 표현하는 것입니다. 즉 각의 크기를 도에서 길이의 단위로 바꿔버리는 겁니다( 그림9 참조 ).

그림9. 반지름이 r 인 부채꼴의 호의 길이가 r 일 경우 각도를 1 라디안이라 합니다.

여기가 바로 질문이 나올 타이밍입니다; "대체 뭐가 편한데요?".

우리는 반지름이 r 인 원의 둘레가 2πr 이라는 것을 알고 있습니다. 반지름이 r 인 부채꼴( 반원 )의 호의 길이는 πr 이죠. 이 때의 각은 π 입니다( 그림10 참조 ).

그림10. 반지름 r 인 ( 그리고 각이 π 인 ) 반원의 호의 길이는 πr 입니다.

관계가 명확하게 보이시나요? 만약 반지름이 r 인 부채꼴의 각도가 a 라디안이라고 하면, 그것의 호의 길이는 ar 인 것입니다( 그림11 참조 ).

식5. 반지름이 r 이고 각이 a 인 부채꼴의 호의 길이 x 구하기.

그림11. 반지름이 r 이고 부채꼴의 각이 a 라디안이면, 호의 길이는 ar 입니다.

뭔가 복잡하게 변환할 필요가 없습니다. 각과 반지름 알면 호의 길이를 알 수 있고, 각과 호의 길이를 알면 반지름을 구할 수 있고, 반지름과 호의 길이를 알면 각을 구할 수 있습니다. 매우 직관적이고 계산이 단순해집니다.

3차원에서의 각

평면에서의 각은 라디안이라는 단위를 사용해서 쉽게 표현할 수 있다는 것을 알게 되었습니다. 하지만 3 차원에서의 각도는 어떻게 표현해야 할까요?

애초에 우리는 각이라는 것을 평면에서만 사용해 왔습니다. 삼차원에서 10 도라는 개념이 상상이 되시나요?

그림12. 3차원에서 10도를 상상해 봅시다.

3D 에 익숙하신 분들이라면 이를 경도와 위도처럼 나누어서 생각하실 수 있을겁니다. 그림13 처럼 중심이 되는 방향( 벡터 )를 기준으로 수평으로 몇도 수직으로 몇도 이렇게 나눌 수 있겠죠( 물론 다른 표현들도 존재합니다만, 머리만 복잡해지므로 여기에서 굳이 다루지는 않겠습니다 ).

그림13. 3차원에서의 각을 수직각과 수평각으로 나누어서 생각할 수 있습니다.

하지만 수학자들은 호도법을 발명했듯이 입체각( solid angle )이라는 것을 발명하게 되었습니다[4]. 반지름이 r 인 구에서, 면적이 r2 인 면적을 포함하는 원뿔형의 각을 1 스테라디안( steradian, sr )이라고 부르고, 이러한 각도를 입체각이라 정의한 것입니다( 그림14 참조 ).

그림14. 반지름이 r 인 구에서 r2 인 면적을 포함하는 원뿔형의 입체각을 1 스테라디안이라 부릅니다. 출처 : [4]. 

그럼 여기에서 또 뭔가 룰이 보이시나요? 호도법이 호의 길이를 각으로 치환했듯이, 입체각은 겉넓이( 면적 )를 각으로 치환한 것입니다. 호도법에서는 1차원적인 곱인 "호의길이 X 반지름" 으로 표현되듯이, 입체각은 2차원적인 곱인 "겉면적 X 반지름의 제곱" 으로 표현되고 있습니다.

우리는 구의 겉면적을 4πr2 로 알고 있습니다. r2 이 1 스테라디안을 의미하므로 구 전체의 입체각은 4π 인 것입니다.

만약 반지름이 r 인 구에서 입체각이 a sr( 스테라디안 )인 원뿔형의 겉면적을 구해야 한다면 다음과 같은 관계로 표현될 수 있습니다.

식6. 반지름이 r 인 구에서 입체각이 a sr 일 때 원뿔형의 겉면적 x 구하기.

호도법처럼 매우 단순하게 표현되는 것을 알 수 있습니다.

빛이 거리의 제곱에 반비례해 감쇠하는 이유

반지름이 r 인 구에서 입체각 a 인 원뿔형의 겉면적이 ar2 이라는 사실을 알게 되었습니다. 만약 r 값이 늘어난다고 해도 a 는 각이기 때문에 변하지 않습니다. 어떤 광원이  a 라는 입체각 내에 광자를 1 개를 내 보낸다고 가정해 봅시다. 그리고 그것의 밝기를 1 이라고 하죠. 1초가 지났을 때의 반지름은 1 이고 r 초가 지났을 때 반지름은 r 이겠죠. 그렇다면 각각의 겉면적은 a ( = a X 12 ) 과 ar2 입니다. 겉면적의 비율은 1 : r이 됩니다.

면적이 r2 만큼 늘었으니, 광자가 커버해야 하는 영역은 더 넓어지며, 밝기는 반대로 1 / r2 에 비례하는 것입니다.

정리

빛이 감쇠하는 것은 엄밀히 말해 거리가 멀기 때문이 아닙니다. 거리가 멀어질 수록 면적에 비해 광자의 개수가 줄어들기 때문이죠. 거리에 따라 면적이 얼마나 커지느냐는 입체각의 정의를 통해 알 수 있습니다.

참고자료

[1] 라이팅 기초, Unreal Engine Documents.

[2] Light Attenuation, Technical Grahic Director.

[3] Radian, Wikipedia.

[4] Solid Angle, Wikipedia.

주의 : 정확하지 않은 내용이 포함되어 있을 수 있으므로 이상하면 참고자료를 확인하세요.


[ PBR 이란 무엇인가 ] 2. 조도와 휘도

개요

[ PBR 이란 무엇인가 ] 에 대한 두 번째 주제인 [ 조도와 휘도 ] 에 대해서 설명합니다. 그래픽스에 관심을 가지고 계신 분들은 "radiance", "irradiance", "luminance", "illuminance" 라는 용어들에 대해 한 번쯤은 들어 보셨을 겁니다.

그런데 어떤 문서에서는 비슷한 현상을 설명하면서 radiance 라 하고 어떤 문서에서는 luminance 라고 합니다. 이 두 개의 차이를 인지하지 못하는 분들은 혼란에 빠지게되죠. 사전을 찾아 보면 다음과 같이 나옵니다.

    • Radiance : 복사 휘도.
    • Irradiance : 복사 조도.
    • Luminance : 휘도
    • Illuminance : 조도.

이것만 보고 의미의 차이를 이해할 수 있는 분은 많지 않을거라 생각합니다. 이 문서에서는 이러한 용어들의 차이에 대해서 명확하게 정리해 보고자 합니다.

방사측정( Radiometry ) 과 광도측정( Photometry )

우리는  [ 인간과 빛 ] 문서에서 빛이 다양한 파장의 전자기파로 구성된다는 것을 알게되었습니다. 그런데 에너지가 입자나 파동의 형태로 전달되거나 방출되는 것을 방사선( radiation )이라고 합니다[1]. 즉 가시광선을 포함한 전체 파장 영역의 전자기파들로 구성된 빛을 방사선이라 부를 수 있는 것입니다.

넓은 의미에서( 전체영역 ) 빛을 다루기 위해서 에너지를 측정하는 것을 방사측정( radiometry )이라 합니다. 그리고 좁은 의미에서( 가시영역 ) 빛을 다루기 위해서 에너지를 측정하는 것을 광도측정( photometry )이라고 합니다. Visible-Radiometry 같은 용어가 아니라 Photometry 라는 용어를 사용한 것은 아마도 카메라를 통해 사진이 찍히는 과정이 인간의 눈을 통해 들어 온 빛을 인지하는 과정과 유사하기 때문이지 않을까 생각합니다.

어쨌든 방사측정에서는 제곱미터당 일률( watt per squre meter )의 단위로 에너지를 측정하고, 광도측정에서는 제곱미터당 루멘( lumens per squre meter, lux ) 단위로 에너지를 측정합니다. 쉽게 이해하자면 전자는 파워( power )를 의미하고 후자는 밝기( brightness )를 의미한다고 생각하시면 됩니다.

좀 지루하죠? 어쨌든 radiance, irradiance 는 방사측정에서 사용하는 용어이고, luminance, illuminance 는 광도측정에서 사용하는 용어입니다. 단지 어떤 영역의 파장들을 다루고 있느냐, 에너지를 어떤 관점에서 바라보느냐의 차이가 있을 뿐이죠. 그러므로 일반적으로 그래픽스에서는 radiance 를 luminance 로 irradiance 를 illuminance 로 대체해서 이해하셔도 무방합니다. 그래픽스에서는 빛을 photometry 의 관점에서 다루고 있기 때문에 큰 차이는 없습니다( 어차피 보이지도 않는 에너지에 대해 고민해 봐야 무슨 소용이 있겠습니까... ).

조도와 휘도

조도의 "조( 照 )"는 "비출 조" 입니다. 그리고 휘도의 "휘( 輝 )"는 "빛날 휘"입니다. 조는 능동적인 표현이고 휘는 수동적인 표현입니다. 빛을 생각할 때 광원에서 빛이 나오는 것을 "비춘다"라고 표현하고, 어딘가 부딪혀서 눈에 들어 오는 것을 "빛난다" 라고 표현하는 것입니다.

이것을 관점을 좀 다르게 해서 생각해 보면, 다음과 같이 표현할 수 있습니다.

물 표면에 들어온 빛의 양 X 를 조도( illuminance )라 하고 눈으로 들어 온 빛의 양 Y 를 휘도( luminance )라고 합니다. 여기에서 일루미넌스와 루미넌스가 헷갈릴 수 있습니다. 원래 Illuminate 라는 단어는 "비추다" 라는 뜻입니다. 그래서 어떤 면적에 빛을 비춘 양을 illuminance 라고 부르는 것입니다. 비슷한 느낌의 예를 들자면 GI( Global Illumination ) 가 있습니다. 이것을 우리말로 번역하면 "전역 조명" 정도로 정의할 수 있겠죠.

그런데 조도와 휘도를 구분하는 이유는 무엇일까요?

표면( surface )에 도달한 빛이 모두 관찰자의 눈으로 들어 오는 것은 아닙니다. 어떤 매질( 재질 )의 표면에 입사한( incident ) 빛은 흡수( absorbed )되거나 투과( tramsmitted )거나 반사( reflected )됩니다. 방출( emitted )되는 빛도 있지만 여기에서는 다루지 않겠습니다. 우리는 어떤 물체에서 반사된 빛만을 인지할 수 있는 것입니다. 그래서 조도와 휘도를 구분하는 것입니다.

출처 : Waves, KaiserScience.

참고자료

[1] Radiation, Wikipedia.

[2] Radiometry, Wikipedia.

[3] Photometry, Wikipedia.

 

 

주의 : 정확하지 않은 내용이 포함되어 있을 수 있습니다. 이상하면 참고자료를 확인해 보세요.


[ PBR 이란 무엇인가 ] 1. 인간과 빛

 

들어가며

술자리에서 직장 동료에게서 PBR 에 대해 PT 를 했으면 좋겠다는 이야기를 들었습니다. 그래서 프로그래머가 아닌 사람들이 PBR 에 대해 쉽게 이해할 수 있게 하는 방법이 무엇일까에 대한 고민을 해 보았습니다. 짧은 시간에 많은 내용을 전달하는 것은 힘들 것이라는 생각이 들었고, 너무 깊게는 아니지만 꼭 필요한 내용들에 대해서 설명하는 것으로부터 시작해야겠다는 생각이 들었습니다. 그래서 [ PBR 이란 무엇인가 ] 라는 글을 정리하기로 했습니다.

Physically Based Rendering( PBR ) 이라는 것은 "물리에 기반한 렌더링"이라는 의미입니다. 엄밀하게 이야기해서 현세대의 그래픽 하드웨어와 이론으로는 완벽하게 물리적으로 정확한 렌더링을 하는 것은 불가능합니다. 이진정보를 통해 자연현상을 완벽하게 표현한다는 것은 거의 불가능에 가깝습니다. 단지 기존보다는 "더욱" 물리적으로 정확하다는 의미라고 생각하시면 됩니다.

[1] 과 [2] 에 의하면 물리적으로 정확한 렌더링 모델이라는 것은 다음과 같은 요소들에 의해서 결정됩니다:

    • 전역 조명( Global Illumination ) : 이미지 기반 라이팅( Image Based Lighting, IBL ).
    • 에너지 보존 법칙( Energy Conservation ).
    • 반사도( Reflectivity ) : 디퓨즈 및 스펙큘러( Diffuse & Specular ).
    • 미세면( Microsurface ) : 러프니스( Roughness ).
    • 프레넬 법칙( Fresnel's Law ).
    • 금속성( Metalicity ).

아마 아티스트들은 위에서 언급한 요소들을 보는 순간 멘붕에 빠지게 될 것입니다. 사실 그래픽스에 익숙하지 않은 프로그래머들도 처음에는 이해하기 힘들겁니다. 사실 PBR 에 대해서 설명하려면 책 한권은 필요합니다. 그렇지만 이 문서의 목적은 아티스트에게 PBR 을 이해하기 위한 기본적인 정보들을 전달하는데 있기 때문에 너무 깊게 파고 들지는 않을 계획입니다. 그럼에도 불구하고 분량이 매우 많기 때문에 시리즈를 구성하기로 했습니다.

앞에서 언급한 요소들에 대해서 설명하기 이전에 알아야할 정보들에 대해서 설명한 다음에, 본격적으로 PBR 에 대해서 다룰 계획입니다.

빛이란 무엇인가

우리는 일상생활에서 빛이라는 개념을 자연스럽게 받아들이고 있습니다. 하지만 막상 "빛이란 무엇인가요?" 라는 질문을 누군가 하게 된다면 명확하게 대답할 수 있는 사람은 드물 것입니다. 하물며 아인슈타인만 해도 다음과 같이 말했다고 하죠[3].

나의 여생동안 빛이 무엇인지 되집어 보며 살 것이다 - 1917 년경
지난 50 여년 동안 곱씹어 고민해 왔음에도 빛이란 무엇인가에 대한 답에 더 가까이 다가서지 못했다. 물론 장난꾸러기같은 사람들은 답을 안다고 생각하겠지만 그들은 자신을 속이고 있는 것이다 - 1951 년.

아인슈타인이 양자론과 관련한 연구성과를 인정하고 싶지 않아서 한 말일 것이라 생각하기는 하지만, 어쨌든 빛이란 무엇인가에 대한 질문에 대답하는 것이 쉽지 않은 것만은 사실입니다. 여기에서 빛의 입자성과 파동성에 대해서 이야기하기에는 너무 주제가 무거워지기 때문에 단순하게 파동성과 관련한 부분에 대해서만 언급하도록 하겠습니다.

빛이라는 것은 기본적으로 전자기파( Electromagnetic wave )라고 할 수 있습니다. 전자기파라는 것은 전자기적 과정에 의해 발생하는 에너지입니다. 그냥 파동의 형태로 발산되는 에너지라고 이해하시면 됩니다. 빛이라는 것은, 수소원자같이 개별적으로 셈을 할 수 있는 입자가 아니라, 파장이 다른 여러 가지 전자기파로 구성되어 있습니다[4].

그림1. 전자기파의 스펙트럼[4].

좁은 의미로 봤을 때, 빛은 그림1 의 가시 영역을 의미합니다. 넓은 의미로 봤을 때, 빛은 그림1 의 전체 영역을 의미합니다. 우리가 볼 수 없는 많은 부분이 존재하고, 다들 적외선( IR, Infrared Rays )이나 자외선( UV, Ultra Violet )같은 이름에는 익숙할 것입니다. 시리즈의 다음 글에 언급하겠지만, 이러한 관점의 차이가 광도측정( Photometry )과 방사측정( Radiometry )의 차이를 만듭니다.

빛이라는 것은 위에서도 말했듯이 파장이 다른 여러 개의 전자기파로 구성되어 있기 때문에 프리즘같은 것을 써서 각각의 파장을 분리해낼 수도 있습니다. 시리즈의 뒷편에서 언급하겠지만 이는 파장에 따라서 굴절률이 달라지는 것을 이용한 것이죠. 무지개도 이런 원리로 생성됩니다.

그림2. 빛이 프리즘을 통과하면서 파장에 따라서 분리되는 현상을 보여줍니다[4].

눈치가 빠른 분들이라면 그림2 에서 각 색깔별로 파장의 길이가 다르다는 것을 눈치채실 수 있을 겁니다. 빨간색의 파장의 길이가 가장 길고, 보라색의 파장의 길이가 가장 짧습니다. 일단 여기에서는 빛이라는 것이 하나의 색상을 가지는 것이 아니라 여러 전자기파의 조합이라는 것만 이해하시면 됩니다.

그런데 인간은 어떻게 이러한 빛을 인지할 수 있는 것일까요?

우리는 빛을 어떻게 인지할까

그림3. 인간의 눈 구조. 출처: Encyclopedia Britannica, 1994.

인간의 눈에 있는 망막( Retina )을 확대해 보면 원추세포( cone cell : blue cone, red cone, green cone )와 간상세포( rod )라는 것이 있습니다. 원추세포는 색상을 감지하고 간상세포는 명암을 감지합니다. 원추세포는 그것을 구성하고 있는 감광세포의 종류에 따라 받아들일 수 있는 색상이 정해져 있죠. 그림3 을 보시면 세 종류의 원추세포가 존재하며, 그것의 색상이 RGB 라는 것을 알 수 있습니다. 이를 빛의 3원색이라 하고 실제로 텍스쳐( texture )를 만들 때도 RGB 를 사용하게 됩니다. RGB 채널을 사용하는 것은 어느날 갑자기 그렇게 하기로 결정된 것이 아닙니다. 인간의 눈과 관련이 있는 것입니다.

간상세포는 약 9000 만개이고 원추세포는 약 600 만개인데, 간상세포는 약한 빛에도 반응하고 원추세포는 일정 세기의 빛에 반응합니다[7]. 결과적으로 인간의 눈은 색상대비보다 명도대비에 더욱 민감하다고 할 수 있습니다.

대부분의 포유류들은 인간보다 적은 개수의 감광색소를 가지고 있다고 합니다. 반면에 새들의 경우에는 감광색소를 더 가지고 있어서 자외선까지 볼 수 있다고 합니다. 앞에서 언급한 가시광선이라는 것은 인간의 관점에서의 가시광선이라는 것이죠. 그러므로 새들은 인간보다 좀 더 다채로운 세상을 볼 수 있고 벌레를 쉽게 발견할 수 있다고 합니다.

그림4. 인간과 새가 인지할 수 있는 파장 비교[6].

좀 더 직관적으로 이해할 수 있도록 예를 들면 인간과 새가 보는 차이는 다음과 같습니다.

그림5. 인간과 새가 보는 색상의 차이[6].

그림5 에서 알 수 있듯이 인간의 눈에는 비슷해 보이는 색상이 새의 눈에는 확연하게 차이가 날 수 있습니다. 노란색 꽃에 노란 벌레가 앉아 있을 때. 인간은 둘을 구별하지 못하지만, 새의 입장에서는 그 차이가 명확하게 보일 수도 있는 것이죠.

인간의 눈에 있는 원추세포가 가장 민감하게 반응하는 구간이 녹색과 인접해 있어 인간은 녹색빛을 가장 멀리서도 인지한다고 합니다. 그리고 원추세포에 이상이 생기면 색맹이 된다고 합니다[7].

정리

빛은 다양한 파장을 가진 전자기파의 집합이며, 인간의 그중 가시영역의 파장을 가진 전자기파( 가시광선 )들만 인지할 수 있습니다. 그런데 인간의 눈은 RGB 의 조합으로 색상을 인지하게 되며, 이것은 우리가 빛의 3 원색을 사용하게 되는 근간이 되었습니다.

참고자료

[1] Physically based rendering, Wikipedia.

[2] Basic Theory Of Physically-Based Rendering, Marmoset.

[3] 빛이란 무엇인가? Barray R. Marsters.

[4] Light, Wikipedia.

[5] 파동의 표시, 더불어 생각하는 과학 교실.

[6] Color Vision in Birds.

[7] 원추세포, 위키백과.

주의 : 공부하면서 정리한 것이기 때문에 오류가 있을 수 있습니다.


 

PBR Specular D 의 기하학적 의미

 

PBR( Physically Based Rendering )에서 대세가 된 Cook-Torrance 의 스펙큘러 BRDF [1] 는 다음과 같이 정의됩니다.

 

 

 

이 중에서 D 함수는 미세면( microfacet )의 기울기에 대한 분산( Distribution ) 함수입니다. 이 문서에서는 이것의 기하학적 의미에 대해서 다루고자 합니다.

 

하나의 서피스( surface )는 여러 개의 미세면( microfacet )으로 구성되어 있다는 것이 PBR 이론의 근간에 깔려 있습니다. 그리고 서피스를 구성하는 각 미세면들은 서로 다른 노멀( normal )을 가지게 됩니다. 또한 그 미세면들에서는 거울면 반사( mirror reflection, 정반사 )가 발생합니다.

 

많은 문서에서는 이러한 미세면의 노멀을 m 으로 표시하기도 하고 h 로 표시하기도 합니다. 아마도 microfacet normal 과 half vector 의 약자인 것 같습니다. 그림 1 에서는 서피스와 미세면의 관계를 보여 줍니다.

 

그림1 : 미세면으로 구성된 서피스[2].

 

미세면의 노멀을 m 이라 표기하는 것은 이해가 가는 부분이지만 h( half vector )라 표기할 수도 있다는 것은 이해가 안 갈 것입니다. Burley 와 Cook-Torrance [1, 3] 은 공통적으로 하프 벡터( half vector )가 미세면의 노멀을 표현한다고 기술하고 있습니다.

 

이것은 하프 벡터를 사용하는 문맥으로부터 그 의미를 이해하는 것이 좋습니다. 위에서 우리는 미세면이 거울면 반사를 보여 준다고 가정했습니다. 그러면 질문을 뒤집어 보죠. 

 

서피스 내에서, 우리에게 거울면 반사를 보여 줄 수 있는 기울기를 가진 미세면은 얼마나 많을까요?

 

이것이 바로 Specular D 함수를 통해 얻고자 하는 값의 본질입니다. 그림 2 의 가장 왼쪽에 있는 미세면이 나에게 거울면 반사라는 결과를 보여 주려면 어떤 기울기를 가지고 있어야 할까요? 여기에서 n 은 서피스 노멀이고 m 은 미세면 노멀입니다.

 

그림 2: 샘플 미세면.

 

거울면 반사는 "입사각과 반사각이 같은 반사" 입니다. 그러므로 아래 그림처럼 빛 벡터 l 과 뷰 벡터 v 의 절반인 하프 벡터( h )와 미세면 노멀( m )이 일치하는 경우에 거울면 반사가 발생합니다.

 

 

여기에서 추정할 수 있는 것은 뾰족한 미세면이 많다면 retroreflection 의 양이 많아진다는 것입니다. 그냥 대중없이 거칠다면 난반사가 심해질 것이고, 부드럽다면( 즉 mn 과 거의 비슷한 면이 많다면 ) 정반사가 커지겠죠.

 

결국 우리의 질문은 다음과 같이 바뀔 수 있습니다.

 

광원을 향하는 벡터 l 와 관찰자(뷰)를 향하는 벡터 v 를 가지고 있을 때, 그것의 하프 벡터 h 와 동일한 미세면 노멀 m 은 얼마나 존재하나요?

 

하프 벡터 h 와 미세면 노멀 m 의 각도가 0 이 되는 미세면의 분포를 찾는 것이 Specular D 함수의 목적입니다. 그러므로 어떤 문헌들에서는 이런 가정을 깔고 "하프 벡터가 미세면의 노멀이다" 라는 식의 표현을 하게 되는 것입니다.

 

[3] 에서 Burley 는 실측 데이터와 다른 Specular D 함수들을 비교했습니다.

 

그림 3: Burley 가 비교한 분산들.

왼쪽부터 크롬 실측값, GGX, Beckmann.

 

일단 기존의 모델 중에서 가장 나은 것은 GGX( Trowbridge-Reitz 와 같음 ) 였습니다. 하지만 실측값을 보면 타는 듯한 효과와 더 긴 테일( tail )이 보입니다. 그래서 Burley 의 경우에는 이중 스펙큘러 로브를 구현하게 됩니다. 자세한 내용은 해당 기사에서 확인하시기 바랍니다.

 

하지만 실시간 렌더링의 세계에서는 스펙큘러 로브를 두 개씩 계산하는 것이 부담이 됩니다. 그래서 UE4 같은 경우에는 그냥 GGX 를 사용합니다.

 

물론 여러 개의 변종들이 있을 수 있으며, Specular BRDF Reference 에서 이를 확인할 수 있습니다. 참고로 이 문맥에서 "Normal Distribution" 은 정규 분포가 아닙니다. "노멀의 분포"라는 이야기입니다. "Specular D" 와 동일한 말입니다.

 

참고자료

 

[1] Robert L. Cook and Kenneth E. Torrance, "A Reflectance Model for Computer Graphics"( 번역 : http://lifeisforu.tistory.com/349 ).

 

[2] Simon's Tech Blog, "Microfacet BRDF". http://simonstechblog.blogspot.kr/2011/12/microfacet-brdf.html.

 

[3] Brent Burley, "Physically-Based Shading at Disney"( 번역 : http://lifeisforu.tistory.com/350 ).

+ Recent posts