개 어지러운 미적분
디퓨즈 및 람베르시안 셰이딩
읽는 시간: 22분
디퓨즈 또는 람베르시안 셰이딩
디퓨즈 물체는 CG에서 시뮬레이션하기 쉽습니다. 하지만 이것이 어떻게 작동하는지 이해하려면 먼저 빛이 표면과 상호작용하는 방식에 대해 배워야 합니다. 기술적으로, 이 주제를 철저히 이해하려면 먼저 복사측정학(radiometry)을 공부해야 합니다. 이 소개를 간단하고 직관적으로 유지하기 위해 복사측정학 없이 진행하겠습니다. 개념을 단순화하면, CG에서 한 점을 셰이딩할 때 이 점이 매우 작은 표면을 나타낸다고 가정하는데, 이를 미분 면적(differential area)이라고 부릅니다. 여기서 “미분(differential)“이라는 용어에 너무 집중하지 말고 “면적(area)“이라는 용어에 주목하세요. 물리적 의미가 없는 이론적 점을 고려하는 대신, 우리는 점 주변의 매우 작은 면적을 고려할 것이며, 이를 CG에서는 일반적으로 (dA)로 표기합니다. 또한 (P) 주변의 이 매우 작은 면적의 표면에 떨어지는 빛의 양을 고려합니다. (P)에 떨어지는 빛은 단일 광선으로 축소되지 않습니다. 왜냐하면 우리는 단일 점이 아니라 그 점 주변의 작은 영역 (dA)에 관심이 있기 때문입니다. 이 영역에 떨어지는 빛은 다음 그림의 왼쪽 그림에서 보듯이 (P)에 수직인 작은 부피 내에 포함됩니다.
다시 말해, (dA)와 동일한 단면적을 가진 이 부피 내에 포함된 모든 빛 에너지가 (dA)에 떨어집니다. 위 그림의 왼쪽 이미지에서 보듯이 일정한 빛 에너지 플럭스가 이 부피를 통과한다면, 언제든지 일정량의 빛 에너지가 표면 (dA)에 충돌한다고 가정할 수 있습니다. 이를 표현하는 또 다른 방법은 언제든지 1000개의 광자가 (dA)의 표면에 충돌한다고 상상하는 것입니다. 이 1000개의 광자는 물체의 표면과 상호작용합니다: 일부는 흡수되고 일부는 거의 동시에 반사됩니다. 잠시 후에 1000개의 새로운 광자가 다시 (dA)의 표면에 충돌할 것입니다. 광자의 플럭스가 일정하다면 이 과정은 계속 반복됩니다. (dA)에 수직인 빛의 원뿔이 (dA)와 동일한 단면적을 가지고 있기 때문에, (dA)는 시간의 각 순간마다(CG에서는 종종 (dt)라고 부르며, (dA)와 유사한 개념이지만 시간에 적용됨) 1000개의 광자에 지속적으로 폭격당합니다. 이 빛의 원뿔이 (P)에서의 법선에 대해 각도를 이룰 때 흥미로운 현상이 발생합니다. 위 이미지의 두 번째와 세 번째 그림에서 볼 수 있듯이, 광선과 (P)에서의 법선 사이의 각도가 증가함에 따라 광선과 물체 표면의 단면적이 (dA)보다 커집니다. 다르게 표현하면, (dA)에 충돌하던 1000개의 광자 중 광선이 법선과 각도를 이룰 때는 이 광자들 중 일부만 (dA)에 도달합니다. 그 비율(광선에 포함된 전체 광자 수에 대한 (dA)가 받는 광자 수)은 각도가 증가함에 따라 작아집니다. 광선이 물체의 표면에 수직일 때는 (dA)에 광자가 전혀 충돌하지 않습니다.
요약하면:
- 광선이 (dA)에 수직일 때, 단면적이 (dA)와 동일한 작은 빛의 원뿔 내의 광자의 100%가 (dA)에 충돌합니다.
- 광선이 셰이딩 점의 법선과 각도를 이룰 때, 광선과 표면의 단면적이 (dA)보다 커집니다. 이는 광자 또는 빛 에너지가 (dA)보다 더 큰 영역에 분포됨을 의미합니다. 우리는 (dA)로 덮인 영역에 도달하는 빛 에너지의 양에만 관심이 있으므로, 광선과 법선 사이의 각도가 증가함에 따라 더 적은 광자가 (dA)에 도달한다고 말할 수 있습니다. 각도가 클수록 광자는 더 적어집니다. 따라서 광선과 법선 사이의 각도가 증가함에 따라 (dA)는 점점 더 적은 에너지를 받습니다.
- 극단적인 경우, 광선이 (P)에서의 법선에 수직일 때는 광자가 (dA)에 전혀 떨어지지 않습니다. 이 특별한 경우 (dA)는 빛 에너지를 전혀 받지 못합니다.
이러한 관찰로부터, 표면 요소 (dA)는 광선이 표면에 수직일 때, 즉 표면 법선 (N)과 빛의 방향 (L)이 평행할 때 최대 빛 에너지를 받는다는 것을 더 쉽게 이해할 수 있습니다. 그러나 광선이 특정 각도에서 표면을 비출 때, (dA)는 광선이 표면에 수직일 때보다 더 적은 빛 에너지를 받으며, 이는 표면 자체도 환경으로 더 적은 빛을 반사한다는 것을 의미합니다. 이로부터 표면이 더 어두워질 것이라는 것을 자연스럽게 추론할 수 있습니다. 앞서 언급했듯이, (N)과 (L) 사이의 각도가 증가함에 따라 (dA)는 점점 더 적은 광자에 맞습니다. 실질적으로 이는 두 벡터 사이의 각도가 증가함에 따라 표면이 점점 더 어두워진다는 것을 의미합니다. 궁극적으로 (N)과 (L)이 수직일 때, (dA)는 빛을 전혀 받지 못하므로 검은색입니다(빛을 받지 못하므로 반사도 하지 않습니다). 더 일반적으로, 밝기는 (dA) 대 (dL)의 비율에 비례한다고 말할 수 있습니다. (dL), 즉 광선의 경사진 단면적이 두 벡터 사이의 각도가 증가함에 따라 커지므로, 이 비율은 각도가 증가함에 따라 감소합니다.
이 원리는 CG에서 가장 기본적이고 잘 알려진 현상 중 하나입니다. 이것은 **람베르트의 코사인 법칙(Lambert’s Cosine Law)**이라는 이름으로 알려져 있습니다. 표면이 받는 빛의 양은 표면 법선 (N)과 빛의 방향 (L) 사이의 각도에 직접 비례합니다. 이 각도는 수학적으로 다음과 같이 정의될 수 있습니다:
따라서 법칙 이름에 코사인이라는 용어가 들어갑니다. 각도 (\theta)(그리스 문자 세타)의 코사인은 벡터 (N)과 (L)의 내적으로 정의됩니다. 이 레슨에서 기억해야 할 것이 하나 있다면, 아마도 이 기본 법칙일 것입니다. 물론, 표면이 반사하는 빛의 양, 즉 얼마나 밝게 보이는지는 받는 빛의 양에 직접적으로 달려 있습니다. 따라서 디퓨즈 표면의 최종 색상(그리고 곧 디퓨즈가 여기서 무엇을 의미하는지 정의할 것입니다)이 두 벡터 사이의 각도의 코사인에 어떻게든 비례한다고 쓸 수 있습니다:
여기서 (\propto) 기호는 “비례한다”를 의미합니다. 이제 이것은 문제의 한 측면일 뿐입니다. 적어도 이제 디퓨즈 표면의 한 점에 도달하는 빛의 양을 계산하는 방법에 대해 알게 되었지만, 전체 그림을 완성하고 사용 가능한 방정식을 만들려면 디퓨즈 표면이 환경으로, 특히 시선 방향(눈의 방향)으로 그 빛을 얼마나 반사하는지도 알아야 합니다. 먼저, 빛 에너지가 (P)에서 표면에 충돌할 때, 그 빛의 일부는 물체에 흡수되고 일부는 반사됩니다. 첫 번째 장에서 언급했듯이, 이것은 표면의 알베도(albedo) 파라미터로 정의됩니다. 알베도 항은 입사광의 양에 대한 반사광의 비율을 정의합니다:
컴퓨터 그래픽스에서 알베도라는 용어는 종종 그리스 문자 (\rho)(로)로 표시됩니다. 퍼즐의 조각들을 모으면, 표면 법선과 빛의 방향 사이의 각도에 비례한다는 것을 알고 있는 입사광의 양과, 표면 알베도에 비례한다는 것을 알고 있는 표면에 의해 반사되는 빛의 양이 있습니다. 이 두 구성요소를 합치면, 디퓨즈 표면에 의해 반사되는 빛의 양은 받는 빛의 양에 알베도(표면에 의해 반사되는 입사광의 비율, 즉 흡수되지 않는 비율)를 곱한 것과 같다고 말할 수 있습니다:
이것은 입사 빛 에너지, 표면 법선, 빛의 방향, 표면 알베도를 알고 있을 때 디퓨즈 표면의 한 점의 색상을 계산하는 거의 완전한 공식입니다. 방정식을 완성하기 위해 한 가지 항만 더 필요합니다.
첫 번째 장에서 언급했듯이, 디퓨즈 표면은 표면에 충돌하는 빛을 입사점 위의 모든 방향으로 균등하게 반사한다는 독특한 속성을 가지고 있습니다. 그림 3에서 보듯이, 한 점에서 물체의 표면에 충돌하는 광선과 입사점에서 바깥쪽으로 확장되는 반구 방향으로 재분배되는 빛 에너지를 상상해보세요. 실용적인 관점에서 이것은 광선의 에너지가 표면 법선과 빛의 방향 사이의 각도의 코사인에 의해 감쇠된다는 것을 알고 있으며, 반구의 표면에 걸쳐 재분배된다는 것을 의미합니다. 우리는 이 문제를 다른 방식으로 보고, 이 반구의 표면에 걸쳐 분포된 모든 에너지를 수집한다면, 그것은 입사 빛 에너지와 같아야 한다고 말할 수 있습니다. 물론 표면에 흡수된 빛의 양은 빼야 합니다. 재분배된 빛만큼의 빛이 표면에 입사하는 것과 같으며, 표면에 흡수된 빛의 양은 뺍니다. 수학적으로, 반구의 표면에 걸쳐 빛 에너지를 수집하는 것은 적분을 사용하여 쓸 수 있습니다:
적분 기호는 어떤 의미에서 반구의 표면에 걸쳐 퍼진 모든 빛 에너지를 합산하는 것에 관심이 있다는 것을 의미합니다(예를 들어, 그 반구의 표면에 분포된 광자의 수를 세는 것을 상상하세요). 이 방정식에서 반구의 개념은 (\Omega) 항으로 표현됩니다. 이 방정식을 읽으면 “입사점에서 표면 법선 (N)을 중심으로 향한 반구(여기서 (\Omega) 항으로 정의됨)에 걸쳐, (P)에서 표면에 의해 반사된 입사 광선의 빛 에너지(예를 들어 광자의 수)를 수집한다((\int) 항)“라고 말할 수 있습니다. 반사되는 에너지는 그 자체로 표면의 알베도에 입사 빛 에너지와 표면 법선과 빛의 방향 사이의 각도의 코사인을 곱한 것과 같다는 것을 알고 있습니다. 따라서 이 두 개념을 함께 놓으면, 왼쪽의 적분 항(방정식에서 녹색 부분)과 수집하려는 것, 즉 적분의 오른쪽에 있는 빨간색 항을 얻습니다.
적분 개념에 익숙하지 않다면, The Mathematics of Shading 레슨을 읽어보시기 바랍니다.
이 레슨에서는 적분에 대한 많은 정보를 제공하지 않으며, (d\omega) 항이 무엇을 의미하는지도 설명하지 않습니다. 그러나 어떤 물체(이 경우 반구)의 표면에 걸쳐 “어떤 값”을 수집하는 것은 표면을 작은 영역으로 나누고, 이 작은 영역의 표면에서 관심 있는 양을 측정하고, 결과를 합산하는 것으로 볼 수 있다는 것을 알아야 합니다. 측정하려는 양이 물체의 표면에 걸쳐 변할 수 있기 때문에 이렇게 합니다. 예를 들어, 물체가 평평한 평면일 때, 이 평면의 패치 면적은 제곱미터, 인치 또는 길이를 측정하는 데 사용하려는 단위로 측정할 수 있습니다. 우리는 이것을 미분 면적이라고 부를 것입니다. 우리는 이미 이 장의 앞부분에서 이 개념을 소개했고 미분 면적은 일반적으로 (dA)로 표기된다고 언급했습니다. 그러나 구나 반구의 경우, 제곱미터 대신 스테라디안(steradian)을 사용합니다. 스테라디안은 입체각의 단위로, 입체각은 길이가 아닌 각도로 표현된 구의 패치 측정값입니다. CG에서 입체각에 가장 많이 사용되는 기호는 (\omega)입니다. 따라서 (d\omega) 항은 미분 입체각의 개념, 또는 더 일반적인 용어로 구의 매우 작은 패치를 의미하지만 입체각으로 표현됩니다. 위에서 언급한 적분의 목표는 관심 표면(이 경우 반구)을 매우 작은 패치(반구 표면의 (d\omega)로, 반구 표면의 패치이기 때문에 수학적으로 스테라디안으로 측정됨)로 나누고, 이 작은 패치 또는 미분 입체각 각각에 대해 측정된 값(우리 예제에서 빨간색으로 정의된 값)을 합산하는 것입니다.
적분과 적분을 해석적으로 또는 몬테카를로 적분과 같은 기법을 사용하여 어떻게 풀 수 있는지에 대한 자세한 정보는 The Mathematics of Shading 레슨을 참조하세요.
이제, 표면에 의해 반사되는 빛의 양이 실제로 표면에 도달하는 빛의 양에서 흡수되는 빛의 양을 뺀 것보다 클 수 없다는 것에 동의하시기 바랍니다. 논리적이죠? 다시 말해, 위의 방정식을 사용하여 표면에 의해 반사되는 에너지의 양을 측정할 수 있다면, 그것은 입사 빛 에너지의 양보다 작거나 같아야 합니다:
여기서 (L_i)는 입사 빛 에너지의 양을 나타냅니다. 다행히도 우리에게는 이 특별한 경우의 적분 결과를 해석적으로 계산할 수 있습니다. 간단히 말하면, 우리는 이 적분의 결과가 무엇인지 알고 있습니다. 다시 한 번, 적분을 어떻게 풀 수 있는지 배우려면 The Mathematics of Shading 레슨을 참조하세요. 이 경우, 미적분학의 제1 기본 정리를 사용할 수 있습니다. 이 정리의 아이디어는 어떤 함수 (f)의 역도함수 (F)를 알고 있다면, 닫힌 구간에서 (f)의 적분 결과를 계산할 수 있다는 것입니다. 이것은 종종 다음과 같이 쓰입니다:
우리 적분의 문제는 입체각((d\omega) 항)으로 표현된다는 것인데, 이는 다루기 쉬운 단위가 아닙니다. 더 간단하게 만들기 위해, (d\omega) 항을 (\sin\theta d\theta d\phi)로 바꿀 수 있습니다. 여기서 각도 (\theta)(그리스 문자 세타)는 구간 [0, (\pi/2)]에서 정의되고 각도 (\phi)(그리스 문자 파이)는 구간 [0, (2\pi)]에서 정의됩니다. 이 아이디어는 그림 5에 설명되어 있습니다. 다시 말해, 스테라디안을 사용하는 대신 이제 라디안 또는 각도를 사용하는데, 이것이 다루기 더 쉽습니다. 하지만 이제 (\theta)와 (\phi), 두 가지 양에 대해 적분해야 하므로 하나 대신 두 개의 적분이 필요합니다:
구면 좌표에서 입체각을 각도 (\theta)와 (\phi)를 사용하는 것으로 변환할 때 (\sin(\theta))의 사용은 어디에서 나오는가?
그것은 (\theta)가 변함에 따라 구 표면 위의 면적의 다양한 “폭”을 설명해야 할 필요성에서 나옵니다. 이것은 구면 기하학의 기본 개념이며, 특히 적분 미적분학을 사용하여 구의 면적을 설명할 때 그렇습니다.
구면 좌표((\theta)와 (\phi))는 단위 구(반지름 = 1) 위의 3차원 점을 나타냅니다. 이 시스템에서:
- (\theta)(세타)는 극각으로, 양의 z축에서 측정됩니다.
- (\phi)(파이)는 방위각으로, xy 평면에서 양의 x축에서 측정됩니다.
구와 같은 표면에 대한 적분을 다룰 때, 우리는 입체각으로 면적을 표현합니다. 구면 좌표에서 입체각 (d\omega)는 단위 구의 면적과 관련이 있습니다. 구 표면의 작은 면적(면적의 패치처럼)을 (\theta)와 (\phi)의 평면으로 투영할 때, 구의 곡률 때문에 그 구의 패치의 실제 면적은 단순한 직사각형이 아닙니다. (\theta)가 변함에 따라, 특히 적도((\theta = \frac{\pi}{2}))에서 멀어질 때, 위도 띠의 “폭”이 감소합니다.
- 극점((\theta = 0) 또는 (\theta = \pi))에서 띠는 점과 같아지며 폭이 없습니다.
- 적도((\theta = \frac{\pi}{2}))에서 띠는 최대 폭입니다.
(\sin(\theta)) 인수는 이 폭의 변화를 설명합니다. 그것은 본질적으로 우리의 구면 면적 요소의 “수평적”(또는 방위각) 구성요소를 스케일링하며, 이는 (\sin(\theta))에 비례합니다.
구면 좌표에서 구의 미분 면적 요소(표면적)는 (\sin(\theta) d\theta d\phi)로 주어집니다. 구에 대한 함수의 적분은 다음과 같이 표현됩니다:
이 적분은 함수 (f)를 구면 표면에 걸쳐 합산하며, (\sin(\theta))로 인한 다양한 위도에서의 면적 크기 변화를 올바르게 설명합니다. (\sin(\theta))의 사용은 구면 표면의 기하학적 현실을 정확하게 반영하는 데 필수적입니다. 이것은 적분에서 표현된 면적 요소가 극점 근처의 면적이 적도 근처의 면적에 비해 더 작다는 구의 기하학을 올바르게 설명하도록 보장합니다. 이 기하학적 보정은 입체각으로 표현된 적분을 더 익숙한 각도 측정값인 (\theta)와 (\phi)를 포함하는 적분으로 변환할 때 중요합니다.
이 이중 적분이 단위 구의 면적과 같다는 수학적 증명:
적분을 수행해 봅시다. 구의 총 표면적을 찾기 위한 적분은:
-
(\theta)에 대해 적분:
-
(\phi)에 대해 적분:
이 결과들을 결합하면:
이 결과, (4\pi)는 정확히 단위 구의 표면적 공식이며, 면적 요소에서 (\sin(\theta))를 사용한 적분 계산이 총 면적을 올바르게 산출한다는 것을 확인합니다.
적분에서 적분하는 것은 방정식의 끝에서 문자 (d) 앞에 오는 양입니다. 이 예제에서는 (\phi)와 (\theta)가 될 것입니다. 다시 말해, 상수 (\rho_d)와 (L_i)는 영향을 받지 않으며 적분 밖으로 꺼낼 수 있습니다:
또한 (\le) 기호의 양쪽에 (L_i) 항이 있다는 것을 주목하세요. 부등식의 양변을 (L_i)로 나누면:
또한:
따라서:
첫 번째 적분((\phi)에 대한 적분)을 (2\pi)로 대체할 수 있습니다:
마지막으로 미적분학의 제1 기본 정리를 사용하여 마지막 적분을 풀 수 있습니다. (\cos x \sin x)의 역도함수는:
역도함수가 어떻게 결정되었는지 이해하지 못한 경우를 대비해 단계를 설명하겠습니다. 역도함수에서 시작하여 그 도함수가 실제로 (\cos(x) \sin(x))임을 보여드리겠습니다:
-
시작 표현식:
- 함수 (-\frac{1}{2} \cos^2(x))를 고려합니다.
-
내부 함수 정의:
- (u = \cos(x))를 정의합니다. 이 선택은 표현식을 재검토하게 합니다: (-\frac{1}{2} u^2).
-
연쇄 법칙 적용:
- (-\frac{1}{2} u^2)를 (x)에 대해 미분하기 위해 연쇄 법칙을 사용합니다. 연쇄 법칙은 합성 함수를 미분하기 위해, 먼저 내부 함수를 상수로 취급하여 외부 함수를 미분한 다음 (x)에 대한 내부 함수의 도함수를 곱한다고 규정합니다.
-
연쇄 법칙 실행:
- (-\frac{1}{2} u^2)를 (u)에 대해 미분하면 (-u)가 됩니다.
- (u = \cos(x))일 때, (u = \cos(x))의 (x)에 대한 도함수는 (-\sin(x))입니다.
-
결과 결합:
- 따라서 도함수는 (-u \times (-\sin(x)) = \cos(x) \sin(x))가 됩니다.
-
최종 단계:
- 원래 표현식으로 다시 대입하고 단계를 고려하면, 다음을 발견합니다:
- 이것은 (-\frac{1}{2} \cos^2(x))의 도함수가 실제로 (\cos(x) \sin(x))임을 확인하며, (-\frac{1}{2} \cos^2(x))가 올바른 역도함수임을 검증합니다.
따라서:
마지막으로, 결과를 얻습니다:
(\rho_d) 항, 즉 표면 알베도는 [0,1] 범위의 모든 값을 가질 수 있습니다. 표면의 알베도가 예를 들어 0.5라고 상상하면, 위의 부등식은 명백히 올바르지 않습니다: (\frac{1}{2} \cdot \pi)는 1보다 작지 않습니다. 따라서 위의 방정식은 알베도가 가질 수 있는 모든 가능한 값에 대해 참이 아닙니다. 이 부등식이 작동하도록 만드는 유일한 해법은 알베도 자체를 (\pi)로 나누는 것입니다:
그러면 작동할 것입니다. 따라서 디퓨즈 표면에 의해 반사되는 빛의 양은 실제로:
왜냐하면 이 방정식을 반구에 대해 적분하면:
그러면 이 방정식으로 디퓨즈 표면이 받는 것보다 더 많은 에너지를 반사할 수 없다는 것을 실제로 알 수 있습니다:
알베도를 (\pi)로 나누는 것을 적분 결과를 정규화하는 방법으로 볼 수 있습니다.
이제 방정식을 알았으니 이것을 실제로 적용해 봅시다. 이번에는 장면에 빛을 추가해야 합니다. 단순화를 위해 먼 광원(distant light)과 하나의 빛으로 시작하겠습니다. 장면에 하나 이상의 빛이 있을 때 무엇을 해야 하는지, 그리고 구형 빛에 대해서는 다음 장에서 배우겠습니다. 이전 레슨에서 개발한 레이 트레이서의 소스 코드를 수정하겠습니다. 먼저, 장면의 각 물체는 이제 알베도 파라미터를 가지며, 이것을 물체의 색상으로 볼 수 있습니다:
class Object {
Object(const Matrix44f &o2w, const Vec3f &c = 0.18)
: objectToWorld(o2w), worldToObject(o2w.inverse()), albedo(c)
...
Vec3f albedo;
...
};왜 기본 색상이 0.18인가? 알베도 기본값을 0.18로 설정하는 이유는 실제 세계의 물체가 받는 빛의 평균적으로 약 18%를 반사하기 때문입니다. 이것은 평균값입니다. 다시 말해, 다양한 과일, 아스팔트, 눈, 나무 잎, 풀 등이 반사하는 빛의 양을 보고 이 모든 값의 평균을 내면 18%에 가까운 값이 나옵니다. 이 주제에 대한 자세한 정보는 A Creative Dive into BRDF, Linearity, and Exposure 레슨에서 찾을 수 있습니다.
광선이 장면의 물체에 부딪히면, 먼저 교차점에서 표면 법선을 계산합니다. 그런 다음 위에서 제공한 방정식을 사용하여 카메라 광선과 관련된 픽셀 색상을 계산합니다:
Vec3f castRay(
const Vec3f &orig, const Vec3f &dir,
const std::vector<std::unique_ptr<Object>> &objects,
const std::unique_ptr<DistantLight> &light,
const Options &options)
{
Vec3f hitColor = options.backgroundColor;
float tnear = kInfinity;
Vec2f uv;
uint32_t index = 0;
Object *hitObject = nullptr;
if (trace(orig, dir, objects, tnear, index, uv, &hitObject)) {
Vec3f hitPoint = orig + dir * tnear;
Vec3f hitNormal;
Vec2f hitTexCoordinates;
hitObject->getSurfaceProperties(hitPoint, dir, index, uv, hitNormal, hitTexCoordinates);
Vec3f L = -light->dir;
// 단일 먼 광원에 의해 조명되는
// 디퓨즈 표면의 색상을 계산합니다.
hitColor = hitObject->albedo / M_PI * light->intensity * light->color
* std::max(0.f, hitNormal.dotProduct(L));
}
return hitColor;
}이것은 방정식의 단순한 적용입니다. 알베도를 (\pi)로 나누면 표면이 받는 것보다 더 많은 빛을 반사하지 않도록 보장합니다. 그런 다음 결과에 빛의 강도를 곱하고, 빛의 색상을 더 곱합니다(이것은 교차점에 입사하는 총 빛 에너지 양을 제공합니다). 이는 교차점에서의 표면 법선과 빛의 방향 사이의 각도의 코사인에 의해 감쇠됩니다.
빛과 표면 법선이 표면 법선에 수직인 평면의 같은 쪽에 있으면 표면 법선과 빛의 방향 사이의 내적 결과는 양수입니다. 그러나 빛이 표면 “뒤”에 있으면 내적 결과는 음수입니다. 물론 빛이 기술적으로 표면 뒤에 있다면 더 이상 표면을 비추지 않아야 하지만, 더 중요한 것은 표면 색상 계산에 음수 값을 도입하고 싶지 않다는 것입니다. 따라서 C++ std::max() 함수를 사용하여 내적 결과를 클램핑합니다(20번째 줄).
다음은 몇 가지 결과입니다:
축하합니다! 이제 두 가지 셰이딩 기법에 대해 알게 되었습니다. 페이싱 비율(facing ratio)과 완벽한 디퓨즈 표면의 외관 시뮬레이션에 대해 알게 되었습니다. 다음 장에서는 하나 이상의 광원 처리와 구형 빛 사용에 대해 배우겠습니다. 또한 이미지에 그림자를 추가하는 방법도 배우겠습니다.
번역이 완료되었습니다. 이 내용은 컴퓨터 그래픽스에서 람베르시안 셰이딩의 수학적 원리와 구현 방법에 대한 상세한 설명입니다.