Physically Based Rendering
PBR은 어떠한 조명 환경에서도 일관되고 사실적으로 보이는 재질을 표현할 수 있게 해 준다.
조명 환경에 따라 값을 미세조정할 필요가 없으므로, 작업 효율도 높일 수 있다.
이 글에서는 BRDF에 대해서 다룬다.
BRDF의 뜻은 Bidirectional Reflectance Distribution Function(양방향 반사도 분포 함수)으로, 불투명한 물체의 빛 반사를 표현한다.
이 외에도 목적에 따라 BTDF, BSDF, BSSRDF 등의 함수가 존재하지만, 이 글에서는 다루지 않는다.
렌더링 방정식
먼저, 렌더링 방정식이라는 큰 그림을 이해해야 한다.
표면의 한 점($p$)에서 나오는 빛에 대한 렌더링 방정식은 다음과 같다.
\[L_o(p,\mathbf{w}_o)=L_e(p,\mathbf{w}_o)+\int_{\Omega}f(p,\mathbf{w}_i,\mathbf{w}_o)L_i(p,\mathbf{w}_i)\left<\mathbf{n}\cdot\mathbf{w}_i\right>\,\operatorname{d}\mathbf{w}_i\]
- $L_o$: 최종적으로 눈으로 들어오는 빛의 양
- $L_i$: 들어오는 빛
- $L_e$: 물체 자체가 내는 빛 (Emissive)
- $\int_{\Omega}$: 반구의 모든 방향에서 들어오는 빛을 모두 누적
- $f$: 표면에 대한 함수 (BRDF)
- $\mathbf{w}_i$: 입사 방향
- $\mathbf{w}_o$: 반사 방향
- $\left<\cdots\right>$: $0$ 이상으로 클램핑
- $\left<\mathbf{n}\cdot \mathbf{w}_i\right>$: 표면의 법선 방향($\mathbf{n}$)과 빛의 입사 방향($\mathbf{w}_i$)의 내적($=\cos\theta_i$)
정리하면 다음과 같다.
\[\underbrace{L_o(p,\mathbf{w}_o)}_{\textrm{Light out}}=\underbrace{L_e(p,\mathbf{w}_o)}_{\textrm{Emissive}}+\int_{\Omega}\underbrace{f(p,\mathbf{w}_i,\mathbf{w}_o)}_{\textrm{BRDF}}\underbrace{L_i(p,\mathbf{w}_i)}_{\textrm{Light in}}\underbrace{\left<\mathbf{n}\cdot\mathbf{w}_i\right>}_{\cos\theta_i}\,\operatorname{d}\mathbf{w}_i\]
여기에서 $\cos\theta_i$는 Lambert의 코사인 법칙에 따른 것으로, 입사각에 따라 받는 조명의 양이 달라지기 때문에 곱하게 된다.
그리고 이 식에서 BRDF를 어떻게 정의하느냐에 따라 표면의 표현이 달라지게 된다.
표면의 물리적인 모델링
PBR을 위한 BRDF를 정의하려면, 먼저 물리 현상에 대해 이해할 필요가 있다.
물체 표면에서의 빛의 반응
먼저, 빛은 물체의 표면에서 다음과 같이 반응한다.

빛이 물체의 표면에 부딪히면, 일부는 반사되고 나머지는 표면을 뚫고 들어가서 내부에서 확산된다.
이를 통해 눈으로 보게 되는 건, 바로 반사되는(굵은 파란색 화살표) 빛과, 내부에서 확산되어 나오는(얇은 초록색 화살표) 빛이다.
만약 내부에서 확산되는 거리가 매우 짧다면(모니터의 한 픽셀보다 훨씬 작은 경우), 아래의 이미지처럼 위의 과정을 단순화할 수 있다.

따라서, BRDF는 위 이미지처럼 내부에서 확산되어 나오는 빛은 $f_{d}$(Diffuse), 표면에서 반사되는 빛은 $f_{r}$(Specular)로 나누어서 다룰 수 있다.
\[f=f_{d}+f_{r}\]
확산되거나 반사되는 정도는 물체의 특성에 따라 달라진다.
일반적으로, 전기가 통하지 않는 나무와 플라스틱 등의 비금속(Dielectic, 절연체 또는 유전체)의 경우에는 대부분 확산되고, 일부만 반사된다.
반면, 전기가 통하는 금속(Conductor)의 경우에는 확산 없이 모두 반사된다.

이미지 자료에서 $f_r$이라는 표현에서의 $r$은 Reflection을 뜻하지만, 이후부터는 Specular라는 표현을 사용하여 첨자에 $s$를 사용하겠다. (e.g. $f_s$)
즉, BRDF는 다음과 같이 구성된다.
\[f=f_{d}+f_{s}\]
미세면(Microfacet) 이론
현실의 표면은 위의 이미지처럼 평평하지 않다.
매끈해 보이는 표면도 미세하게는 울퉁불퉁하고 고르지 못한 면으로 이루어져 있다.
그리고 이런 고르지 못한 정도를 거칠기(Roughness)라고 표현한다.

거칠기에 따라 미세한 표면인 Microfacet이 다양한 방향을 바라보면서 분포하게 된다.

위의 이미지에서 거시적인 표면의 법선 벡터는 $\mathbf{n}$의 방향을 가리키지만, 미세면은 빨간색으로 표시된 다른 방향($\mathbf{m}$)을 가리키게 된다.
그리고 Microfacet BRDF는 이런 미세면들의 분포를 수치적으로 표현해서 현실과 가까운 모습을 묘사한다.
그리고 경우에 따라 미세면이 서로 가려서 빛을 막을 수 있으므로, 이를 고려해야 한다.

위의 이미지는 Shadowing과 Masking이 발생하는 예시다.
Shadowing은 들어오는 빛이 가려지는 것, Masking은 반사되는 빛이 가려지는 것이다.
미리 언급하자면, 이러한 가림 현상 때문에 이후에 문제가 발생하게 된다.
이와 관련해서는 이후에 다루겠다.
BRDF
이후 내용에서 $\mathbf{n}$, $\mathbf{v}$, $\mathbf{l}$, $\mathbf{h}$ 벡터를 언급하게 된다.
각 벡터의 의미는 다음과 같다.

$\mathbf{n}$: Normal 벡터. 거시적 표면의 법선 방향.
$\mathbf{v}$: View 벡터. 시점의 방향.
$\mathbf{l}$: Light 벡터. 광원의 방향.
$\mathbf{h}$: Half 벡터.
$\mathbf{m}$: 미세면의 Normal 벡터
여기에서 $\mathbf{h}$는 $\mathbf{v}$와 $\mathbf{l}$을 통해 구할 수 있다.
\[\mathbf{h}=\frac{\mathbf{v}+\mathbf{l}}{\left\|\mathbf{v}+\mathbf{l}\right\|}\]
셰이더 코드로는 간단하게 normalize(V + L)이 된다.
그리고 위에서 다뤘던 렌더링 방정식은 다음과 같이 간소화 해서 표기할 수 있다.
\[L_o=L_e+\int_{\Omega}f(\mathbf{v},\mathbf{l})L_i\left<\mathbf{n}\cdot\mathbf{l}\right>\,\operatorname{d}\mathbf{l}\]
Specular BRDF
먼저, 반사되는 빛인 Specular($f_s$)에 대해 다루겠다.
Specular는 미세면의 분포에 직접적으로 영향받게 된다.
위의 벡터를 표시한 이미지를 보면, 미세면 중 하나의 노멀 벡터는 $\mathbf{h}$와 일치한다.
$\mathbf{h}$는 $\mathbf{l}$을 반사시켜 $\mathbf{v}$ 방향으로 향하게 만들어서, 관찰하는 시점으로 빛을 직접 향하게 해 준다.
따라서, 이 $\mathbf{h}$를 노멀 벡터로 가지는 미세면을 찾는 것이 목적이다.
그리고 이 미세면을 거울처럼 여겨서, 빛을 얼마나 반사하는지를 구하는 것이 Specular 항이다.
또한, 이 과정에서 이전에 언급했던 Shadowing과 Masking도 고려한다.
이 Specular 항에 주로 사용되는 것은 Cook-Torrance Approximation이다.
\[f_{s}(\mathbf{v},\mathbf{l})=\frac{D(\mathbf{h},\alpha)\,G(\mathbf{v},\mathbf{l},\mathbf{h},\alpha)\,F(\mathbf{v},\mathbf{h},f_{0},f_{90})}{4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>}\]
- $D$ (Normal Distribution Function, NDF):
노멀 방향이 $\mathbf{h}$와 일치(정렬)하는 미세면이 얼마나 분포되어 있는지를 계산한다. - $G$ (Geometry):
미세면이 정렬되어 있더라도 Shadowing과 Masking에 의해 가려지므로, 실제로 얼마나 보이는지를 계산한다. - $F$ (Fresnel):
미세면이 빛을 얼마나 반사하는지를 계산한다. - $4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>$:
미세면 기준으로 계산 한 $D$, $G$, $F$ 함수의 결과를 거시적인 면으로 변환하는데 필요한 보정 계수
$D$, $G$, $F$ 함수의 인자를 보면 모두 $\mathbf{h}$가 들어가는데, 이는 미세면을 기준으로 계산하기 때문이다.
하지만 최종적으로는 거시적인 면의 색상을 구해야 하므로, 이를 보정해야하는 과정이 필요하다.
그리고 그 역할을 분모의 $4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>$가 한다.
왜 이 값인지에 대한 것은 글 하단의 추가 정보 섹션에서 자세히 다루겠다.
다음은 여기에 필요한 각 함수에 대한 내용이다.
$D$, Normal Distribution Function (NDF)
미세면 노멀 벡터의 분포 정도를 구하는 함수다.
여기에는 주로 Trowbridge-Reitz 분포인 GGX를 많이 사용한다.
\[D_{GGX}(\mathbf{h},\alpha)=\frac{\alpha^{2}}{\pi(\left<\mathbf{n}\cdot \mathbf{h}\right>^{2}(\alpha^{2}-1)+1)^{2}}\]
여기에서 $\alpha$는 $\textrm{Roughness}$의 제곱이다.
Burley$^{[\textrm{Burley}]}$에 따르면, $\alpha$를 $\textrm{Roughness}^{2}$로 표현하는 게 보기에 더 선형적으로 변한다고 한다.
따라서, $\alpha^{2}=\textrm{Roughness}^{4}$다.
코드로는 다음과 같다.
// GGX / Trowbridge-Reitz
// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
float D_GGX( float a2, float NoH )
{
float d = ( NoH * a2 - NoH ) * NoH + 1; // 2 mad
return a2 / ( PI * d * d ); // 4 mul, 1 rcp
}
언리얼 엔진의 코드로, 연산 최적화를 위해 이렇게 작성되어 있다.
여기에서 NoH는 $\mathbf{n}$과 $\mathbf{h}$의 내적 값($\left<\mathbf{n}\cdot \mathbf{h}\right>$) 즉, saturate(dot(NormalVector, HalfVector))다.
이와 비슷한 예시로, VoL이라는 변수명은 $\left<\mathbf{v}\cdot\mathbf{l}\right>$라고 이해하면 된다. (다른 비슷한 경우도 마찬가지)

$G$, Geometry
미세면이 실제로 얼마나 보이는지를 구하는 함수다.
$G$ 함수는 Smith의 방식에 따라 근사화 하여 진행한다.
원래는 미세면의 법선인 $\mathbf{m}$에 따라 가려짐이 달라져야 하지만, $\mathbf{m}$과 가려짐은 독립적이라고 가정하여 계산하는 방식이다. (정확하지는 않지만 나름 괜찮다고 한다.)
따라서, 함수의 인자에서 $\mathbf{h}$가 빠진다.
또한, 다음과 같이 Shadowing과 Masking을 따로 분리하여 계산한다.
\[G_2(\mathbf{v},\mathbf{l},\alpha)=G_{1}(\mathbf{v},\alpha)\,G_{1}(\mathbf{l},\alpha)\]
$G_{1}$에는 여러 모델을 사용할 수 있다.
주로 사용되는 GGX는 다음과 같다.
\[G_{1}(\mathbf{v},\alpha)=G_{GGX}(\mathbf{v},\alpha)=\frac{2\left<\mathbf{n}\cdot \mathbf{v}\right>}{\left<\mathbf{n}\cdot \mathbf{v}\right>+\sqrt{\alpha^{2}+(1-\alpha^{2})\left<\mathbf{n}\cdot \mathbf{v}\right>^{2}}}\]
즉, 식을 합친 결과인 Smith-GGX는 다음과 같이 된다.
\[G_2(\mathbf{v},\mathbf{l},\alpha)=\frac{2\left<\mathbf{n}\cdot \mathbf{v}\right>}{\left<\mathbf{n}\cdot \mathbf{v}\right>+\sqrt{\alpha^{2}+(1-\alpha^{2})\left<\mathbf{n}\cdot \mathbf{v}\right>^{2}}}\;\frac{2\left<\mathbf{n}\cdot \mathbf{l}\right>}{\left<\mathbf{n}\cdot \mathbf{l}\right>+\sqrt{\alpha^{2}+(1-\alpha^{2})\left<\mathbf{n}\cdot \mathbf{l}\right>^{2}}}\]
여기에서 눈여겨볼 것은, 분자의 $2\left<\mathbf{n}\cdot \mathbf{v}\right>$과 $2\left<\mathbf{n}\cdot \mathbf{l}\right>$이다.
위에서 적었던 Specular BRDF의 식을 다시 보면,
\[f_{s}=\frac{D\cdot G\cdot F}{4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>}\]
분모에 있는 보정 계수와 상쇄되는 값임을 알 수 있다.
이는 서로 상쇄되므로, 계산을 더 효율적으로 하기 위해 $G$ 함수와 하나로 묶어서 관리하기도 한다.
이렇게 최적화 한 함수를 $V$(Visibility)라고 정의한다.
\[V(\mathbf{v},\mathbf{l},\alpha)=\frac{G(\mathbf{v},\mathbf{l},\alpha)}{4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>}=V_{1}(\mathbf{v},\alpha)\,V_{1}(\mathbf{l},\alpha)\]
\[V_{1}(\mathbf{v},\alpha)=V_{GGX}(\mathbf{v},\alpha)=\frac{1}{\left<\mathbf{n}\cdot \mathbf{v}\right>+\sqrt{\alpha^{2}+(1-\alpha^{2})\left<\mathbf{n}\cdot \mathbf{v}\right>^{2}}}\]
언리얼 엔진의 코드는 다음과 같다.
// Smith term for GGX
// [Smith 1967, "Geometrical shadowing of a random rough surface"]
float Vis_Smith( float a2, float NoV, float NoL )
{
float Vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2 );
float Vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2 );
return rcp( Vis_SmithV * Vis_SmithL );
}
이 코드에서 rcp 함수는 역수의 근삿값을 빠르게 구하는 함수다.
$V$ 함수를 사용한다면 Specular BRDF는 다음과 같이 깔끔하게 계산된다.
\[f_{s}(\mathbf{v},\mathbf{l})=D\cdot V\cdot F\]
Height-correlated Masking and Shadowing
사실 위의 방식은 한계가 있다.
높은 지점은, $\mathbf{v}$와 $\mathbf{l}$에 상관없이 항상 잘 보여야 한다.
따라서 위의 방식으로는 표면이 거칠 수록, 그리고 거시면을 비스듬히 볼 수록 오차가 커진다.
따라서, 미세면의 높이를 고려하여 더 정확하게 계산하는 방은 다음과 같다.
\[G(\mathbf{v},\mathbf{l},\mathbf{h},\alpha)=\frac{\chi^{+}(\mathbf{v}\cdot \mathbf{h})\,\chi^{+}(\mathbf{l}\cdot \mathbf{h})}{1+\Lambda(\mathbf{v})+\Lambda(\mathbf{l})}\]
여기에서 $\chi^{+}(x)$는 $x\leq0$ 이면 $0$을, $x>0$ 이면 $1$을 리턴하는 함수다.
\[\chi^+(x)=\begin{cases}&0\;\;\;\;\text{if}\;x\leq0,\\&1\;\;\;\;\text{if}\;x>0\\\end{cases}\]
$\mathbf{v}\cdot \mathbf{h}$ 또는 $\mathbf{l}\cdot \mathbf{h}$가 $0$ 이하인 경우에는 시점 또는 광원이 표면의 뒷면에 존재해야 하므로, BRDF에서 고려할 필요가 없다.
이런 상황을 걸러내기 위한 역할을 한다고 생각하면 된다.
참고로, $\mathbf{v}\cdot \mathbf{h}$와 $\mathbf{l}\cdot \mathbf{h}$의 값은 동일하다.
$\mathbf{h}$가 $\mathbf{v}$와 $\mathbf{l}$의 중간이기 때문이다.
그리고 $\Lambda$는 다음과 같다.
\[\Lambda(m)=\frac{-1+\sqrt{1+\alpha^{2}\tan^{2}(\theta_{m})}}{2}=\frac{-1+\sqrt{1+\alpha^{2}\frac{(1-\cos^2(\theta_m))}{\cos^2(\theta_m)}}}{2}\]
$m$의 각도인 $\theta_{m}$의 코사인 값이 필요한데, 이는 $\mathbf{v}$ 또는 $\mathbf{l}$을 대입하는 경우, $\mathbf{n}\cdot \mathbf{v}$와 $\mathbf{n}\cdot \mathbf{l}$으로 표현 가능하다.
따라서, 다음과 같이 정리할 수 있다.
\[\Lambda(\mathbf{v})=\frac{1}{2}\left(\frac{\sqrt{\alpha^2+(1-\alpha^{2})\left<\mathbf{n}\cdot \mathbf{v}\right>^2}}{\left<\mathbf{n}\cdot \mathbf{v}\right>}-1\right)\]
최종적으로 다음과 같이 된다.
\[V(\mathbf{v},\mathbf{l},\alpha)=\frac{0.5}{\left<\mathbf{n}\cdot \mathbf{l}\right>\sqrt{\left<\mathbf{n}\cdot \mathbf{v}\right>^2(1-\alpha^2)+\alpha^2}\;+\;\left<\mathbf{n}\cdot \mathbf{v}\right>\sqrt{\left<\mathbf{n}\cdot \mathbf{l}\right>^2(1-\alpha^2)+\alpha^2}}\]
언리얼 엔진의 코드는 다음과 같다.
// [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"]
float Vis_SmithJoint(float a2, float NoV, float NoL)
{
float Vis_SmithV = NoL * sqrt(NoV * (NoV - NoV * a2) + a2);
float Vis_SmithL = NoV * sqrt(NoL * (NoL - NoL * a2) + a2);
return 0.5 * rcp(Vis_SmithV + Vis_SmithL);
}
언리얼 엔진 5.7 기준으로, $V$에 이 함수를 사용한다.


$F$, Fresnel
마지막 함수인 $F$는, 빛을 얼마나 반사하는지에 대한 함수다.
여기에서는 표면의 기울기에 따라서 빛을 반사하는 정도가 달라지는 프레넬 효과를 묘사한다.
일반적으로, 표면을 비스듬하게 볼수록 반사를 많이 하고, 수직으로 볼 수록 반사가 적어진다.
다음 gif처럼, 조명이 표면에 비스듬해질수록 빛을 더 많이 반사하여 밝아진다.

$F$ 함수에는 주로 Schlick 식을 쓴다.
\[F_{Schlick}(\mathbf{v},\mathbf{h},f_0,f_{90})=f_0+(f_{90}-f_0)(1-\left<\mathbf{v}\cdot \mathbf{h}\right>)^5\]
여기에서 $f_0$는 표면을 수직으로 바라봤을 때의 반사 정도(또는 색상)를, $f_{90}$는 표면을 비스듬하게 바라봤을 때(Grazing-angle)의 반사 정도(또는 색상)를 의미한다.
숫자가 각도라고 생각하면 된다. (수직: $0^{\circ}$, 비스듬 또는 수평: $90^{\circ}$)
따라서, 재질에 따라서 여기에 값을 다르게 지정하면 된다.
대신, $f_{90}$는 거의 모든 경우 완전한 하얀색이다.
위의 gif에서 조명이 비스듬해질수록 하얀색이 반사되는 것처럼.
따라서 식을 다음과 같이 적기도 한다.
\[F_{Schlick}(\mathbf{v},\mathbf{h},f_0)=f_0+(1-f_0)(1-\left<\mathbf{v}\cdot \mathbf{h}\right>)^5\]
$f_0$는 Specular Color라고 부르기도 한다.
말 그대로 반사 색상이다.
언리얼 엔진 코드는 다음과 같다.
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float3 F_Schlick( float3 SpecularColor, float VoH )
{
float Fc = Pow5( 1 - VoH ); // 1 sub, 3 mul
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
// Anything less than 2% is physically impossible and is instead considered to be shadowing
return saturate( 50.0 * SpecularColor.g ) * Fc + (1 - Fc) * SpecularColor;
}
float3 F_Schlick(float3 F0, float3 F90, float VoH)
{
float Fc = Pow5(1 - VoH);
return F90 * Fc + (1 - Fc) * F0;
}
언리얼 엔진 5.7 기준으로, 아래의 $f_{90}$을 사용하는 함수를 사용한다.
식을 보면 $f_0+(f_{90}-f_0)Fc$ 아닌, $f_{90}Fc+(1-Fc)f_0$로 계산한다. ($Fc=(1-\left<\mathbf{v}\cdot \mathbf{h}\right>)^5$)
전개해 보면 같은 식이지만, 이렇게 작성한 식을 기억해 두면 좋다.

Specular BRDF 결과
모든 함수의 결과를 반영한 Cook-Torrance Specular의 결과는 다음과 같다.
참고로, 아래의 이미지는 렌더링 방정식의 $\cos\theta_i$를 곱한 결과다.


float3 CookTorranceSpecular(float3 F0, float Roughness, float NoL, float NoV, float NoH, float VoH)
{
float alpha = Roughness * Roughness;
float a2 = alpha * alpha;
float D = D_GGX(a2, NoH);
float3 F = F_Schlick(F0, VoH);
float Vis = Vis_SmithJoint(a2, NoV, NoL);
return D * Vis * F;
}
Diffuse BRDF
다음으로, 산란하는 빛인 Diffuse다.
Lambertian reflectance (Lambertian BRDF)
Diffuse에는 가장 기본적으로, 완전 산란을 가정하는 Lambertian reflectance가 있다.
여기에서는, 산란되는 빛이 표면과 수직인 방향(노멀 벡터)으로 많이 퍼진다고 가정한다.
그리고 방출되는 에너지는 수직 방향과의 각도($\theta$)에 비례해서 감소($\cos\theta$)한다.

이 표면에서는 모든 방향으로 퍼지는 빛의 에너지를 모두 더하면 $\pi$가 된다.
이를 직관적으로 이해하려면, 위의 이미지에서 빨간색 선으로 퍼지는 면적의 넓이를 구하면 된다.

에너지가 퍼지는 범위는 지름이 $1$인 원 모양이고, 3차원에서는 구체 모양으로 퍼지게 된다.
구의 겉넓이 공식은 $4\pi r^2$이고 반지름($r$)은 $1/2$이므로, 최종적으로 $\pi$가 나온다.
여기에서 에너지 보존 법칙을 고려하면, 들어온 에너지가 $1$일때 모든 방향으로 퍼지는 빛의 에너지는 $1$을 넘으면 안된다.
따라서, 한 점으로 산란되는 빛의 에너지는 $1/\pi$의 크기를 가진다.
따라서, 산란되는 색상을 $\pi$로 나눈 값을 사용한다.
관련하여 더 자세한 내용은 글 하단의 추가 정보 섹션에서 자세히 다루하겠다.
\[f_d=\frac{\textrm{Diffuse Color}}{\pi}\]
셰이더 코드로는 간단하게 디퓨즈 색상(Albedo)을 $\pi$로 나누면 된다.
성능에도 부담이 적기 때문에, 가장 많이 쓰이는 방식이다.
#define PI 3.14159265359
float3 Diffuse_Lambert(float3 DiffuseColor)
{
return DiffuseColor / PI;
}
Rough Diffuse
Lambertian reflectance의 한계는, 모든 표면이 매끄럽다고 가정했다는 점이다.
하지만, 현실의 재질은 거친 표면을 가지고 있기 때문에, 실제로 보이는 것과는 차이가 존재한다.
따라서, 디퓨즈 모델에도 미세면 이론을 도입하게 되었고, 이것이 러프 디퓨즈다.
러프 디퓨즈에서 구현하고자 했던 핵심적인 현상은 역반사(Retro-reflection)다.
Lambertian reflectance에서 가정한 것과 달리, 현실의 거친 표면에서는 빛이 들어온 방향으로 더 많이 반사되는 성질이 있다.
따라서, 조명의 위치에서 물체를 바라보면, 물체가 전체적으로 납작한 것처럼 보이게 된다.
러프 디퓨즈는 이러한 효과를 구현한다.
러프 디퓨즈는 여러 모델이 있고, 최근에도 새로운 모델들이 나오고 있다.
- Disney(Burley)$^{[\textrm{Burley}]}$
- Oren-Nayar$^{[\textrm{ON}]}$
- Chan$^{[\textrm{Chan}]}$
- VMF$^{[\textrm{VMF}]}$
- EON(Energy-preserving Oren-Nayar)$^{[\textrm{EON}]}$
- ⋯
언리얼 엔진의 경우, 5.7 버전에서 Substrate의 정식 도입 후, 기본 값으로 러프 디퓨즈를 사용한다.
조금 더 자세한 정보는 다음 링크의 글에서 확인할 수 있다.
https://mstone8370.tistory.com/57


이 글에서는 러프 디퓨즈의 대표적인 모델이면서도 가장 간단한 Disney Diffuse를 다루겠다.
Disney Diffuse (Burley)
이 모델은 현실의 다양한 재질에 대한 관찰을 기반으로 제작되어, 아티스트가 보기에도 더 좋아 보이게 해주는 모델이라고 한다$^{[\textrm{Burley}]}$.
\[f_d=\frac{\textrm{Diffuse Color}}{\pi}\left(1+(f_{D90}-1)(1-\cos\theta_{\mathbf{l}})^5\right)\left(1+(f_{D90}-1)(1-\cos\theta_{\mathbf{v}})^5\right)\]
\[f_{D90}=0.5+2\,\textrm{Roughness}\,\left<\mathbf{v}\cdot\mathbf{h}\right>^2\]
언리얼 엔진 코드는 다음과 같다.
// [Burley 2012, "Physically-Based Shading at Disney"]
float3 Diffuse_Burley( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
{
float FD90 = 0.5 + 2 * VoH * VoH * Roughness;
float FdV = 1 + (FD90 - 1) * Pow5( 1 - NoV );
float FdL = 1 + (FD90 - 1) * Pow5( 1 - NoL );
return DiffuseColor * ( (1 / PI) * FdV * FdL );
}
아니면, Fresnel 함수에 Schlick을 사용하고 $f_{90}$ 파라미터를 사용한다면, 아래와 같이 구현할 수도 있다.
float Pow5(float x)
{
return x * x * x * x * x;
}
float3 F_Schlick(float3 F0, float3 F90, float VoH)
{
float Fc = Pow5(1 - VoH);
return F90 * Fc + (1 - Fc) * F0;
}
float3 Diffuse_Burley( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
{
float FD90 = 0.5 + 2 * VoH * VoH * Roughness;
float LightScatter = F_Schlick(1.0, FD90, NoL);
float ViewScatter = F_Schlick(1.0, FD90, NoV);
return DiffuseColor * LightScatter * ViewScatter * (1.0 / PI);
}
Disney Diffuse를 Lambertian reflectance와 비교하면 다음과 같다.

Metallic-Roughness 워크플로우
지금까지 다룬 BRDF를 계산하기 위해 추가적으로 필요한 재질에 대한 정보는 다음과 같다.
- Diffuse Color (Albedo)
- Specular Color (F0)
- Roughness
각 값을 어떻게 지정하느냐에 따라 물체의 특성이 달라진다.
이 값들을 직접 제어하는 건 앞으로 설명할 Metallic-Roughness 워크플로우보다는, Specular-Glossiness 워크플로우에 가깝다.
$\left ( \textrm{Roughness}=1-\textrm{Glossiness} \right )$
이 방식의 문제점은, Diffuse Color와 Specular Color를 직접 지정할 수 있다 보니, 물리적으로 불가능한 조합을 만들 수 있다는 점이다.
이전에 언급했듯이, 비금속의 경우에는 확산의 비중이 크고, 금속의 경우에는 반사의 비중이 크다.
하지만, 확산의 색상과 반사의 색상을 직접 지정할 수 있다 보니, 둘 다 밝게 하여 확산과 반사를 모두 많이 하는, 물리적으로 불가능한 재질을 만들 수 있게 된다.
이러면 표면에 들어오는 빛보다 나오는 빛이 더 많아지게 되어 에너지 보존 법칙도 따르지 않게 된다.
이러한 문제는 이 글에서 다룬 금속 및 비금속 물체뿐만 아니라, 다른 재질을 위한 모델에서도 발생했다.
따라서, Burley$^{[\textrm{Burley}]}$는 Principled BRDF를 제안하여 파라미터를 단순화했고, 이 파라미터 중 하나가 Metallic이다.
Metallic을 사용하면 파라미터는 다음과 같이 된다.
- Base Color
- Metallic
- Roughness
Metallic은 이름 그대로 금속성을 나타낸다.
Metallic이 $0$이면 비금속을, $1$이면 금속을 의미한다.
그리고 Metallic 값에 따라 Base Color를 선형 보간하여 Diffuse Color로 쓸지, 아니면 Specular Color로 쓸지 결정하게 된다.
비금속은 대부분 확산된 빛을, 금속은 대부분 반사된 빛을 보기 때문이다.
float3 F0 = lerp(0.04, BaseColor, Metallic); // Specular Color
float KdScale = 1.0 - Metallic; // Diffuse Energy
float3 DiffuseColor = BaseColor * KdScale;
코드를 통해 알 수 있듯이, Metallic 값에 따라 일부는 Diffuse Color로, 나머지는 Specular Color로 정해진다.
여기에서 $0.04$라는 값은, 플라스틱과 같은 일반적인 비금속은 평균적으로 약 $0.04$ 정도의 반사율을 가지기 때문에, 이 값 이하의 일반적이지 않은 경우를 막기 위함이다.
조명 계산 코드
지금까지 진행한 것을 셰이더 코드로 작성하기 위해 이전에 다뤘던 렌더링 방정식을 다시 봐야 한다.
\[L_o=L_e+\int_{\Omega}f(\mathbf{v},\mathbf{l})L_i\left<\mathbf{n}\cdot\mathbf{l}\right>\,\operatorname{d}\mathbf{l}\]
여기에서 $f(\mathbf{v},\mathbf{l})$은 지금까지 다뤘던 Diffuse + Specular BRDF다.
$L_i$는 현재 계산해야 할 조명의 색상과 밝기, $\left<\mathbf{n}\cdot\mathbf{l}\right>$은 표면의 기울기에 따라 들어오는 빛의 양에 대한 것이다.
적분 과정은 주변의 직접광을 하나씩 순환하면서 누적하면 된다.
$L_e$의 경우, 이 물체 자체가 빛을 내고 있다면 그 값을 그대로 더하면 된다.
따라서, 다음 코드와 같이 최종적으로 BRDF를 계산할 수 있다.
float3 N = WorldNormal;
float3 V = normalize(ViewWorldPosition - WorldPosition);
float3 L = normalize(LightWorldPosition - WorldPosition);
float3 H = normalize(V + L);
float VoL = saturate(dot(V, L));
float NoL = saturate(dot(N, L));
float NoV = saturate(dot(N, V));
float VoH = saturate(dot(V, H));
float NoH = saturate(dot(N, H));
float3 F0 = lerp(0.04, BaseColor, Metallic);
float KdScale = 1.0 - Metallic;
float3 DiffuseColor = BaseColor * KdScale;
Roughness = max(0.025, Roughness); // 안정성을 위한 최소 Roughness값 제한
float3 DiffuseContribution = Diffuse_Burley(DiffuseColor, Roughness, NoV, NoL, VoH);
float3 SpecularContribution = CookTorranceSpecular(F0, Roughness, NoL, NoV, NoH, VoH);
float3 TotalBRDF = DiffuseContribution + SpecularContribution;
float3 FinalColor = TotalBRDF * LightIntensity * LightColor * NoL;
렌더 결과는 다음과 같다.

조명이 하나뿐이어서 어색해 보인다.
이 글에서 다루지 않았지만, Image Based Lighting(IBL)을 통해 주변에 조명을 추가하면 다음과 같다.


에너지 보존
이쯤에서 에너지 보존에 관해서 조금 더 다룰 필요가 있다고 생각한다.
에너지 보존 법칙에 따르면, 나오는 빛의 에너지는 들어온 빛의 에너지와 같거나 작아야 한다. (일부는 흡수)
지금까지 다룬 식은 Diffuse BRDF와 Metallic을 통해 이를 지키기 위해 노력했다.
하지만, 현재 방식으로는 거친 표면에서 에너지를 너무 많이 잃는 문제가 발생한다.
위의 이미지에서 Roughness가 높은 금속 재질을 보면 과도하게 어두워지는 결과를 통해 이를 확인할 수 있다.
이러한 문제가 발생하는 이유는, 미세면에서 한 번만 반사되는 빛만 고려했기 때문이다. (Single-scattering)
미세면 이론을 다룰 때, Shadowing과 Masking에 대해 언급했다.
그리고 이러한 현상에 의해 미세면이 가려진 경우에는 보이지 않음을 가정했다.

하지만, 현실에서는 Shadowing과 Masking에 의해 빛이 막혔더라도, 여러 차례의 반사에 의해서 미세면에 빛이 들어오거나 빛이 반사될 수 있다. (Multi-scattering)

이 문제를 해결하기 위해 에너지를 보상하는 방법을 사용하고, 그 결과는 다음과 같다.

따라서, 나오는 빛이 과도해질 것을 고려해야 할 뿐만 아니라, 과도하게 잃지도 않게 고려해야 한다.
Multi-Scattering과 관련해서는 현재 시점에서는 적용이 어렵고, 이후에 기회가 된다면 다루겠다.
참고 문헌 및 자료
Google Filament. Physically Based Rendering in Filament. [Link]
[$\textrm{Burley}$] Brent Burley. 2012. Physically-Based Shading at Disney. SIGGRAPH 2012 Course. [Link]
Sébastien Lagarde & Charles de Rousiers. 2014. Moving Frostbite to Physically Based Rendering 3.0. SIGGRAPH 2014 Course. [Link]
Christopher Kulla & Alejandro Conty. 2017. Revisiting Physically Based Shading at Imageworks. SIGGRAPH 2017 Course. [Link]
[$\textrm{ON}$] Michael Oren, Shree K. Nayar. 1994. Generalization of Lambert’s Reflectance Model. SIGGRAPH, 239–246. [Link]
[$\textrm{Chan}$] Danny Chan. 2018. Material Advances in Call of Duty: WWII. SIGGRAPH 2018 Course. [Link]
[$\textrm{VMF}$] Eugene d’Eon, Andrea Weidlich. 2024. VMF Diffuse: A unified rough diffuse BRDF. Computer Graphics. [Link]
[$\textrm{EON}$] Jamie Portsmouth, Peter Kutz, Stephen Hill. 2025. EON: A Practical Energy-Preserving Rough Diffuse BRDF. Journal of Computer Graphics Techniques (JCGT), vol. 14, no. 1 [Link]
Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Technique (JCGT), vol. 3, no. 2 [Link]
Earl Hammon, Jr. 2017. PBR Diffuse Lighting for GGX+Smith Microsurfaces. SIGGRAPH 2017. [Link]
추가 정보
Lambertian reflectance
Lambertian reflectance는, 산란되는 빛이 표면과 수직인 방향(노멀 벡터)으로 많이 퍼진다고 가정한다.
그리고 방출되는 에너지는 수직 방향과의 각도($\theta$)에 비례해서 감소($\cos\theta$)한다.

이 표면을 눈으로 보면, 표면을 어느 각도로 보든 상관없이 일정한 밝기로 보인다.
그런데 가정에 따르면, 표면을 비스듬하게 볼수록 눈에 도달하는 에너지는 분명 감소해야 한다.
하지만, 표면을 비스듬하게 볼수록 한 지점에 모이는 표면의 넓이는 더 넓어지므로($1/\cos\theta$), 방출되는 에너지들이 모여서 서로 상쇄되어 밝기가 일정하게 유지된다.
이러한 표면에서 산란되는 빛을 모두 더하는 건, 다음과 같은 식으로 표현할 수 있다.
\[E=\int_\Omega L_o\cos\theta\,\operatorname{d}\omega\]
여기에서 들어오는 빛인 $L_i$는 $1$로 가정하고, 나오는 빛인 $L_o$는 빛이 가장 많이 방출되는 곳인 $\cos (0)$에서 $1$이므로, $L_o$ 또한 $L_i$와 동일하게 $1$이 된다.
그리고 $\operatorname{d}\omega$는 미소 입체각으로, 구면좌표계에 따라 $\operatorname{d}\omega=\sin\theta\,\operatorname{d}\theta\,\operatorname{d}\phi$ 가 된다.
구면좌표계는 3차원 공간의 점을 나타내는 좌표계다.

$r$은 거리, $\theta$는 수직 각도, $\phi$는 수평 각도를 의미한다.
따라서, 각 값들의 범위는 다음과 같이 제한된다.
$0\leq r$
$0\leq\theta\leq\pi$
$0\leq\phi<2\pi$
구면 좌표계를 적분할 때는 다음과 같이 $\sin\theta$가 붙는다.
\[r^2\int_0^{2\pi}\int_0^{\pi}\sin\theta\,\operatorname{d}\theta\,\operatorname{d}\phi\]
이를 이해하기 위해서는, 구의 면을 작은 사각형으로 나누어서 생각하면 된다.

이런 방식으로 면을 더 작게 쪼개서 각 면의 넓이를 모두 더하는 과정이 적분이다.
이 면들은 수평 각도인 $\phi$에 따라서는 동일한 크기를 가지지만, 수직 각도인 $\theta$에는 영향을 받게 된다.

이렇게 나뉜 사각형의 높이는 $\theta$에 따라 일정하게 나뉘었으니 동일하지만, 윗변과 아랫변의 길이는 $\theta$에 따라 달라진다.
그리고, 윗변과 아랫변의 길이는 $\sin\theta$의 형태를 따르며 달라진다.


따라서, 적분 식에 $\sin\theta$가 붙는다.
그리고 적분을 해보면, 구의 겉넓이 공식인 $4\pi r^2$가 나온다.
다시 Lambertian reflectance로 돌아와서, 기존의 식은 다음과 같이 표현할 수 있게 된다.
\[\begin{align}E&=\int_\Omega L_o\cos\theta\,\operatorname{d}\omega\\&=\int_0^{2\pi}\int_0^{\pi/2}\cos\theta\sin\theta\,\operatorname{d}\theta\,\operatorname{d}\phi \end{align} \]
$\theta$를 적분할 때는, 반구 범위만큼 해야 하므로, $0$에서 $\pi/2$까지 한다.
적분 결과는 다음과 같다.
\[\begin{align} E&=\int_0^{2\pi}\int_0^{\pi/2}\cos\theta\sin\theta\,\operatorname{d}\theta\,\operatorname{d}\phi\\&=\int_0^{2\pi}\int_0^{\pi/2}\frac{1}{2}\sin2\theta\,\operatorname{d}\theta\,\operatorname{d}\phi\\&=\int_0^{2\pi}\frac{1}{2}\,\operatorname{d}\phi\\&=\pi \end{align} \]
Specular BRDF 유도
\[ f_{s}(\mathbf{l},\mathbf{v})=\frac{D(\mathbf{h})G(\mathbf{l},\mathbf{v},\mathbf{h})F(\mathbf{v},\mathbf{h})}{4\left<\mathbf{n}\cdot\mathbf{v}\right>\left<\mathbf{n}\cdot\mathbf{l}\right>}\]
Cook-Torrance Specular 식의 보정 계수는 미세면 기준인 $D$, $G$, $F$ 함수를 거시면으로 변환하는 역할을 한다.
이 값인 $\frac{1}{4\left<\mathbf{n}\cdot \mathbf{v}\right>\left<\mathbf{n}\cdot \mathbf{l}\right>}$이 어디에서 나온 건지 이해하려면, 미세면 이론에 대해 더 깊게 이해할 필요가 있다.
미세면들은 크기가 너무 작아서 화면의 한 픽셀에도 수많은 미세면이 존재한다.
따라서, 지금까지 다룬 Specular 항은 이 수많은 미세면들이 빛에 반응한 결과를 모두 적분한 결과다.
일반적인 미세면의 BRDF는 다음과 같다.
\[\int_{\Omega}\rho_\mathbf{m}(\mathbf{l},\mathbf{v},\mathbf{m})D(\mathbf{m})G_2(\mathbf{l},\mathbf{v},\mathbf{m})\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\operatorname{d}\mathbf{m}\]
이 식에서 $\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}$는 각각 미세면이 빛에 대해서 어느 정도의 크기로 보이는지, 보는 입장에서 어느 정도의 크기로 보이는지를 나타낸다.
그리고, $\rho_\mathbf{m}$은 미세면이 빛에 어떻게 반응하는지에 대한 함수다.
$D$ 함수에 대해 조금 더 알아보면, 식이 왜 이렇게 구성되는지 알 수 있다.
$D$ 함수는 미세면의 법선($\mathbf{m}$)이 거칠기에 따라 어떻게 분포하는지를 나타낸다. ($\mathbf{m}$에 대한 확률 밀도 함수)
그리고 위에서 다뤘던 GGX의 식을 보면 알겠지만, 이 값의 범위는 $\left [ 0, 1 \right ]$이 아닌 $\left [ 0, \infty \right ]$의 범위를 가진다.
$D$를 적분하면 모든 미세면의 면적을 더한 것이 되는데, 이렇게 되면 완전히 매끄러운 표면에서는 1을, 조금이라도 거칠기가 있다면 1을 초과하게 된다.
\[\int_{\Omega}D(\mathbf{m})\operatorname{d}\mathbf{m}\]
하지만, 이 미세면들을 거시면에 투영하여 적분한다면, 거칠기에 상관없이 항상 1이 된다.
\[\int_{\Omega}D(\mathbf{m})\cos\theta_\mathbf{m}\operatorname{d}\mathbf{m}=1,\;\;\;\;\cos\theta_\mathbf{m}=\mathbf{m}\cdot\mathbf{n}\]
이것이 $D$ 함수의 정규화 조건이다.
그리고 여기에 표면에 대한 함수($\rho$)와 미세면이 서로 얼마나 가리는지($G$), 거시면 대비 미세면이 어느 정도로 보이는지($\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}$)를 추가로 고려하면 일반적인 미세면의 BRDF가 된다.
여기에서 미세면을 완전한 거울($\textrm{입사각} = \textrm{반사각}$)이라고 가정한다면 적분을 쉽게 풀 수 있고, 위에서 다뤘던 Cook-Torrance Specular 식이 된다.
\[\int_{\Omega}\rho_\mathbf{m}(\mathbf{l},\mathbf{v},\mathbf{m})D(\mathbf{m})G_2(\mathbf{l},\mathbf{v},\mathbf{m})\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\operatorname{d}\mathbf{m}\;\xrightarrow{\rho_m=\text{거울}}\;\frac{D(\mathbf{h})\,G_2(\mathbf{v},\mathbf{l},\mathbf{h})\,F(\mathbf{v},\mathbf{h})}{4\langle\mathbf{n}\cdot\mathbf{v}\rangle\langle\mathbf{n}\cdot\mathbf{l}\rangle}\]
완전 거울의 표면에 대한 함수는 다음과 같이 표현한다.
\[\rho_\mathbf{m}(\mathbf{l},\mathbf{v},\mathbf{m})=k\delta_\mathbf{m}(\mathbf{h},\mathbf{m})\]
- $k$: 정규화 상수(Normalization factor)
- $\delta_\mathbf{m}(\mathbf{h},\mathbf{m})$: $\mathbf{m}$에 대한 디랙 델타(Dirac delta)
디랙 델타는 분포를 나타내는데, 특정한 한 지점에서만 무한대의 값을 가지고 나머지는 $0$인 함수라고 이해하면 쉽다.
따라서 임의의 연속 함수 $f(x)$에 대해 다음 식을 만족하는 함수를 디랙 델타라고 한다.
\[\int_{-\infty}^{\infty}f(x)\cdot\delta(x-a)\operatorname{d}x=f(a)\]
조금 더 직관적으로 이해하려면, 거울을 생각하면 쉽다.
거울은 노멀 벡터($\mathbf{m}$)가 $\mathbf{l}$과 $\mathbf{v}$의 중간인 $\mathbf{h}$일 때, 즉 $\mathbf{m}=\mathbf{h}$일 때에만 빛을 반사하고, 그 외에는 빛을 반사하지 못한다.
이런 거울의 특징을 디랙 델타로 표현할 수 있다.
여기에서 이전에 다뤘던 정규화 조건을 반사에 대해 적용하면, 반사되는 빛을 모두 누적했을 때에는 1이 됨을 표현할 수 있다.
\[\int_{\Omega}\rho(\mathbf{l},\mathbf{v},\mathbf{n})\cos\theta_\mathbf{v}\operatorname{d}\mathbf{v}=1\]
그리고 표면에 대한 함수에 디랙 델타를 적용하면 다음과 같이 된다.
\[\int_{\Omega}k\delta_\mathbf{m}(\mathbf{h},\mathbf{m})\cos\theta_\mathbf{v}\frac{\operatorname{d}\mathbf{v}}{\operatorname{d}\mathbf{m}}\operatorname{d}\mathbf{m}=1\]
그리고 이 식을 만족하는 정규화 상수인 $k$를 찾아야 한다.
먼저, $\frac{\operatorname{d}\mathbf{v}}{\operatorname{d}\mathbf{m}}$는 $\mathbf{m}$의 움직임에 비해서 $\mathbf{v}$가 어느 정도로 움직이는지에 관한 것이다.
그리고 디랙 델타에 의해 $\mathbf{m}$은 한 지점만 선택되어 $\mathbf{h}$가 된다. ($\operatorname{d}\mathbf{m}=\operatorname{d}\mathbf{h}$)
변수를 줄이기 위해 $\mathbf{l}$을 고정하면, $\operatorname{d}\mathbf{v}$와 $\operatorname{d}\mathbf{h}$의 관계는 아래의 이미지처럼 표현된다.

여기에서 $\operatorname{d}\mathbf{v}$ 면적과 $\operatorname{d}\mathbf{h}$ 면적의 비율을 구해야 한다. (호가 아닌 입체각임에 주의)
이 두 면적의 비율을 구하기 위해, 아래 이미지와 같이 $\operatorname{d}\mathbf{v}$의 위치를 옮겨서 $\mathbf{l}+\mathbf{v}$의 중심에 위치하도록 한다.

이 $\operatorname{d}\mathbf{v}$ 면적을 길이가 $\mathbf{l}+\mathbf{v}$인 구에 투영하면 아래 이미지의 검은색으로 표현한 입체각의 면적이 된다.

이렇게 $\mathbf{l}+\mathbf{v}$ 구에 투영된 검은색 입체각의 면적은 $\cos\theta_\mathbf{v}\operatorname{d}\mathbf{v}$가 된다. ($\cos\theta_\mathbf{v}=(\mathbf{h}\cdot\mathbf{v})$)

이렇게 구한 검은색 입체각 면적을 스케일링하면 $\operatorname{d}\mathbf{h}$ 입체각의 면적을 구할 수 있다.
반지름의 길이가 $\mathbf{l}+\mathbf{v}$인 구에 투영했으니, 다음 값만큼 스케일링하면 된다.
\[\frac{4\pi\,1^2}{4\pi\,\left\|\mathbf{l}+\mathbf{v}\right\|^2}=\frac{1}{\left\|\mathbf{l}+\mathbf{v}\right\|^2}\]
따라서 $\operatorname{d}\mathbf{v}$와 $\operatorname{d}\mathbf{m}$의 관계는 다음과 같다.
\[\operatorname{d}\mathbf{m}=\frac{\mathbf{h}\cdot\mathbf{v}}{\left\|\mathbf{l}+\mathbf{v}\right\|^2}\operatorname{d}\mathbf{v}\]
그리고 $\mathbf{l}+\mathbf{v}$는 $2(\mathbf{h}\cdot\mathbf{v})$로 표현할 수 있다.

따라서, 최종적으로 다음과 같다.
\[\begin{align}\operatorname{d}\mathbf{m}=\frac{1}{4(\mathbf{h}\cdot\mathbf{v})}\operatorname{d}\mathbf{v}\\\frac{\operatorname{d}\mathbf{v}}{\operatorname{d}\mathbf{m}}=4(\mathbf{h}\cdot\mathbf{v})\end{align}\]
이 값이 $\mathbf{m}$ 공간에서 $\mathbf{v}$ 공간으로 변환하는데 필요한 값이다.
다시 미세면의 BRDF로 돌아와서 보면 이제 $k$의 값을 구할 수 있다.
\[\int_{\Omega}k\delta_\mathbf{m}(\mathbf{h},\mathbf{m})\cos\theta_\mathbf{v}\frac{\operatorname{d}\mathbf{v}}{\operatorname{d}\mathbf{m}}\operatorname{d}\mathbf{m}=1\]
\[\int_{\Omega}k\delta_\mathbf{m}(\mathbf{h},\mathbf{m})(\mathbf{m}\cdot\mathbf{v})4(\mathbf{h}\cdot\mathbf{v})\operatorname{d}\mathbf{m}=1\]
여기에서 디랙 델타에 의해 $\mathbf{m}=\mathbf{h}$인 경우만 고려하면 되니
\[\cos\theta_\mathbf{v}=(\mathbf{m}\cdot\mathbf{v})=(\mathbf{h}\cdot\mathbf{v})\]
가 되고, 식은 다음과 같아진다.
\[\int_{\Omega}k\delta_\mathbf{m}(\mathbf{h},\mathbf{m})4(\mathbf{h}\cdot\mathbf{v})^2\operatorname{d}\mathbf{m}=1\]
\[k=\frac{1}{4(\mathbf{h}\cdot\mathbf{v})^2}\]
따라서, 미세면이 완전한 거울이라고 가정했을 때의 $\rho_\mathbf{m}$는 최종적으로 다음과 같다.
\[\rho_\mathbf{m}=\frac{\delta_\mathbf{m}(\mathbf{h},\mathbf{m})}{4(\mathbf{h}\cdot\mathbf{v})^2}\]
미세면을 거울이라고 가정했지만, 모든 빛을 그대로 반사하지는 않는다.
입사각($\mathbf{l}$)에 따라 빛이 반사되는 정도가 달라지고, 그것을 표현한 것인 프레넬($F$) 항이다.
따라서, 프레넬을 반영한 $\rho_\mathbf{m}$은 다음과 같다.
\[\rho_\mathbf{m}=F(\mathbf{l},\mathbf{m})\frac{\delta_\mathbf{m}(\mathbf{h},\mathbf{m})}{4(\mathbf{h}\cdot\mathbf{v})^2}\]
이렇게 구한 $\rho_\mathbf{m}$을 미세면 BRDF에 대입하면 다음과 같다.
\[\int_{\Omega}\rho_\mathbf{m}(\mathbf{l},\mathbf{v},\mathbf{m})D(\mathbf{m})G_2(\mathbf{l},\mathbf{v},\mathbf{m})\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\operatorname{d}\mathbf{m}\]
\[\int_{\Omega}F(\mathbf{l},\mathbf{m})\frac{\delta_\mathbf{m}(\mathbf{h},\mathbf{m})}{4(\mathbf{h}\cdot\mathbf{v})^2}D(\mathbf{m})G_2(\mathbf{l},\mathbf{v},\mathbf{m})\frac{\langle\mathbf{m}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{m}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\operatorname{d}\mathbf{m}\]
그리고 디랙 델타에 의해 $\mathbf{m}=\mathbf{h}$인 경우만 남게 된다.
\[\frac{F(\mathbf{l},\mathbf{h})D(\mathbf{h})G_2(\mathbf{l},\mathbf{v},\mathbf{h})}{4(\mathbf{h}\cdot\mathbf{v})^2}\frac{\langle\mathbf{h}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{h}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\]
그리고 미세면은 입사각과 반사각이 동일한 완전한 거울이라고 가정했기 때문에, $(\mathbf{h}\cdot\mathbf{v})$와 $(\mathbf{h}\cdot\mathbf{l})$은 동일하다.
\[\frac{F(\mathbf{l},\mathbf{h})D(\mathbf{h})G_2(\mathbf{l},\mathbf{v},\mathbf{h})}{4(\mathbf{h}\cdot\mathbf{l})(\mathbf{h}\cdot\mathbf{v})}\frac{\langle\mathbf{h}\cdot\mathbf{l}\rangle}{|\mathbf{n}\cdot\mathbf{l}|}\frac{\langle\mathbf{h}\cdot\mathbf{v}\rangle}{|\mathbf{n}\cdot\mathbf{v}|}\]
렌더링에서 앞면만 처리하므로 $(\mathbf{h}\cdot\mathbf{l}) \geq 0$, $(\mathbf{h}\cdot\mathbf{v}) \geq 0$이 보장된다. 따라서 분자의 $\langle\mathbf{h}\cdot\mathbf{l}\rangle$, $\langle\mathbf{h}\cdot\mathbf{v}\rangle$와 분모의 $(\mathbf{h}\cdot\mathbf{l})$, $(\mathbf{h}\cdot\mathbf{v})$가 소거된다.
따라서, 최종적으로 Specular BRDF는 다음과 같이 된다.
\[\frac{D(\mathbf{h})G_2(\mathbf{l},\mathbf{v},\mathbf{h})F(\mathbf{v},\mathbf{h})}{4|\mathbf{n}\cdot\mathbf{v}||\mathbf{n}\cdot\mathbf{l}|}\]
'그래픽스' 카테고리의 다른 글
| IBL - 1. Cube map (2) | 2026.03.08 |
|---|