서비스
교육 철학

10.6 표준 국소 조명 모델 (Standard Local Illumination)

렌더링 방정식에서 BRDF는 주어진 주파수와 입사 방향의 빛이 어떻게 산란하는지 그 분포를 나타냅니다. 표면마다 이 분포가 다르기 때문에 서로 다른 표면은 물론, 같은 물체의 서로 다른 표면 지점도 서로 다르게 보입니다. 컴퓨터에서는 대부분의 BRDF를 어떤 수식으로 표현하며, 원하는 재질 특성에 맞게 그 수식에 들어가는 몇몇 수치를 조정합니다.
수식 자체를 흔히 조명 모델(lighting model)이라고 부르며, 수식에 대입하는 구체적인 값은 표면에 지정한 재질에서 얻습니다. 장면에 매우 다양한 재질과 수천 가지 BRDF가 있더라도 게임 엔진에서 사용하는 조명 모델의 종류는 몇 가지에 불과한 경우가 흔합니다.
원서 집필 무렵만 해도 거의 모든 실시간 렌더링을 단 하나의 조명 모델로 처리했습니다. 당시에는 여전히 드물지 않은 방식이었습니다.
이 조명 모델은 워낙 널리 쓰였기 때문에 OpenGL과 DirectX의 렌더링 API 자체에 고정 기능으로 들어갔습니다. 프로그래머블 셰이더를 갖춘 하드웨어에서는 이러한 오래된 API 부분이 사실상 레거시 기능이 되었지만, 셰이더와 범용 상수·보간값이라는 더 일반적인 틀 안에서도 표준 모델을 여전히 자주 사용합니다.
프로그래머블 셰이더가 제공하는 다양한 기능과 유연성은 다른 모델을 선택하기보다, 기존 모델에 필요한 매개변수를 더 효율적으로 공급하는 데 쓰이는 경우가 많았습니다. 예를 들어 여러 광원을 한꺼번에 처리하거나, 지연 셰이딩으로 마지막에 조명을 모두 계산하는 식입니다. 프로그래머블 셰이더를 제쳐 놓고 보더라도, 집필 당시 가장 인기 있는 비디오 게임 콘솔은 닌텐도 Wii였으며(원주 10-13), 이 기기에는 이 표준 모델을 지원하는 고정 기능이 들어 있었습니다.
이 절에서는 오랫동안 사용되어 온 표준 조명 모델을 다룹니다. 이 모델은 BRDF와 렌더링 방정식이라는 틀보다 적어도 10년 먼저 개발되었으므로, 먼저 모델이 만들어질 당시의 단순화된 맥락 안에서 설명하겠습니다. 이러한 표기와 관점은 지금도 관련 문헌에서 주류를 이루므로, 모델 자체의 용어로 아이디어를 소개할 필요가 있다고 생각합니다.
설명하는 도중에 모델의 한 성분인 난반사 성분을 BRDF로 표현하는 방법도 보여 주겠습니다. 표준 모델은 현재에도 중요하지만, 미래에 대비하려면 렌더링 방정식을 이해해야 합니다.
원주 10-13: 이것은 매우 중요한 교훈입니다. 사실적인 그래픽은 하드코어 게이머에게 중요할지 몰라도, 더 폭넓은 이용자층에서는 우리가 예전에 생각했던 만큼 중요하지 않습니다. 최근 페이스북 게임의 인기 급상승은 이 점을 더욱 분명하게 보여 줍니다.

10.6.1 표준 조명 방정식: 개요

부이 뜨엉 퐁(Bui Tuong Phong) [54]은 1975년에 표준 조명 모델의 기본 개념을 제시했습니다. 당시에는 직접 반사를 빠르게 모델링하는 방법에 관심이 집중되어 있었습니다. 연구자들이 간접광의 중요성을 이해하지 못했던 것은 아니지만, 아직은 감당할 수 없는 사치였습니다.
따라서 앞에서 설명했듯이 표준 모델이 제안된 뒤 약 10년이 지나서야 명확한 형태를 갖춘 렌더링 방정식은 한 점에서 임의의 방향으로 나가는 복사휘도를 나타내는 방정식인 반면, 당시 중요하게 여겼던 출사 방향은 눈을 향하는 방향뿐이었습니다.
마찬가지로 렌더링 방정식은 표면 법선을 둘러싼 반구 전체에서 들어오는 입사광을 고려하지만, 간접광을 무시하면 모든 입사 방향을 살펴볼 필요가 없습니다. 광원을 향하는 방향만 고려하면 됩니다. 실시간 그래픽스에서 광원을 모델링하는 여러 방법은 10.7절에서 자세히 살펴보겠지만, 지금 중요한 점은 광원이 렌더링 방정식이나 현실 세계에서처럼 장면 안의 발광 표면이 아니라는 사실입니다.
대신 광원은 그에 대응하는 기하 형상이 없는 특별한 개체이며, 빛이 하나의 점에서 나오는 것처럼 시뮬레이션합니다. 그러므로 각 광원의 발광 표면을 x\mathbf{x} 주변 반구에 투영했을 때 차지하는 방향의 입체각을 포함하는 대신, 그 광원에 대응하는 단 하나의 입사 방향만 신경 씁니다.
정리하면, 표준 모델의 원래 목적은 유한한 수의 방향, 즉 광원마다 하나의 방향에서 입사하는 빛의 직접 반사만 고려하여 카메라 방향으로 되돌아오는 빛을 구하는 것이었습니다.
이제 모델 자체를 살펴보겠습니다. 기본 아이디어는 눈에 들어오는 빛을 네 가지 범주로 구분하고, 각 범주의 기여분을 서로 다른 방법으로 계산하는 것입니다.
•
발광 기여분(emissive contribution) cemis\mathbf{c}_{\mathrm{emis}}는 렌더링 방정식의 발광 항과 같습니다. 주어진 방향으로 표면 자체가 직접 방출하는 복사휘도의 양을 나타냅니다. 전역 조명 기법을 사용하지 않으면 이 표면은 자기 자신을 제외한 어떤 것도 실제로 밝히지 못합니다.
•
정반사 기여분(specular contribution) cspec\mathbf{c}_{\mathrm{spec}}는 광원에서 직접 들어온 빛 가운데 완벽한 ‘거울 반사’ 방향으로 우선적으로 산란하는 빛을 나타냅니다.
•
난반사 기여분(diffuse contribution) cdiff\mathbf{c}_{\mathrm{diff}}는 광원에서 직접 들어온 빛 가운데 모든 방향으로 고르게 산란하는 빛을 나타냅니다.
•
환경광 기여분(ambient contribution) camb\mathbf{c}_{\mathrm{amb}}는 모든 간접광을 대신하기 위해 넣는 보정 항입니다.
문자 cc는 contribution, 즉 ‘기여분’의 머리글자입니다. 굵은 글씨로 표기했다는 점에 주목하겠습니다. 이 기여분들은 특정 파장의 빛의 양을 나타내는 스칼라가 아니라, 이산적인 수의 성분, 즉 ‘채널’을 갖는 어떤 기저에서 색을 나타내는 벡터입니다. 앞에서 말했듯이 인간의 시각은 삼자극 체계이므로 채널 수는 거의 항상 3으로 정합니다.
어떤 세 기저 함수를 사용할지는 그보다 덜 근본적인 선택이지만, 실시간 그래픽스에서는 빨강·파랑·초록에 채널 하나씩을 배정하는 방식이 압도적으로 흔합니다. 구현 세부 사항을 떠나 원리를 설명할 때는 놀라울 만큼 이러한 세부 사항이 중요하지 않으며, 방정식 어디에도 드러나지 않습니다. 물론 실제 구현에서는 중요한 고려 사항입니다.
발광 항은 렌더링 방정식에서의 발광 항과 같으므로 더 자세히 설명할 내용이 많지 않습니다. 실제로는 주어진 표면 지점 x\mathbf{x}에서의 발광 기여분을 단순한 상수 색으로 두는 경우가 많습니다. 정반사·난반사·환경광 항은 더 복잡하므로 다음 세 소절에서 각각 자세히 다루겠습니다.
💡
조명 모델을 코드에 적용하기
원문의 ‘지금’, ‘현대적인 하드웨어’, Wii의 보급률, 금속성 입력에 대한 아티스트의 익숙함 등은 원서 집필 당시의 설명입니다. 번역에서는 이를 현재 시장 현황으로 갱신하지 않았습니다.

10.6.2 정반사 성분

표준 조명 모델의 정반사 성분은 표면에서 대체로 ‘완벽한 거울 반사’ 방향으로 반사되는 빛을 나타냅니다. 표면에 ‘반짝이는’ 모습을 부여하는 것이 정반사 성분입니다. 더 거친 표면은 빛을 훨씬 넓은 방향 분포로 산란시키는 경향이 있으며, 이 현상은 10.6.3절의 난반사 성분으로 모델링합니다.
이제 표준 모델에서 정반사 기여분을 어떻게 계산하는지 보겠습니다. 중요한 벡터들은 그림 10.20에 표시되어 있습니다.
•
n\mathbf{n}은 해당 지점에서 표면 바깥쪽을 향하는 국소 표면 법선입니다.
•
v\mathbf{v}는 관찰자를 향합니다. 이 벡터를 눈(eye)을 뜻하는 e\mathbf{e}로 표기하기도 합니다.
•
l\mathbf{l}은 광원을 향합니다.
•
r\mathbf{r}은 ‘완벽한 거울 반사’ 방향을 나타내는 반사 벡터입니다. l\mathbf{l}을 n\mathbf{n}에 대해 대칭시킨 결과입니다.
•
θ\theta는 r\mathbf{r}과 v\mathbf{v} 사이의 각도입니다.
그림 10.20. 정반사를 위한 퐁 모델
편의상 이 벡터들을 모두 단위 벡터라고 가정하겠습니다. 이 책에서는 단위 벡터 위에 모자 기호를 붙이는 것이 원칙이지만, 방정식이 지나치게 복잡해 보이지 않도록 여기서는 생략합니다. 이 주제를 다루는 많은 문헌이 이 표준 변수 이름들을 사용하며, 특히 비디오 게임 분야에서는 사실상 공통 어휘의 일부가 되었습니다. 지원자가 이 틀을 잘 알고 있다고 가정한 채 면접 질문을 하는 경우도 드물지 않습니다.
계속하기 전에 l\mathbf{l} 벡터에 관해 한 가지 짚고 넘어가겠습니다. 광원은 추상적인 개체이므로 반드시 ‘위치’를 가질 필요는 없습니다. 방향성 광원이나 Doom 방식의 체적 광원(10.7절 참조)은 광원의 위치가 분명하지 않을 수 있는 예입니다. 핵심은 광원의 위치 자체가 중요하지 않다는 점입니다. 사용 중인 광원 추상화는 주어진 셰이딩 지점에서 입사 방향을 계산할 수 있게 해 주면 됩니다. 물론 입사광의 색과 세기도 제공해야 합니다.
그림 10.21. 반사 벡터 r의 구성
네 벡터 중 처음 세 벡터는 문제에 본래 주어지는 자유도이며, 반사 벡터 r\mathbf{r}은 이들로부터 유도하여 계산해야 하는 양입니다. 기하학적 관계는 그림 10.21과 같습니다. 그림에서 보듯이 반사 벡터는 다음 식으로 구합니다.
반사 벡터 계산 — 게임 업계 면접에 자주 등장하는 질문
r=2(n⋅l)n−l.(10.10)\mathbf{r}=2(\mathbf{n}\cdot\mathbf{l})\mathbf{n}-\mathbf{l}.\tag{10.10}
이 방정식을 즐겨 묻는 면접관이 많기 때문에, 문단 안에 넣어도 충분했을 식을 일부러 독립된 줄로 표시했습니다. 비디오 게임 업계에 취업하려는 독자라면 압박을 받는 상황에서도 식 (10.10)을 도출할 수 있도록 그림 10.21을 완전히 이해하기 바랍니다. n\mathbf{n}과 l\mathbf{l}이 단위 벡터라면 r\mathbf{r}도 단위 벡터라는 점에 주목하겠습니다.
이제 r\mathbf{r}을 알았으므로 정반사용 퐁 모델, 식 (10.11)을 사용해 정반사 기여분을 계산할 수 있습니다.
정반사를 위한 퐁 모델
cspec=(sspec⊗mspec)(cos⁡θ)mgls=(sspec⊗mspec)(v⋅r)mgls.(10.11)\mathbf{c}_{\mathrm{spec}} =(\mathbf{s}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}})(\cos\theta)^{m_{\mathrm{gls}}} =(\mathbf{s}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}})(\mathbf{v}\cdot\mathbf{r})^{m_{\mathrm{gls}}}.\tag{10.11}
이 식을 비롯하여 이 책에서 기호 ⊗\otimes는 색의 성분별 곱을 뜻합니다. 이제 식에 들어가는 값들을 더 자세히 살펴보겠습니다.
먼저 mglsm_{\mathrm{gls}}는 재질의 광택도(glossiness)이며, 퐁 지수(Phong exponent), 정반사 지수(specular exponent), 또는 재질의 반짝임(shininess)이라고도 합니다. 이 값은 ‘핫스폿’, 즉 반사광의 밝은 부분이 얼마나 넓은지 제어합니다.
mglsm_{\mathrm{gls}}가 작으면 핫스폿이 넓고 주변으로 완만하게 어두워지며, 값이 크면 핫스폿이 매우 좁고 급격하게 어두워집니다. 여기서 말하는 핫스폿은 반사의 밝은 부분이며 스폿 광원의 핫스폿과 혼동하지 말아 주세요.
크롬처럼 완벽하게 반사하는 표면은 mglsm_{\mathrm{gls}}가 매우 큽니다. 입사 방향 l\mathbf{l}에서 광선이 표면에 닿으면, 반사된 방향 사이의 편차가 매우 작습니다. 광선들은 거의 산란하지 않고 r\mathbf{r} 방향 주위의 아주 좁은 입체각, 즉 ‘원뿔’ 안으로 반사됩니다. 사과의 표면처럼 반짝이지만 완벽한 반사체는 아닌 표면은 정반사 지수가 더 작아 핫스폿이 더 넓습니다.
작은 정반사 지수는 광선의 반사가 덜 완벽한 상황을 모델링합니다. 광선들이 같은 입사 방향 l\mathbf{l}에서 표면에 닿아도 반사 방향의 편차가 더 큽니다. 분포는 반사 방향 r\mathbf{r} 주변에 모이지만, r\mathbf{r}에서 멀어질수록 세기가 감소하는 정도가 더 완만합니다.
잠시 뒤에 이 차이를 그림으로 보여 주겠습니다.
조명 방정식에 입력하는 다른 재질 특성들과 마찬가지로, mglsm_{\mathrm{gls}}도 표면 위에서 달라질 수 있으며, 특정 위치의 값은 원하는 방법으로 결정할 수 있습니다. 예를 들어 텍스처 맵(10.5절 참조)을 사용할 수 있습니다. 그러나 다른 재질 특성과 비교하면 이런 방식은 드문 편입니다. 실제 실시간 그래픽스에서는 광택도를 재질 전체에 대한 상수로 정하고 표면 위에서 변화시키지 않는 경우가 매우 흔합니다.
식 (10.11)에서 ‘반짝임’과 관련된 또 다른 값은 재질의 정반사 색 mspec\mathbf{m}_{\mathrm{spec}}입니다. mglsm_{\mathrm{gls}}가 핫스폿의 크기를 제어한다면 mspec\mathbf{m}_{\mathrm{spec}}는 그 세기와 색을 제어합니다. 반사율이 높은 표면은 mspec\mathbf{m}_{\mathrm{spec}} 값이 높고, 무광에 가까운 표면은 값이 낮습니다. 원한다면 텍스처 맵이 물체의 색을 제어하듯이 스페큘러 맵(specular map)이라는 비트맵으로 핫스폿의 색을 제어할 수도 있습니다(원주 10-14).
원주 10-14: 안타깝게도 이 맵을 gloss map이라고 부르는 사람도 있어서, 정확히 어떤 재질 특성을 텍셀별로 지정하는 것인지 혼동을 일으킵니다.
광원의 정반사 색 sspec\mathbf{s}_{\mathrm{spec}}는 기본적으로 광원의 ‘색’이며, 색상과 세기를 모두 담고 있습니다. 많은 광원이 하나의 일정한 색을 갖지만, 이 색의 세기는 거리에 따라 감쇠합니다(10.7.2절). 여기서 사용하는 공식에서는 이 감쇠도 sspec\mathbf{s}_{\mathrm{spec}}에 포함합니다. 감쇠를 무시하더라도 같은 광원이 서로 다른 방향으로 서로 다른 색의 빛을 비출 수 있습니다.
사각형 스폿 광원에서는 투사되는 비트맵 영상인 고보(gobo)에서 색을 구할 수 있습니다. 색이 있는 고보는 스테인드글라스 창을 통과하는 빛을 흉내 내는 데 쓸 수 있으며, 움직이는 고보로 회전하는 천장 선풍기나 바람에 흔들리는 나무의 그림자를 가짜로 만들 수도 있습니다.
여기서는 광원(source)을 뜻하는 문자 ss를 사용합니다. 아래첨자 spec은 이 색을 정반사 계산에 사용한다는 뜻입니다. 난반사 계산에는 다른 광원 색을 사용할 수 있습니다. 이는 특정 상황에서 특수 효과를 얻기 위한 조명 모델의 기능일 뿐, 현실 세계에서 대응되는 의미는 없습니다. 실제로 sspec\mathbf{s}_{\mathrm{spec}}는 거의 항상 난반사 조명에 사용하는 광원 색과 같으며, 예상할 수 있듯이 이 책에서는 그 색을 sdiff\mathbf{s}_{\mathrm{diff}}라고 씁니다.
그림 10.22. m_gls와 m_spec의 값에 따른 차이
그림 10.22는 mglsm_{\mathrm{gls}}와 mspec\mathbf{m}_{\mathrm{spec}}를 바꾸었을 때 정반사를 하는 물체의 모습이 어떻게 달라지는지 보여 줍니다. 재질의 정반사 색 mspec\mathbf{m}_{\mathrm{spec}}는 가장 왼쪽 열의 검정에서 가장 오른쪽 열의 흰색으로 변합니다. 정반사 지수 mglsm_{\mathrm{gls}}는 맨 위 행에서 크고 아래 행으로 갈수록 작아집니다.
맨 왼쪽 열의 머리들이 모두 똑같아 보인다는 점에 주목하겠습니다. 정반사의 세기가 0이므로 지수는 아무런 의미가 없고, 어떤 경우에도 정반사 기여분이 없습니다. 이때의 밝기는 각각 10.6.3절과 10.6.4절에서 다룰 난반사와 환경광 성분에서 나옵니다.
블린(Blinn) [6]은 퐁 모델을 조금 수정하여 시각적으로 매우 비슷한 결과를 얻으면서도 당시에는 상당한 최적화가 되었던 방법을 널리 알렸습니다. 지금도 많은 경우 더 빨리 계산할 수 있지만, 이 모델에서 줄어드는 벡터 연산이 언제나 성능 병목은 아니라는 점을 조심해야 합니다.
기본 아이디어는 이렇습니다. 물체 크기에 비해 관찰자까지의 거리가 충분히 멀다면 v\mathbf{v}를 한 번만 계산하고 물체 전체에 대한 상수로 볼 수 있습니다. 광원과 l\mathbf{l} 벡터도 마찬가지입니다. 실제로 방향성 광원에서는 l\mathbf{l}이 항상 일정합니다. 그러나 표면 법선 n\mathbf{n}은 일정하지 않으므로 반사 벡터 r\mathbf{r}은 여전히 계산해야 합니다.
가능하면 이 계산을 피하고 싶습니다. 블린 모델은 새로운 벡터 h\mathbf{h}를 도입합니다. 이 이름은 하프웨이 벡터(halfway vector)를 뜻하며, v\mathbf{v}와 l\mathbf{l}을 평균한 뒤 정규화한 결과입니다.
h=v+l∥v+l∥.\mathbf{h}=\frac{\mathbf{v}+\mathbf{l}}{\|\mathbf{v}+\mathbf{l}\|}.
그다음에는 퐁 모델처럼 v\mathbf{v}와 r\mathbf{r} 사이의 각도를 사용하는 대신, n\mathbf{n}과 h\mathbf{h} 사이 각도의 코사인을 사용합니다. 이 관계를 그림 10.23에 나타냈습니다.
그림 10.23. 정반사를 위한 블린 모델
블린 모델의 공식은 원래 퐁 모델과 매우 비슷합니다. 내적 부분만 달라집니다.
정반사를 위한 블린 모델
cspec=(sspec⊗mspec)(cos⁡θ)mgls=(sspec⊗mspec)(n⋅h)mgls.\mathbf{c}_{\mathrm{spec}} =(\mathbf{s}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}})(\cos\theta)^{m_{\mathrm{gls}}} =(\mathbf{s}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}})(\mathbf{n}\cdot\mathbf{h})^{m_{\mathrm{gls}}}.
관찰자와 광원이 물체에서 충분히 멀리 떨어져 있어 그 방향들을 상수로 볼 수 있다면, 블린 모델을 하드웨어로 구현하는 편이 퐁 모델보다 빠를 수 있습니다. 이 경우 h\mathbf{h}가 상수이므로 한 번만 계산하면 되기 때문입니다. 그러나 v\mathbf{v}나 l\mathbf{l}을 상수로 볼 수 없다면 퐁 계산이 더 빠를 수도 있습니다.
앞서 말했듯이 두 모델은 비슷하지만 동일하지 않은 결과를 만듭니다. 비교는 Fisher와 Woo [21]을 참고해 보세요. 둘 다 경험적인 모델이며, 블린 모델을 ‘올바른’ 퐁 모델의 ‘근사’라고 생각해서는 안 됩니다. 실제로 Ngan 등 [48]은 블린 모델이 객관적인 장점을 가지며 일부 표면에서는 실험 데이터에 더 잘 맞는다는 것을 보였습니다.
지금까지 생략한 세부 사항이 하나 있습니다. 어느 모델에서든 cos⁡θ\cos\theta가 음수가 될 수 있습니다. 이때는 보통 정반사 기여분을 0으로 제한합니다.
💡
조명 모델을 코드에 적용하기
하프웨이 벡터 h를 계산할 때 v+l이 영벡터가 되는 특수 경우에는 정규화가 정의되지 않습니다. 실제 구현에서는 이런 경계 조건과 정규화 오차를 처리해야 합니다.

10.6.3 난반사 성분

표준 조명 모델의 다음 성분은 난반사 성분입니다. 정반사 성분과 마찬가지로, 난반사 성분도 광원에서 셰이딩 지점까지 직접 이동한 빛을 모델링합니다. 하지만 정반사광이 특정 방향으로 우선적으로 반사되는 빛을 나타낸다면, 난반사광은 표면 재질의 거친 성질 때문에 모든 방향으로 무작위로 반사되는 빛을 모델링합니다. 그림 10.24는 완벽하게 반사하는 표면과 거친 표면에서 광선이 반사되는 모습을 비교합니다.
정반사 조명을 계산할 때는 눈이 완벽한 거울 반사 방향에 얼마나 가까운지 알아야 하므로 관찰자의 위치가 필요했습니다. 반면 난반사 조명에서는 관찰자의 위치가 중요하지 않습니다. 반사가 무작위로 흩어지므로, 카메라를 어디에 놓더라도 그 방향으로 광선이 향할 가능성이 같기 때문입니다.
그러나 표면에 대한 광원의 상대 위치가 정하는 입사 방향 l\mathbf{l}은 중요합니다. 램버트 법칙을 앞에서도 언급했지만 여기서 다시 살펴보겠습니다. 실시간 그래픽스에서 이 법칙이 적용되는 가장 중요한 곳이 블린–퐁 모델의 난반사 부분이기 때문입니다. 물체 표면에 닿아 눈으로 반사될 기회를 얻는 광자들을 센다고 생각해 보면, 광선에 수직인 표면은 비스듬한 표면보다 단위 면적당 더 많은 광자를 받습니다.
그림 10.25가 이를 보여 줍니다.
그림 10.24. 난반사 조명은 흩어지는 반사를 모델링한다
그림 10.25. 광선에 더 수직인 표면일수록 단위 면적당 더 많은 빛을 받는다
두 경우 모두 광선 사이의 수직 거리가 같다는 점에 주목하겠습니다. 그림의 착시 때문에 오른쪽 광선 사이가 더 멀어 보일 수 있지만 실제로는 같습니다. 광선 사이의 수직 거리는 같아도, 그림 10.25 오른쪽에서는 광선이 물체에 닿는 지점들 사이의 거리가 더 멉니다. 두 표면의 ‘면적’은 같은데도 왼쪽 표면은 광선 9개를 받고 오른쪽 표면은 6개만 받습니다.
따라서 단위 면적당 광자 수(원주 10-15)는 왼쪽이 더 많고, 다른 조건이 같다면 왼쪽이 더 밝게 보입니다. 적도 부근의 기후가 극지방보다 따뜻한 것도 같은 현상 때문입니다. 지구는 둥글기 때문에 적도 부근에서는 햇빛이 지표면에 더 수직에 가까운 각도로 닿습니다.
난반사 조명은 램버트 법칙을 따릅니다. 반사광의 세기는 표면 법선과 광선 사이 각도의 코사인에 비례합니다. 이 코사인은 내적으로 계산합니다.
램버트 법칙에 따른 난반사 성분 계산
cdiff=(sdiff⊗mdiff)(n⋅l).(10.12)\mathbf{c}_{\mathrm{diff}}=(\mathbf{s}_{\mathrm{diff}}\otimes\mathbf{m}_{\mathrm{diff}})(\mathbf{n}\cdot\mathbf{l}).\tag{10.12}
앞에서와 같이 n\mathbf{n}은 표면 법선이며 l\mathbf{l}은 광원을 향하는 단위 벡터입니다. mdiff\mathbf{m}_{\mathrm{diff}}는 재질의 난반사 색으로, 대부분의 사람이 물체의 ‘색’이라고 생각하는 값입니다. 재질의 난반사 색은 흔히 텍스처 맵에서 얻습니다. 광원의 난반사 색은 sdiff\mathbf{s}_{\mathrm{diff}}이며, 보통 광원의 정반사 색 sspec\mathbf{s}_{\mathrm{spec}}와 같습니다.
원주 10-15: 정확한 복사측정학 용어는 복사조도(irradiance)이며, 단위 면적에 도달하는 복사속을 측정합니다.
정반사 조명에서와 마찬가지로 내적이 음수가 되지 않도록 0으로 제한해야 합니다. 이렇게 하면 물체가 뒷면에서 들어오는 빛으로 밝혀지는 것을 막을 수 있습니다.
렌더링 방정식의 틀 안에서 난반사 표면을 어떻게 표현하는지 살펴보면 매우 유익합니다.
난반사는 빛이 완전히 무작위로 산란하는 상황을 모델링한다. 들어오는 빛의 방향과 관계없이 모든 출사 방향의 가능성이 같다. 따라서 완전한 난반사 표면의 BRDF는 상수이다.
식 (10.12)가 렌더링 방정식의 적분 안에 있는 다음 항과 닮았다는 점에 주목하겠습니다.
Lin(x,ω^in,λ)f(x,ω^in,ω^out,λ)(−ω^in⋅n^).L_{\mathrm{in}}(\mathbf{x},\hat{\boldsymbol{\omega}}_{\mathrm{in}},\lambda) f(\mathbf{x},\hat{\boldsymbol{\omega}}_{\mathrm{in}},\hat{\boldsymbol{\omega}}_{\mathrm{out}},\lambda) (-\hat{\boldsymbol{\omega}}_{\mathrm{in}}\cdot\hat{\mathbf{n}}).
첫 번째 인자는 입사광의 색입니다. 재질 색 mdiff\mathbf{m}_{\mathrm{diff}}는 그다음에 오는 상수 BRDF 값에 해당합니다. 마지막에는 램버트 인자가 있습니다.
💡
조명 모델을 코드에 적용하기
본문의 m_diff는 전통적인 색 기반 모델 안에서 사용하는 계수입니다. 물리적인 램버트 BRDF를 반사율 rho로 정의하면 f_r = rho / pi가 되며, 이를 에너지 보존을 고려하는 조명 식과 연결할 때는 pi 정규화가 필요합니다. 원문의 식 (10.12)는 그대로 두고, 물리적인 정규화 조건을 보충 설명으로 구분했습니다.

10.6.4 환경광과 발광 성분

정반사와 난반사 조명은 모두 광원에서 물체 표면까지 직접 이동한 뒤 한 번 ‘튕겨’ 눈에 도달하는 광선을 나타냅니다. 그러나 현실에서 빛은 하나 이상의 중간 물체에서 반사된 뒤 다른 물체에 닿고, 거기에서 다시 눈으로 반사되는 경우가 흔합니다. 한밤중에 냉장고 문을 열면 문이 직접광 대부분을 막고 있어도 주방 전체가 조금 밝아집니다.
눈에 들어오기 전에 두 번 이상 반사된 빛은 ‘환경광’이라는 매우 거친 근사로 모델링할 수 있습니다. 조명 방정식의 환경광 부분은 재질 특성과 환경광 값에만 의존합니다. 환경광 값은 장면 전체에 사용하는 전역 값인 경우가 많습니다. 어떤 광원도 이 계산에 참여하지 않습니다. 실제로 광원이 전혀 없어도 됩니다. 환경광 성분은 식 (10.13)으로 계산합니다.
조명 방정식의 환경광 기여분
camb=gamb⊗mamb.(10.13)\mathbf{c}_{\mathrm{amb}}=\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}.\tag{10.13}
mamb\mathbf{m}_{\mathrm{amb}}는 재질의 ‘환경광 색’입니다. 이 값은 거의 항상 난반사 색과 같고, 그 난반사 색은 흔히 텍스처 맵으로 정의합니다. 다른 인자인 gamb\mathbf{g}_{\mathrm{amb}}는 환경광 값입니다. 하나의 전역 환경광 값을 장면 전체에 사용하는 경우가 많아서, global을 뜻하는 gg를 사용했습니다. 그러나 라이팅 프로브 같은 기법은 더 국소적이고 방향에 따라 달라지는 간접 조명을 제공하려고 합니다.
때로는 광선이 중간의 어떤 표면에도 닿지 않고 광원에서 눈으로 곧바로 이동합니다. 표준 조명 방정식은 재질에 발광 색을 지정하여 이런 광선을 나타냅니다. 예를 들어 전구의 표면을 렌더링할 때는 장면에 다른 광원이 전혀 없어도 그 표면이 매우 밝게 보일 것입니다. 전구가 빛을 내기 때문입니다.
많은 상황에서 발광 기여분은 환경 요인에 의존하지 않으며, 단순히 재질의 발광 색과 같습니다.
발광 기여분은 재질에만 의존한다
cemis=memis.\mathbf{c}_{\mathrm{emis}}=\mathbf{m}_{\mathrm{emis}}.
대부분의 표면은 빛을 내지 않으므로 발광 성분이 0입니다. 발광 성분이 0이 아닌 표면을 ‘자체 발광(self-illuminated)’ 표면이라고 합니다.
실시간 그래픽스에서는 자체 발광 표면이 다른 표면을 밝히지 않는다는 점을 이해하는 것이 중요합니다. 다른 표면을 밝히려면 광원이 필요합니다. 다시 말해 우리는 실제로 광원 자체를 렌더링하는 것이 아니라, 광원이 장면의 표면에 미치는 효과만 렌더링합니다. 자체 발광 표면은 렌더링하지만 그 표면은 장면의 다른 표면과 상호작용하지 않습니다. 반면 렌더링 방정식을 제대로 사용하면 발광 표면이 주변을 실제로 밝힙니다.
안개와 같은 대기 조건 때문에 발광 기여분을 감쇠시키기로 할 수도 있고, 성능상의 이유로 멀리 있는 물체를 서서히 흐리게 하다가 사라지게 할 수도 있습니다. 그러나 10.7.2절에서 설명하겠지만, 일반적으로 발광 기여분에는 광원에 적용하는 것과 같은 방식의 거리 감쇠를 적용해서는 안 됩니다.

10.6.5 조명 방정식: 모든 성분 합치기

조명 방정식의 각 성분을 자세히 살펴보았습니다. 이제 표준 조명 모델의 완전한 방정식을 제시할 차례입니다.
광원이 하나일 때의 표준 조명 방정식
clit=cspec+cdiff+camb+cemis=(sspec⊗mspec)max⁡(n⋅h,0)mgls+(sdiff⊗mdiff)max⁡(n⋅l,0)+gamb⊗mamb+memis.\begin{aligned} \mathbf{c}_{\mathrm{lit}} &=\mathbf{c}_{\mathrm{spec}}+\mathbf{c}_{\mathrm{diff}}+\mathbf{c}_{\mathrm{amb}}+\mathbf{c}_{\mathrm{emis}}\\ &=(\mathbf{s}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}})\max(\mathbf{n}\cdot\mathbf{h},0)^{m_{\mathrm{gls}}}\\ &\quad +(\mathbf{s}_{\mathrm{diff}}\otimes\mathbf{m}_{\mathrm{diff}})\max(\mathbf{n}\cdot\mathbf{l},0)\\ &\quad +\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}+\mathbf{m}_{\mathrm{emis}}. \end{aligned}
그림 10.26은 환경광·난반사·정반사 조명 성분을 다른 성분과 분리했을 때 실제로 어떻게 보이는지 보여 줍니다. 이 떠 있는 머리는 빛을 내지 않는다고 가정하여 발광 성분은 무시했습니다. 눈여겨볼 점이 몇 가지 있습니다.
그림 10.26. 조명 방정식의 각 성분이 시각적으로 기여하는 모습
•
귀는 실제로 머리의 그림자 안에 있지만 코만큼 밝게 비칩니다. 그림자를 표현하려면 섀도 매핑 같은 기법으로 광원이 셰이딩 중인 지점을 실제로 ‘볼’ 수 있는지 판단해야 합니다.
•
처음 두 그림에는 환경광이 없기 때문에 광원의 반대쪽을 향한 머리의 측면이 완전히 검습니다. 물체의 ‘뒷면’을 밝히려면 환경광을 사용해야 합니다. 모든 표면에 직접광이 닿도록 충분한 광원을 장면에 배치하는 것이 가장 좋은 상황이지만, 언제나 가능한 것은 아닙니다. Mitchell 등 [47]이 ‘하프 램버트(Half Lambert)’ 조명이라고 부른 흔한 편법은 램버트 항에 편향을 더해 난반사 조명이 모델 뒷면까지 ‘감싸’ 들어가게 하는 것입니다. 이렇게 하면 뒷면이 환경광만 받아 완전히 평평하게 보이는 것을 막습니다. 표준 항 n⋅l\mathbf{n}\cdot\mathbf{l}을 α+(1−α)(n⋅l)\alpha+(1-\alpha)(\mathbf{n}\cdot\mathbf{l})로 바꾸면 간단히 구현할 수 있습니다. α\alpha는 추가로 감싸는 효과의 정도를 정하는 조절 가능한 매개변수입니다. Mitchell 등은 α=1/2\alpha=1/2을 제안하며, 계산 결과를 제곱하기도 합니다. 물리적 근거는 거의 없지만, 특히 작은 계산 비용을 생각하면 지각적으로 얻는 이점이 매우 큽니다.
•
환경광만 있으면 실루엣만 보입니다. 조명은 물체를 ‘3차원’으로 보이게 하는 매우 강력한 시각적 단서입니다. 이 ‘만화 같은’ 효과를 해결하려면 모든 표면이 직접 조명을 받도록 장면에 충분한 수의 광원을 배치합니다.
여러 광원을 이야기했으니, 조명 방정식에서는 여러 광원을 어떻게 다루는지도 보겠습니다. 모든 광원의 조명 값을 더해야 합니다. 표기를 간단히 하기 위해 거의 보편적인 가정인 sspec=sdiff\mathbf{s}_{\mathrm{spec}}=\mathbf{s}_{\mathrm{diff}}를 채택하겠습니다. 그러면 감쇠 인자까지 포함한 jj번째 광원의 색을 sj\mathbf{s}_j로 쓸 수 있습니다. 첨자 jj는 1부터 광원 수 nn까지 변합니다. 이제 조명 방정식은 다음과 같습니다.
여러 광원에 대한 표준 조명 방정식
clit=∑j=1n[(sj⊗mspec)max⁡(n⋅hj,0)mgls+(sj⊗mdiff)max⁡(n⋅lj,0)]+gamb⊗mamb+memis.(10.14)\mathbf{c}_{\mathrm{lit}} =\sum_{j=1}^{n}\left[ (\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{spec}})\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}} +(\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{diff}})\max(\mathbf{n}\cdot\mathbf{l}_j,0) \right] +\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}+\mathbf{m}_{\mathrm{emis}}.\tag{10.14}
주어진 표면에서 환경광 값과 발광 성분은 각각 하나뿐이므로, 이 성분들은 광원마다 합산하지 않습니다.

10.6.6 표준 모델의 한계

오늘날에는 프로그래머블 셰이더 덕분에 원하는 어떤 조명 모델도 선택할 수 있습니다. 표준 모델에는 상당히 심각한 단점이 있으므로 ‘왜 이런 옛날 역사를 배워야 하지?’라고 물을 만합니다. 첫째, 이것은 사실 옛날이야기만은 아닙니다. 표준 모델은 지금도 활발히 사용됩니다. 사실성·사용 편의성·계산 속도 사이에서 좋은 절충안이 되었던 이유는 여전히 유효합니다.
처리 능력이 늘어난 것은 맞지만, 더 많은 픽셀과 더 많은 광원을 렌더링하고 싶다는 요구도 함께 커졌습니다. 프로그래머가 계산 자원을 더 많은 픽셀, 즉 높은 해상도에 쓸지, 더 정확한 픽셀, 즉 더 정확한 조명 모델에 쓸지 결정할 때 표준 조명 모델이 선택되는 경우는 현재 매우 흔합니다.
둘째, 현재의 국소 조명 모델은 콘텐츠 제작자가 이해하고 사용할 수 있습니다. 이 장점을 가볍게 보아서는 안 됩니다. 아티스트들은 난반사 맵과 정반사 맵을 수십 년 동안 사용해 왔습니다. 익숙한 입력을 Strauss 모델 [69]의 ‘금속성(metalness)’처럼 아티스트가 직관적으로 이해하지 못하는 다른 입력으로 바꾸는 조명 모델로 전환하려면 큰 대가를 치러야 합니다.
마지막으로 표준 조명 모델을 배워야 하는 이유는 많은 새로운 모델이 표준 모델과 비슷한 면을 가지고 있기 때문입니다. 오래된 표준을 이해하지 못하면 언제 더 고급 조명 모델을 사용해야 할지도 알 수 없습니다.
OpenGL이나 DirectX의 재질 매개변수 설정 문서를 읽고 환경광·난반사·정반사가 ‘빛이 작동하는 방식’이라고 생각했더라도 이해할 만합니다. 이 장의 시작에서 했던 경고를 떠올려 보겠습니다. 실제로 이들은 특정 조명 모델에 속한 임의의 실용적 구성 요소입니다. 난반사와 정반사라는 이분법이 물리적으로 본래 존재하는 것은 아닙니다.
실용적인 고려에서 생겨났고, 같은 이유로 계속 사용되고 있습니다. 두 용어는 양극단에 해당하는 두 산란 분포를 묘사합니다. 이 두 분포를 임의로 조합하면 많은 현상을 꽤 그럴듯하게 근사할 수 있습니다.
거의 모든 사람이 이 모델을 받아들였기 때문에 이름을 붙이지 않고 사용하는 경우가 많으며, 정확히 무엇이라고 불러야 하는지에도 여전히 혼동이 있습니다. 퐁은 반사를 난반사와 정반사 기여분의 합으로 모델링하는 기본 아이디어를 제안하고, 정반사를 위한 유용한 경험적 계산식도 제공했으므로 ‘퐁 조명 모델’이라고 부를 수 있습니다.
난반사용 램버트 모델은 이미 알려져 있었습니다. 앞에서 보았듯이 블린의 정반사 계산은 비슷하지만 때로는 더 빠릅니다. 가장 자주 사용하는 구체적인 계산법이 이것이라면 ‘블린 모델’이라고 불러야 할까요? 그러나 블린의 이름은 다른 미세면(microfacet) 모델에도 붙어 있습니다.
그 모델에서는 난반사와 정반사가 서로 독립적인 ‘직교’ 성분으로 섞이는 것이 아니라 하나의 연속적인 스펙트럼의 양끝에 놓입니다. 대부분의 구현이 퐁의 기본 아이디어에 블린의 최적화를 사용하므로, 가장 흔히 쓰는 이름은 블린–퐁(Blinn-Phong)이며 이 책도 그 이름을 사용합니다.
사실적인 조명에서 물론 큰 비중을 차지하는 것은 사실적인 그림자입니다. 그림자를 만드는 기법은 흥미롭고 중요하지만, 안타깝게도 여기서는 다룰 시간이 없습니다. 렌더링 방정식의 이론에서는 주어진 방향으로부터 들어오는 복사휘도를 결정할 때 그림자를 처리합니다. 어떤 방향에 광원, 더 정확히는 발광 표면이 있고 그 지점에서 해당 표면이 ‘보인다면’, 그 빛이 지점에 입사합니다.
그러나 그 방향을 보았을 때 다른 표면이 광원을 가리고 있으면, 그 지점은 해당 광원에 대해 그림자 안에 있습니다. 더 일반적으로 그림자는 발광 표면에서 온 빛에만 생기는 것이 아닙니다. 반사 표면에서 튕겨 나온 빛에도 그림자가 생길 수 있습니다. 어느 경우든 그림자는 반사 모델의 문제가 아니라 빛의 가시성 문제입니다.
마지막으로 블린–퐁 모델이 제대로 표현하지 못하는 몇 가지 중요한 물리 현상을 언급하겠습니다. 첫째는 프레넬 반사(Fresnel reflectance)입니다(원주 10-16). 비금속의 반사율은 빛이 스치듯이 입사할 때 가장 크고, 법선 방향에서 입사할 때 가장 작다는 현상입니다.
벨벳 같은 일부 표면은 재귀반사(retroreflection)를 보입니다. 이름만 보고 표면이 마돈나의 귀걸이처럼 복고풍으로 보인다는 뜻이라고 짐작할지 모르지만, 실제로는 주된 반사 방향이 블린–퐁이 예측하는 ‘거울 반사’ 방향이 아니라 광원으로 되돌아가는 방향이라는 뜻입니다.
또한 블린–퐁은 등방성(isotropic)입니다. 관찰자와 광원을 고정한 채 표면을 회전시켜도 반사율이 달라지지 않는다는 뜻입니다. 일부 표면은 표면의 홈이나 다른 무늬 때문에 비등방성 반사(anisotropic reflection)를 보입니다. 이 경우 반사의 세기는 홈의 방향에 대한 입사 방향에 따라 달라집니다.
홈의 방향을 스크래치 방향(scratch direction)이라고도 합니다. 비등방성 재질의 대표적인 예는 결이 있는 금속, 머리카락, 반짝이는 섬유로 만든 작은 크리스마스 장식입니다.
원주 10-16: ‘fre-NELL’로 발음합니다.

10.6.7 플랫 셰이딩과 구로 셰이딩

현대적인 셰이더 기반 하드웨어에서는 보통 픽셀마다 조명 계산을 합니다. 즉 각 픽셀에서 정점 법선을 면 위로 보간하거나 범프 맵에서 값을 가져와 표면 법선을 결정한 뒤, 그 법선으로 전체 조명 방정식을 계산합니다. 이것이 픽셀별 조명(per-pixel lighting)입니다.
정점 법선을 면 위로 보간하는 기법을 퐁 셰이딩(Phong shading)이라고도 하는데, 정반사용 퐁 계산식과 혼동하지 말아 주세요. 퐁 셰이딩의 대안은 면마다 또는 정점마다 계산하는 식으로 조명 방정식의 계산 빈도를 줄이는 것입니다. 두 기법을 각각 플랫 셰이딩(flat shading)과 구로 셰이딩(Gouraud shading)이라고 합니다.
플랫 셰이딩은 소프트웨어 렌더링을 제외하면 실제로는 거의 사용하지 않습니다. 기하 데이터를 하드웨어에 효율적으로 전달하는 대부분의 현대적 방법이 면 단위 데이터를 아예 제공하지 않기 때문입니다. 반면 구로 셰이딩은 일부 플랫폼에서 여전히 제한적으로 사용됩니다. 이 방법들을 살펴보면 중요한 일반 원리를 배울 수 있으므로 결과를 비교해 보겠습니다.
플랫 셰이딩에서는 삼각형 전체에 대해 하나의 조명 값을 계산합니다. 보통 조명 계산에 사용하는 ‘위치’는 삼각형의 무게중심이며, 표면 법선은 삼각형의 법선입니다. 그림 10.27에서 보듯이 플랫 셰이딩으로 물체를 비추면 조각조각 나뉜 면 구조가 너무나 분명하게 드러나고 매끄럽다는 착각이 사라집니다.
그림 10.27. 플랫 셰이딩한 찻주전자
구로 셰이딩은 정점 셰이딩(vertex shading), 정점 조명(vertex lighting), 보간 셰이딩(interpolated shading)이라고도 합니다. 조명이나 안개 등의 값을 정점 단위로 계산한 뒤, 다각형 면 전체에 걸쳐 선형 보간하는 요령입니다. 그림 10.28은 같은 찻주전자를 구로 셰이딩으로 렌더링한 것입니다.
그림 10.28. 구로 셰이딩한 찻주전자
그림에서 보듯이 구로 셰이딩은 물체의 매끄러운 느낌을 꽤 잘 되살립니다. 근사하려는 값이 삼각형 전체에서 대체로 선형으로 변한다면, 구로 셰이딩에 사용하는 선형 보간은 당연히 잘 작동합니다. 그러나 정반사 하이라이트처럼 값이 선형이 아니면 구로 셰이딩의 한계가 드러납니다.
구로 셰이딩한 찻주전자의 정반사 하이라이트를 그림 10.29의 퐁, 즉 픽셀별 셰이딩을 적용한 찻주전자의 하이라이트와 비교해 보겠습니다. 하이라이트가 얼마나 더 매끄러운지 주목해 보세요. 실루엣이나 손잡이·주둥이처럼 기하학적 불연속이 큰 부분을 제외하면 매끄럽다는 착각이 매우 그럴듯합니다. 구로 셰이딩에서는 정반사 하이라이트 때문에 개별 면을 알아볼 수 있습니다.
그림 10.29. 퐁 셰이딩한 찻주전자
보간 셰이딩의 근본적인 문제는 삼각형 내부의 어떤 값도 정점에서의 최댓값보다 클 수 없다는 것입니다. 따라서 하이라이트는 정점에서만 생길 수 있습니다. 테셀레이션을 충분히 하면 이 문제를 극복할 수 있습니다. 이러한 한계에도 구로 셰이딩은 휴대용 플랫폼이나 닌텐도 Wii처럼 제한된 일부 하드웨어에서 여전히 사용됩니다.
여기서 독자가 물어야 할 질문은 조명 방정식의 입력을 제어하는 데 맵을 사용한다면 정점 단계에서 조명을 어떻게 계산할 수 있느냐는 것입니다. 식 (10.14)를 그대로 사용할 수는 없습니다. 특히 난반사 색 mdiff\mathbf{m}_{\mathrm{diff}}는 보통 정점 단위 재질 특성이 아니라 텍스처 맵으로 정의되는 값입니다.
식 (10.14)를 보간 조명 방식에 더 적합하게 만들려면 mdiff\mathbf{m}_{\mathrm{diff}}를 분리하도록 식을 변형해야 합니다. 먼저 합을 나누고 상수인 재질 색들을 합의 밖으로 꺼냅니다.
clit=∑j=1n[(sj⊗mspec)max⁡(n⋅hj,0)mgls+(sj⊗mdiff)max⁡(n⋅lj,0)]+gamb⊗mamb+memis=∑j=1n(sj⊗mspec)max⁡(n⋅hj,0)mgls+∑j=1n(sj⊗mdiff)max⁡(n⋅lj,0)+gamb⊗mamb+memis=[∑j=1nsjmax⁡(n⋅hj,0)mgls]⊗mspec+[∑j=1nsjmax⁡(n⋅lj,0)]⊗mdiff+gamb⊗mamb+memis.\begin{aligned} \mathbf{c}_{\mathrm{lit}} &=\sum_{j=1}^{n}\left[(\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{spec}})\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}}+(\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{diff}})\max(\mathbf{n}\cdot\mathbf{l}_j,0)\right]\\ &\quad+\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}+\mathbf{m}_{\mathrm{emis}}\\ &=\sum_{j=1}^{n}(\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{spec}})\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}} +\sum_{j=1}^{n}(\mathbf{s}_j\otimes\mathbf{m}_{\mathrm{diff}})\max(\mathbf{n}\cdot\mathbf{l}_j,0)\\ &\quad+\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}+\mathbf{m}_{\mathrm{emis}}\\ &=\left[\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}}\right]\otimes\mathbf{m}_{\mathrm{spec}} +\left[\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{l}_j,0)\right]\otimes\mathbf{m}_{\mathrm{diff}}\\ &\quad+\mathbf{g}_{\mathrm{amb}}\otimes\mathbf{m}_{\mathrm{amb}}+\mathbf{m}_{\mathrm{emis}}. \end{aligned}
마지막으로 아주 합리적인 가정인 mamb=mdiff\mathbf{m}_{\mathrm{amb}}=\mathbf{m}_{\mathrm{diff}}를 적용합니다.
정점 단계의 조명 계산에 더 적합한 표준 조명 방정식
clit=[∑j=1nsjmax⁡(n⋅hj,0)mgls]⊗mspec+[gamb+∑j=1nsjmax⁡(n⋅lj,0)]⊗mdiff+memis.(10.15)\begin{aligned} \mathbf{c}_{\mathrm{lit}} &=\left[\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}}\right]\otimes\mathbf{m}_{\mathrm{spec}}\\ &\quad+\left[\mathbf{g}_{\mathrm{amb}}+\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{l}_j,0)\right]\otimes\mathbf{m}_{\mathrm{diff}}+\mathbf{m}_{\mathrm{emis}}. \end{aligned}\tag{10.15}
식 (10.15)의 형태로 쓰면 정점 단계에서 계산한 조명 값을 보간하여 사용하는 방법이 보입니다. 각 정점에서 두 값을 계산하겠습니다. vspec\mathbf{v}_{\mathrm{spec}}는 식 (10.15)의 정반사 부분을 담고, vdiff\mathbf{v}_{\mathrm{diff}}는 환경광과 난반사 항을 담습니다.
정점 단위의 정반사 및 난반사 조명 값
vspec=∑j=1nsjmax⁡(n⋅hj,0)mgls,vdiff=gamb+∑j=1nsjmax⁡(n⋅lj,0).\mathbf{v}_{\mathrm{spec}}=\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{h}_j,0)^{m_{\mathrm{gls}}}, \qquad \mathbf{v}_{\mathrm{diff}}=\mathbf{g}_{\mathrm{amb}}+\sum_{j=1}^{n}\mathbf{s}_j\max(\mathbf{n}\cdot\mathbf{l}_j,0).
이 값들을 정점마다 계산하고 삼각형 면 전체에 걸쳐 보간합니다. 그런 다음 픽셀마다 각 조명 기여분에 대응하는 재질 색을 곱하고 더합니다.
보간한 조명 값으로 픽셀 셰이딩하기
clit=vspec⊗mspec+vdiff⊗mdiff+memis.\mathbf{c}_{\mathrm{lit}}=\mathbf{v}_{\mathrm{spec}}\otimes\mathbf{m}_{\mathrm{spec}}+\mathbf{v}_{\mathrm{diff}}\otimes\mathbf{m}_{\mathrm{diff}}+\mathbf{m}_{\mathrm{emis}}.
앞서 언급했듯이 mspec\mathbf{m}_{\mathrm{spec}}는 때로 상수 색입니다. 그런 경우 이 곱셈을 정점 셰이더로 옮길 수 있습니다. 그러나 스페큘러 맵에서 값을 가져오는 경우도 있습니다.
조명 계산에는 어느 좌표 공간을 사용해야 할까요? 월드 공간에서 계산할 수도 있습니다. 정점 위치와 법선을 월드 공간으로 변환한 뒤 조명을 계산하고, 그다음 정점 위치를 클립 공간으로 변환합니다. 또는 광원들을 모델링 공간으로 변환하고 그 공간에서 조명을 계산할 수도 있습니다. 보통 광원 수가 정점 수보다 적기 때문에 이 방법은 전체 벡터-행렬 곱셈 수를 줄입니다. 세 번째 가능성은 카메라 공간에서 조명을 계산하는 것입니다.
💡
조명 모델을 코드에 적용하기
퐁 조명 모델은 반사광을 계산하는 식입니다. 퐁 셰이딩은 법선을 픽셀까지 보간한 뒤 조명을 계산하는 방식입니다. 같은 이름이지만 구분해야 합니다.
💡
조명 모델을 코드에 적용하기
정점에서 밝기를 먼저 계산한 뒤 보간하는 것과, 법선을 보간한 뒤 밝기를 계산하는 것은 같지 않습니다. 제곱·정규화·거듭제곱이 포함된 함수에서는 일반적으로 ‘계산 후 평균’과 ‘평균 후 계산’의 결과가 다릅니다.
💡
법선 보간과 색 보간의 차이
flowchart LR
 A["정점 법선"] --> B["면 내부에서 법선 보간"]
 B --> C["보간한 법선 정규화"]
 C --> D["픽셀에서 비선형 조명 계산"]
 A --> E["정점에서 조명 계산"]
 E --> F["계산된 색을 선형 보간"]
Mermaid
복사