엘더스크롤 5: 스카이림 반지의 제왕 Ⅲ: 왕의 귀환 레드 데드 리뎀션 2


수놓인 밤하늘은 보는 이를 취하게 만들기도, 다가오는 먹구름은 거악(巨惡)을 형용하기도, 휘황한 노을은 여운을 남기기도 한다. 이렇듯, 날씨는 감정과 분위기를 좌지우지한다. 그리고 날씨를 표현하는 데 있어 하늘은 필수 불가결하다.
본 시리즈에서는 물리 기반 하늘 렌더링의 원리와 구현을 다룬다.
Ⅰ. 수식
태양의 빛이 카메라에 도달하기까지의 과정을 어떻게 나타낼 수 있을까?
이를 빛이 매질을 통과하는 식인 VRE(Volume Rendering Equation)로 나타내면 다음과 같다.
$$
L(\mathbf{x}, \boldsymbol{\omega}) = \int_0^D T(t)\,\Big[\sigma_s(\mathbf{x}_t)\,L_{\text{scat}}(\mathbf{x}_t, \boldsymbol{\omega}) + \sigma_a(\mathbf{x}_t)\,L_e(\mathbf{x}_t, \boldsymbol{\omega})\Big]\,dt + T(D)\,L_0
$$
광원을 오직 태양으로 단순화함으로써, 발광(emission)에 관한 항을 제거하면,
$$
L(\mathbf{x}, \boldsymbol{\omega}) = \int_0^D \textcolor{#419BF9}{T(t)}\,\Big[\textcolor{#00CC66}{\sigma_s(\mathbf{x}_t)\,L_{\text{scat}}(\mathbf{x}_t, \boldsymbol{\omega})}\Big]\,dt + \color{orange}T(D)\,L_0
$$
위 식을 천천히 살펴보도록 하겠다.$T(d)$는 들어온 빛에 대한 남은 빛의 비율 ($\frac{L_{\text{out}}}{L_{\text{in}}}$)이다. 거리 $d$에 대해 다음과 같이 표현한다 (Beer-Lambert 법칙).
$$T(d) = e^{-\sigma_t d}$$
하지만 위 식은 균일(homogeneous) 매질의 경우에만 성립한다. 대기(atmosphere)는 고도(altitude)에 따라 입자의 크기가 달라지는 불균일(heterogeneous) 매질이다. 이 경우,
거리 $d$ 동안 매 지점의 상쇄 함수 $\sigma_t(\mathbf{x})$를 적분해야 한다. 즉,
$$
T(d) = e^{-\int_0^d{\sigma_t(\mathbf{x_s})}ds}
$$이를 통해 기존 VRE에서 $\color{orange}T(D)\,L_0$는 어떻게 해석할 수 있을까?
앞의 $p(\boldsymbol{\omega}^{\prime}, \boldsymbol{\omega})$는 무엇일까? $\mathbf{x}_t$로 들어온 빛은 산란되어 사방으로 흩어진다. 하지만 우리가 원하는 것은, 카메라 방향으로 산란된 빛의 비율이다. 다시 말해, $\omega^{\prime}$에서 온 빛이 $\omega$로 얼마나 향했냐는 것이다. 이를 나타낸 것이 $p(\boldsymbol{\omega}^{\prime}, \boldsymbol{\omega})$이고, 보다시피 들어오고 나가는 방향을 인자로 갖는다. 보통 코드에서는 두 방향의 $\cos$값을 인자로 갖는다.
$p$는 위상 함수(phase function)라고 불린다. 이는 확률 밀도 함수(probability density function)이며, 전 구간에 걸친 적분 값이 1이 된다는 의미이다. 예를 들어, $\omega$와 $\omega^{\prime}$에 관계 없이 모든 방향으로 균일하게 산란하는 위상 함수는 어떻게 될까? 이를 상수 $c$라고 하면,
$$ p(\omega, \omega^{\prime}) = c $$ $$ \int_0^{2\pi}\int_0^{\pi}c\sin(\theta){d\theta}{d\phi} = 1 $$ $$ c4\pi = 1 $$ $$ c = \frac{1}{4\pi} $$
다시 돌아와서, 배운 것을 토대로 $\textcolor{#00CC66}{\sigma_s(\mathbf{x})L_{\text{scat}}(\mathbf{x}, \boldsymbol{\omega})} = \sigma_s(\mathbf{x}) p(\boldsymbol{\omega}^{\prime}, \boldsymbol{\omega}) L_\text{sun}T(D)$를 한 문장으로 정리하면?대기로 들어와 상쇄되고 카메라 쪽으로 산란된 햇빛의 양이다.
지금까지 아래 식을 차근차근 뜯어보았다. 매질을 거쳐 카메라에 도달하는 빛의 양을 어느 정도 이해했기를 바란다. $$ L(\mathbf{x}, \boldsymbol{\omega}) = \int_0^D \textcolor{#419BF9}{T(t)}\,\Big[\textcolor{#00CC66}{\sigma_s(\mathbf{x}_t)\,L_{\text{scat}}(\mathbf{x}_t, \boldsymbol{\omega})}\Big]\,dt + \color{orange}T(D)\,L_0 $$ 다음 장에서는 하늘 렌더링 모델에서 이 수치들이 어떻게 결정되는지 알아보겠다.
Ⅱ. 레일리와 미 (Rayleigh and Mie)
고도에 따라 대기 중 입자의 평균 크기가 달라진다. 이에 따라 산란의 특성이 달라진다. 입자가 비교적 작은 위쪽에는 레일리 산란(Rayleigh scattering)이 주로 일어나고, 입자가 비교적 큰 아래쪽에는 미 산란(Mie scattering)이 주를 이룬다.
두 산란에 따라 위상 함수, 산란 계수, 밀도 분포가 달라지므로 이를 중심으로 살펴보도록 하겠다. 밀도 분포는 해당 고도에서 해당 산란을 일으키는 입자가 얼마나 존재하는지로 이해하면 되겠다.
레일리 산란
레일리 산란의 위상 함수는 다음을 사용하겠다. $$ p(\mu) = \frac{3(1 + \mu^2)}{16\pi} $$ $\mu$는 들어오는 빛의 방향과 산란되어 나가는 빛의 방향 사잇각의 $\cos$값이다.
레일리 산란의 산란 계수는 벡터로 표현된다. $\sigma_s^r = \begin{bmatrix} 5.802 \\ 13.558 \\ 33.1 \end{bmatrix}\times10^{-6}$을 사용하겠다.
레일리 산란의 고도 $h$에 따른 밀도 분포는 $d^r(h) = e^{\frac{-h}{8.0km}}$ 를 사용하겠다.
위 내용을 hlsl로 옮기면 다음과 같다.
float phase_rayleigh(float mu) {
return 0.05968310365 * (1 + mu*mu);
}
float3 Sr = float3(5.802e-6, 13.558e-6, 33.1e-6); // 레일리 산란 계수
float Dr = exp(-altitude / 8.0km); // 8.0km미 산란
미 산란의 위상 함수는 다음처럼 Cornette-Shanks 위상함수로 표현할 수 있다.
$$ p(\mu, g) = {\frac{3}{8\pi}}{\frac{(1 - g^2)(1 + \mu^2)}{(2 + g^2){(1 + g^2 - 2g\mu)}^{3/2}}} $$$g$는 비대칭 계수(asymmetry parameter)로서, 산란된 빛이 원래 진행 방향으로 얼마나 유지하려는지를 나타낸다.
$g>0$의 경우, 빛이 원래 진행 방향으로 더 많이 산란되고,
$g<0$의 경우, 빛이 반대 방향으로 더 많이 산란된다.우리는 $g=0.8$로 설정하겠다.
미 산란의 산란 계수 $\sigma_s^m$는 $2.1\times10^{-5}$를 사용하도록 하겠다. 이는 날씨, 대기의 오염도 등에 따라 달라질 수 있다.
미 산란의 고도 $h$에 따른 밀도 분포는 $d^m(h) = e^{\frac{-h}{1.2km}}$ 를 사용하겠다.
위 내용을 hlsl로 옮기면 다음과 같다.
float phase_mie(float mu, float g) {
// Cornette-Shanks
float g2 = g*g;
return 0.11936620731 * (((1 - g2)*(1 + mu*mu)) / ((2 + g2) * pow(1 + g2 - 2*g*mu, 1.5)));
}
float3 Sm = 2.1e-5; // 미 산란 계수
float Dm = exp(-altitude / 1.2e3); // 1.2km정리
표로 정리하면 다음과 같다.
| 레일리 | 미 | |
|---|---|---|
| 위상 함수 | \(p(\mu)=\frac{3(1+\mu^2)}{16\pi}\) | \(p(\mu,g)=\frac{3}{8\pi}\frac{(1-g^2)(1+\mu^2)}{(2+g^2)(1+g^2-2g\mu)^{3/2}}\) |
| 산란 계수 | \(\sigma_s^r=[5.802,13.558,33.1]\times10^{-6}\) | \(\sigma_s^m=2.1\times10^{-5}\) |
| 밀도 분포 | \(d^r(h)=e^{-h/(8.0\text{ km})}\) | \(d^m(h)=e^{-h/(1.2\text{ km})}\) |
아래는 레일리나 미 산란만 있을 때와 합쳐졌을 때의 렌더링 결과이다.



아래는 각 산란을 일으키는 입자의 밀도 분포 그래프이다. $x$축은 고도(km)이다. 파란색 레일리는 초록색 미보다 넓게, 보다 높게까지 분포되어 있다. 붉은색 오존은 제일 높은 고도에 텐트 형태로 존재한다.
III. 결과
아래는 C++20과 Direct3D 12로 구현한 실시간 하늘 렌더링의 결과이다.

레퍼런스
Sébastien Hillaire — A Scalable and Production Ready Sky and Atmosphere Rendering Technique Sébastien Hillaire — Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite Tomoyuki Nishita et al. — Display of The Earth Taking in Account Atmospheric Scattering Epic — Sky Atmosphere Component in Unreal Engine