Environment Lighting

The name environment lighting is from "10.2 Environment Lighting" of Real-Time Rendering Fourth Edition. By "10.2 Environment Lighting" of Real-Time Rendering Fourth Edition, "14.4 The Light Transport Equation" of PBR Book V3 and "13.1 The Light Transport Equation" of PBR Book V4, the most important difference between environment lighting (local illumination) and global illumination is that the shading algorithm of the environment lighting (local illumination) is independent of the other positions on the surface except the shading position. Hence, when we are discussing the environment lighting, the position parameter p \displaystyle \overrightarrow{p} of most functions, such as f ( p , ω i , ω o ) \displaystyle \operatorname{f}(\overrightarrow{p}, \overrightarrow{\omega_i}, \overrightarrow{\omega_o}) , L o ( p , ω o ) \displaystyle \operatorname{L_o}(\overrightarrow{p}, \overrightarrow{\omega_o}) and L i ( p , ω i ) \displaystyle \operatorname{L_i}(\overrightarrow{p}, \overrightarrow{\omega_i}) , is omitted.

Notation Description Shader Code Convention
ω i \displaystyle \overrightarrow{\omega_i} Incident Direction in Tangent Space L
ω o \displaystyle \overrightarrow{\omega_o} Outgoing Direction in Tangent Space V
f ( ω i , ω o ) \displaystyle \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) BRDF N/A
L i ( ω i ) \displaystyle \operatorname{L_i}( \overrightarrow{\omega_i}) Incident Radiance N/A
L o ( ω o ) \displaystyle \operatorname{L_o}( \overrightarrow{\omega_o}) Outgoing Radiance N/A
( cos θ i ) + \displaystyle (\cos \theta_i)^+ Clamped Cosine clamp(dot(N, L), 0.0, 1.0)
ω h \displaystyle \overrightarrow{\omega_h} Half Vector in Tangent Space H
n \displaystyle \overrightarrow{n} Normal in World Space N

1. Diffuse Environment Lighting

Let L ( ω ) \displaystyle \operatorname{L}(\overrightarrow{\omega}) be the distant radiance distribution of which the domain is in world space.

Let n \displaystyle \overrightarrow{n} be the normal in world space and ω i \displaystyle \overrightarrow{\omega_i} be the incident direction in tangent space (where the normal direction is the Z axis [ 0 0 1 ] \displaystyle \begin{bmatrix}0 & 0 & 1\end{bmatrix} ). Evidently, the incident direction in world space can be calculated as R ( n ) ω i \displaystyle \operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i} where R ( n ) \displaystyle \operatorname{R}(\overrightarrow{n}) is the rotation matrix depending on the normal direction n \displaystyle \overrightarrow{n} in world space. And we have the incident radiance L i ( ω i ) = L ( R ( n ) ω i ) \displaystyle \operatorname{L_i}( \overrightarrow{\omega_i}) = \operatorname{L}(\operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i}) .

Since the Lambert BRDF f ( ω i , ω o ) = 1 π ρ s s \displaystyle \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) = \frac{1}{\pi} \rho_{ss} is constant, we have L o ( ω o ) = S 2 f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + d ω i = 1 π ρ s s E ( n ) \displaystyle \operatorname{L_o}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \frac{1}{\pi} \rho_{ss} \cdot \operatorname{E}(\overrightarrow{n}) where E ( n ) = S 2 L i ( ω i ) ( cos θ i ) + d ω i = S 2 L ( R ( n ) ω i ) ( cos θ i ) + d ω i \displaystyle \operatorname{E}(\overrightarrow{n}) = \int_{\mathrm{S}^2} \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \int_{\mathrm{S}^2} \operatorname{L}(\operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} .

1-1. SH (Spherical Harmonics)

1-1-1. SH Basis

Let Υ l m ( ω ) \displaystyle \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) be the SH (Spherical Harmonics) basis function of which l is the degree (or band) and m is the basis function index from -l to l.

The SH basis function Υ l 0 ( ω ) \displaystyle \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) of which the m is zero is also called ZH (zonal harmonics).

By "Appendix A2" of [Sloan 2008], we have the polynomial forms of SH basis Υ l m ( ω ) \displaystyle \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) . These polynomial forms are calculated by sh_eval_basis_2 in DirectXMath, and SHBasisFunction3 in UE4.

Note that the direction vector ω = [ x y z ] \displaystyle \overrightarrow{\omega} = \begin{bmatrix} x & y & z\end{bmatrix} should be normalized before using the polynomial forms. By "13.5.3 Spherical Coordinates" of PBR Book V3 and "Spherical Coordinates" of "3.8.3 Spherical Parameterizations" of PBR Book V4, we have ω = [ x y z ] = [ sin θ cos ϕ sin θ sin ϕ cos θ ] \displaystyle \overrightarrow{\omega} = \begin{bmatrix} x & y & z\end{bmatrix} = \begin{bmatrix} \sin \theta \cos \phi & \sin \theta \sin \phi & \cos \theta \end{bmatrix} where ϕ \displaystyle \phi is azimuth and θ \displaystyle \theta is zenith (in physics, while in mathmatics θ \displaystyle \theta is the azimuth and ϕ \displaystyle \phi is the zenith).

l m Υ l m ( ω ) \displaystyle \operatorname{\Upsilon_l^m}(\overrightarrow{\omega})
0 0 1 2 π = 0.282094791773878140 \displaystyle \frac{1}{2 \sqrt{\pi}} = 0.282094791773878140
1 -1 3 2 π y = 0.488602511902919920 y \displaystyle - \frac{\sqrt{3}}{2 \sqrt{\pi}} y = -0.488602511902919920 y
1 0 3 2 π z = 0.488602511902919920 z \displaystyle \frac{\sqrt{3}}{2 \sqrt{\pi}} z = 0.488602511902919920 z
1 1 3 2 π x = 0.488602511902919920 x \displaystyle - \frac{\sqrt{3}}{2 \sqrt{\pi}} x = -0.488602511902919920 x
2 -2 15 2 π x y = 1.092548430592079200 x y \displaystyle \frac{\sqrt{15}}{2 \sqrt{\pi}} x y = 1.092548430592079200 x y
2 -1 15 2 π y z = 1.092548430592079200 y z \displaystyle - \frac{\sqrt{15}}{2 \sqrt{\pi}} y z = -1.092548430592079200 y z
2 0 3 5 4 π z 2 5 4 π = 0.946174695757560080 z 2 0.315391565252520050 \displaystyle \frac{3 \sqrt{5}}{4 \sqrt{\pi}} z^2 - \frac{\sqrt{5}}{4 \sqrt{\pi}} = 0.946174695757560080 z^2 - 0.315391565252520050
2 1 15 2 π x z = 1.092548430592079200 x z \displaystyle - \frac{\sqrt{15}}{2 \sqrt{\pi}} x z = -1.092548430592079200 x z
2 2 15 4 π ( x 2 y 2 ) = 0.546274215296039590 ( x 2 y 2 ) \displaystyle \frac{\sqrt{15}}{4 \sqrt{\pi}} (x^2 - y^2) = 0.546274215296039590 (x^2 - y^2)

1-1-2. SH Rotation

Let R \displaystyle \mathrm{R} be the rotation matrix. By "A. Rotation of Spherical Harmonics" of "4. SPHERICAL HARMONIC REPRESENTATION" of [Ramamoorthi 2001 A], for each degree (or band) l, we have Υ l m ( R ω ) = j = l l D m j l ( R ) Υ l j ( ω ) \displaystyle \operatorname{\Upsilon_l^m}(\mathrm{R} \overrightarrow{\omega}) = \sum_{j = -l}^l \operatorname{D_{mj}^l}(\mathrm{R}) \operatorname{\Upsilon_l^j}(\overrightarrow{\omega}) where D l ( R ) \displaystyle \operatorname{D_l}(\mathrm{R}) is the Wigner D-matrix. This means that [ Υ l l ( R ω ) Υ l 0 ( R ω ) Υ l l ( R ω ) ] = D l ( R ) [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\mathrm{R} \overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\mathrm{R} \overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\mathrm{R} \overrightarrow{\omega}) \end{bmatrix} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} .

By "Appendix: SH Rotation" of [Kautz 2002], for each degree (or band) l, each element of the Wigner D-matrix can be calculated as D i j l ( R ) = S 2 Υ l i l ( R ω ) Υ l j l ( ω ) d ω \displaystyle \operatorname{D_{ij}^l}(\mathrm{R}) = \int_{\mathrm{S}^2} \operatorname{\Upsilon_l^{i - l}}(\mathrm{R} \overrightarrow{\omega}) \operatorname{\Upsilon_l^{j - l}}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} .

For l = 0, we have D 00 0 = S 2 Υ 0 0 ( R ω ) Υ 0 0 ( ω ) d ω = S 2 1 2 π 1 2 π d ω = 1 4 π S 2 1 d ω = 1 4 π 4 π = 1 \displaystyle \mathrm{D_{00}^0} = \int_{\mathrm{S}^2} \operatorname{\Upsilon_0^0}(\mathrm{R} \overrightarrow{\omega}) \operatorname{\Upsilon_0^0}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} = \int_{\mathrm{S}^2} \frac{1}{2 \sqrt{\pi}} \frac{1}{2 \sqrt{\pi}} \, d\overrightarrow{\omega} = \frac{1}{4\pi} \int_{\mathrm{S}^2} 1 \, d\overrightarrow{\omega} = \frac{1}{4\pi} 4\pi = 1 . This means that D l ( R ) = [ 1 ] \displaystyle \operatorname{D_l}(\mathrm{R}) = \begin{bmatrix} 1 \end{bmatrix} .

For l = 1, it is too complex to calculate the intergral for each element of the Wigner D-matrix. The trick by [Hable 2014] can be used to calculate the Wigner D-matrix. Since the equation [ Υ 1 1 ( R ω ) Υ 1 0 ( R ω ) Υ 1 1 ( R ω ) ] = D l ( R ) [ Υ 1 1 ( ω ) Υ 1 0 ( ω ) Υ 1 1 ( ω ) ] \displaystyle \begin{bmatrix} \operatorname{\Upsilon_1^{-1}}(\mathrm{R} \overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^0}(\mathrm{R} \overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^1}(\mathrm{R} \overrightarrow{\omega}) \end{bmatrix} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} \operatorname{\Upsilon_1^-1}(\overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^0}(\overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^1}(\overrightarrow{\omega}) \end{bmatrix} holds for arbitrary direction ω \displaystyle \overrightarrow{\omega} , we can apply this equation to three linearly independent vectors [ 1 0 0 ] \displaystyle \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix} , [ 0 1 0 ] \displaystyle \begin{bmatrix} 0 \\ 1 \\ 0 \end{bmatrix} and [ 0 0 1 ] \displaystyle \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix} to construct an invertible matrix. By the polynomial forms of SH basis, we have [ Υ 1 1 ( R ω ) Υ 1 0 ( R ω ) Υ 1 1 ( R ω ) ] = D l ( R ) [ Υ 1 1 ( ω ) Υ 1 0 ( ω ) Υ 1 1 ( ω ) ] \displaystyle \begin{bmatrix} \operatorname{\Upsilon_1^{-1}}(\mathrm{R} \overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^0}(\mathrm{R} \overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^1}(\mathrm{R} \overrightarrow{\omega}) \end{bmatrix} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} \operatorname{\Upsilon_1^-1}(\overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^0}(\overrightarrow{\omega}) \\ \operatorname{\Upsilon_1^1}(\overrightarrow{\omega}) \end{bmatrix} \Rightarrow [ 0 3 2 π 0 0 0 3 2 π 3 2 π 0 0 ] R ω = D l ( R ) [ 0 3 2 π 0 0 0 3 2 π 3 2 π 0 0 ] ω [ 0 3 2 π 0 0 0 3 2 π 3 2 π 0 0 ] R [ 1 0 0 0 1 0 0 0 1 ] = D l ( R ) [ 0 3 2 π 0 0 0 3 2 π 3 2 π 0 0 ] [ 1 0 0 0 1 0 0 0 1 ] \displaystyle \color{red} \begin{bmatrix} 0 & - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 \\ 0 & 0 & \frac{\sqrt{3}}{2 \sqrt{\pi}} \\ - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 & 0 \end{bmatrix} \mathrm{R} \color{green} \overrightarrow{\omega} \color{red} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} 0 & - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 \\ 0 & 0 & \frac{\sqrt{3}}{2 \sqrt{\pi}} \\ - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 & 0 \end{bmatrix} \color{green} \overrightarrow{\omega} \color{red} \Rightarrow \begin{bmatrix} 0 & - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 \\ 0 & 0 & \frac{\sqrt{3}}{2 \sqrt{\pi}} \\ - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 & 0 \end{bmatrix} \mathrm{R} \color{green} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \color{red} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} 0 & - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 \\ 0 & 0 & \frac{\sqrt{3}}{2 \sqrt{\pi}} \\ - \frac{\sqrt{3}}{2 \sqrt{\pi}} & 0 & 0 \end{bmatrix} \color{green} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \color{red} [ 0 1 0 0 0 1 1 0 0 ] R [ 1 0 0 0 1 0 0 0 1 ] = D l ( R ) [ 0 1 0 0 0 1 1 0 0 ] [ 1 0 0 0 1 0 0 0 1 ] \displaystyle \Rightarrow \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \mathrm{R} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} . Evidently, [ 0 1 0 0 0 1 1 0 0 ] [ 1 0 0 0 1 0 0 0 1 ] \displaystyle \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} is invertible and we have D l ( R ) = [ 0 1 0 0 0 1 1 0 0 ] R [ 1 0 0 0 1 0 0 0 1 ] ( [ 0 1 0 0 0 1 1 0 0 ] [ 1 0 0 0 1 0 0 0 1 ] ) 1 = [ 0 1 0 0 0 1 1 0 0 ] R [ 1 0 0 0 1 0 0 0 1 ] [ 0 0 1 1 0 0 0 1 0 ] = [ 0 1 0 0 0 1 1 0 0 ] R [ 0 0 1 1 0 0 0 1 0 ] = [ R 10 R 11 R 12 R 20 R 21 R 22 R 00 R 01 R 02 ] [ 0 0 1 1 0 0 0 1 0 ] = [ R 11 R 12 R 10 R 21 R 22 R 20 R 01 R 02 R 00 ] \displaystyle \operatorname{D_l}(\mathrm{R}) = \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \mathrm{R} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} {\left \lparen \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \right \rparen}^{-1} = \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \mathrm{R} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 0 & 0 & -1 \\ -1 & 0 & 0 \\ 0 & 1 & 0 \end{bmatrix} = \begin{bmatrix} 0 & -1 & 0 \\ 0 & 0 & 1 \\ -1 & 0 & 0 \end{bmatrix} \mathrm{R} \begin{bmatrix} 0 & 0 & -1 \\ -1 & 0 & 0 \\ 0 & 1 & 0 \end{bmatrix} = \begin{bmatrix} -{\mathrm{R}}_{10} & -{\mathrm{R}}_{11} & -{\mathrm{R}}_{12} \\ {\mathrm{R}}_{20} & {\mathrm{R}}_{21} & {\mathrm{R}}_{22} \\ -{\mathrm{R}}_{00} & -{\mathrm{R}}_{01} & -{\mathrm{R}}_{02} \end{bmatrix} \begin{bmatrix} 0 & 0 & -1 \\ -1 & 0 & 0 \\ 0 & 1 & 0 \end{bmatrix} = \begin{bmatrix} {\mathrm{R}}_{11} & -{\mathrm{R}}_{12} & {\mathrm{R}}_{10} \\ -{\mathrm{R}}_{21} & {\mathrm{R}}_{22} & -{\mathrm{R}}_{20} \\ {\mathrm{R}}_{01} & -{\mathrm{R}}_{02} & {\mathrm{R}}_{00} \end{bmatrix} .

The Wigner D-matrix is calculated by DirectX::XMSHRotate and DirectX::XMSHRotateZ in DirectXMath.

l D l ( R ) \displaystyle \operatorname{D_l}(\mathrm{R})
0 [ 1 ] \displaystyle \begin{bmatrix} 1 \end{bmatrix}
1 [ R 11 R 12 R 10 R 21 R 22 R 20 R 01 R 02 R 00 ] \displaystyle \begin{bmatrix} {\mathrm{R}}_{11} & -{\mathrm{R}}_{12} & {\mathrm{R}}_{10} \\ -{\mathrm{R}}_{21} & {\mathrm{R}}_{22} & -{\mathrm{R}}_{20} \\ {\mathrm{R}}_{01} & -{\mathrm{R}}_{02} & {\mathrm{R}}_{00} \end{bmatrix}

1-1-3. SH Projection

Let S H \displaystyle \operatorname{\mathcal{SH}} be the SH (Spherical Harmonics) projection operation. Analogous to the Fourier transform, we have f l m = S H ( f ( ω ) ) = S 2 f ( ω ) Υ l m ( ω ) d ω \displaystyle f_l^m = \operatorname{\mathcal{SH}}(\operatorname{f}(\overrightarrow{\omega})) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega}) \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} , and the original function can be reconstructed as the SH series f ( ω ) = l = 0 m = l l f l m Υ l m ( ω ) = l = 0 [ f l l f l 0 f l l ] [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \operatorname{f}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l f_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} .

1-1-4. SH Rotational Invariance

Let R \displaystyle \mathrm{R} be the rotation matrix. Let f ( ω ) = f ( R ω ) \displaystyle \operatorname{f'}(\overrightarrow{\omega}) = \operatorname{f}(\mathrm{R}\overrightarrow{\omega}) and f ( ω ) = l = 0 m = l l f l m Υ l m ( ω ) \displaystyle \operatorname{f'}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l {f'}_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) . By "Basic Properties" of "3. Review of Spherical Harmonics" of [Sloan 2002], we have [ f l l f l 0 f l l ] = [ f l l f l 0 f l l ] D l ( R ) \displaystyle \begin{bmatrix} {f'}_l^{-l} & \cdots & {f'}_l^0 & \cdots & {f'}_l^l \end{bmatrix} = \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \operatorname{D_l}(\mathrm{R}) where D l ( R ) \displaystyle \operatorname{D_l}(\mathrm{R}) is the Wigner D-matrix.

Proof

By "SH Projection", we have f ( ω ) = l = 0 m = l l f l m Υ l m ( ω ) = l = 0 [ f l l f l 0 f l l ] [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \operatorname{f}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l f_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} .

By "SH Rotation", we have [ Υ l l ( R ω ) Υ l 0 ( R ω ) Υ l l ( R ω ) ] = D l ( R ) [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\mathrm{R} \overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\mathrm{R} \overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\mathrm{R} \overrightarrow{\omega}) \end{bmatrix} = \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} .

This means that f ( ω ) = f ( R ω ) = l = 0 [ f l l f l 0 f l l ] [ Υ l l ( R ω ) Υ l 0 ( R ω ) Υ l l ( R ω ) ] = l = 0 [ f l l f l 0 f l l ] D l ( R ) [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \operatorname{f'}(\overrightarrow{\omega}) = \operatorname{f}(\mathrm{R}\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\mathrm{R}\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\mathrm{R}\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\mathrm{R}\overrightarrow{\omega}) \end{bmatrix} = \sum_{l = 0}^{\infin} \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \operatorname{D_l}(\mathrm{R}) \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} where D l ( R ) \displaystyle \operatorname{D_l}(\mathrm{R}) is the Wigner D-matrix.

Since f ( ω ) = l = 0 m = l l f l m Υ l m ( ω ) = l = 0 [ f l l f l 0 f l l ] [ Υ l l ( ω ) Υ l 0 ( ω ) Υ l l ( ω ) ] \displaystyle \operatorname{f'}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l {f'}_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \begin{bmatrix} {f'}_l^{-l} & \cdots & {f'}_l^0 & \cdots & {f'}_l^l \end{bmatrix} \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega}) \end{bmatrix} , we have [ f l l f l 0 f l l ] = [ f l l f l 0 f l l ] D l ( R ) \displaystyle \begin{bmatrix} {f'}_l^{-l} & \cdots & {f'}_l^0 & \cdots & {f'}_l^l \end{bmatrix} = \begin{bmatrix} f_l^{-l} & \cdots & f_l^0 & \cdots & f_l^l \end{bmatrix} \operatorname{D_l}(\mathrm{R}) .

1-1-5. SH Product Integration

Let f ( ω ) = l = 0 m = l l f l m Υ l m ( ω ) \displaystyle \operatorname{f}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l f_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) and g ( ω ) = l = 0 m = l l g l m Υ l m ( ω ) \displaystyle \operatorname{g}(\overrightarrow{\omega}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l g_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) . By "Basic Properties" of "3. Review of Spherical Harmonics" of [Sloan 2002], due to the orthonormality of the SH basis, we have S 2 f ( ω ) g ( ω ) d ω = S 2 ( l = 0 m = l l f l m Υ l m ( ω ) ) ( l = 0 m = l l g l m Υ l m ( ω ) ) d ω = l = 0 m = l l f l m g l m \displaystyle \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega}) \operatorname{g}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} = \int_{\mathrm{S}^2} \left \lparen \sum_{l = 0}^{\infin} \sum_{m = -l}^l f_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \right \rparen \left \lparen \sum_{l = 0}^{\infin} \sum_{m = -l}^l g_l^m \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \right \rparen \, d\overrightarrow{\omega} = \sum_{l = 0}^{\infin} \sum_{m = -l}^l f_l^m g_l^m .

1-1-6. SH Product Projection

Actually, "SH Product Projection" is related to the Clebsch–Gordan coefficients which is too complex to be used in rendering. We only need to know that "SH Product Projection" should be distinguished from "SH Product Integration".

Let h ( ω ) = f ( ω ) g ( ω ) \displaystyle \operatorname{h}(\overrightarrow{\omega}) = \operatorname{f}(\overrightarrow{\omega}) \operatorname{g}(\overrightarrow{\omega}) . By "Product Projection" of "3. Review of Spherical Harmonics" of [Sloan 2002], we have that h l m = S 2 h ( ω ) Υ l m ( ω ) d ω = S 2 f ( ω ) g ( ω ) Υ l m ( ω ) d ω S 2 f ( ω ) g ( ω ) d ω \displaystyle h_l^m = \int_{\mathrm{S}^2} \operatorname{h}(\overrightarrow{\omega}) \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega}) \operatorname{g}(\overrightarrow{\omega}) \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} \ne \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega}) \operatorname{g}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} which is totally different from "SH Product Integration".

1-2. SH convolution

Analogous to the convolution theorem, by [Ramamoorthi 2001 A], we have E ( n ) = S 2 L i ( ω i ) ( cos θ i ) + d ω i = S 2 L ( R ( n ) ω i ) ( cos θ i ) + d ω i = l = 0 m = l l 4 π 2 l + 1 L l m A l Υ l m ( n ) \displaystyle \operatorname{E}(\overrightarrow{n}) = \int_{\mathrm{S}^2} \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \int_{\mathrm{S}^2} \operatorname{L}(\operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \sum_{l = 0}^{\infin} \sum_{m = -l}^l \sqrt{\frac{4 \pi}{2l + 1}} L_l^m A_l \operatorname{\Upsilon_l^m}(\overrightarrow{n}) where L l m = S H ( L ( ω ) ) = S 2 L ( ω ) Υ l m ( ω ) d ω \displaystyle L_l^m = \operatorname{\mathcal{SH}}(\operatorname{L}(\overrightarrow{\omega})) = \int_{\mathrm{S}^2} \operatorname{L}(\overrightarrow{\omega}) \operatorname{\Upsilon_l^m}(\overrightarrow{\omega}) \, d\overrightarrow{\omega} and A l = Z H ( ( cos θ i ) + ) = S 2 ( cos θ i ) + Υ l 0 ( ω i ) d ω i \displaystyle A_l = \operatorname{\mathcal{ZH}}((\cos \theta_i)^+) = \int_{\mathrm{S}^2} (\cos \theta_i)^+ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega_i}) \, d\overrightarrow{\omega_i} .

Proof

By "SH Rotational Invariance", we have L ( R ( n ) ω i ) = l = 0 [ L l l L l 0 L l l ] D l ( R ( n ) ) [ Υ l l ( ω i ) Υ l 0 ( ω i ) Υ l l ( ω i ) ] \displaystyle \operatorname{L}(\operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i}) = \sum_{l = 0}^{\infin} \begin{bmatrix} L_l^{-l} & \cdots & L_l^0 & \cdots & L_l^l \end{bmatrix} \operatorname{D_l}(\operatorname{R}(\overrightarrow{n})) \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega_i}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega_i}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega_i}) \end{bmatrix} where D l ( R ( n ) ) \displaystyle \operatorname{D_l}(\operatorname{R}(\overrightarrow{n})) is the Wigner D-matrix.

Due to circular symmetry of the clamped cosine, only the coefficients of the ZH(Zonal Harmonics) are non-zero. By "SH Projection", we have ( cos θ i ) + = l = 0 A l Υ l 0 ( ω i ) \displaystyle (\cos \theta_i)^+ = \sum_{l = 0}^{\infin} A_l \operatorname{\Upsilon_l^0}(\overrightarrow{\omega_i}) .

By "SH Product Integration", due to the orthonormality of the SH basis, only the elements D m 0 l ( R ( n ) ) \displaystyle \operatorname{D_{m0}^l}(\operatorname{R}(\overrightarrow{n})) of the Wigner D-matrix are multiplied by the non-zero term, and we have E ( n ) = S 2 L ( R ( n ) ω i ) ( cos θ i ) + d ω i = S 2 ( l = 0 [ L l l L l 0 L l l ] D l ( R ( n ) ) [ Υ l l ( ω i ) Υ l 0 ( ω i ) Υ l l ( ω i ) ] ) ( l = 0 A l Υ l 0 ( ω i ) ) d ω i = l = 0 m = l l L l m A l D m 0 l ( R ( n ) ) \displaystyle \operatorname{E}(\overrightarrow{n}) = \int_{\mathrm{S}^2} \operatorname{L}(\operatorname{R}(\overrightarrow{n}) \overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \int_{\mathrm{S}^2} \left \lparen \sum_{l = 0}^{\infin} \begin{bmatrix} L_l^{-l} & \cdots & L_l^0 & \cdots & L_l^l \end{bmatrix} \operatorname{D_l}(\operatorname{R}(\overrightarrow{n})) \begin{bmatrix} \operatorname{\Upsilon_l^{-l}}(\overrightarrow{\omega_i}) \\ \vdots \\ \operatorname{\Upsilon_l^0}(\overrightarrow{\omega_i}) \\ \vdots \\ \operatorname{\Upsilon_l^l}(\overrightarrow{\omega_i}) \end{bmatrix} \right \rparen \left \lparen \sum_{l = 0}^{\infin} A_l \operatorname{\Upsilon_l^0}(\overrightarrow{\omega_i}) \right \rparen \, d \overrightarrow{\omega_i} = \sum_{l = 0}^{\infin} \sum_{m = -l}^l L_l^m A_l \operatorname{D_{m0}^l}(\operatorname{R}(\overrightarrow{n})) .

By "Equation (23)" of [Ramamoorthi 2001 A], we have D m 0 l ( R ( n ) ) = 4 π 2 l + 1 Υ l m ( n ) \displaystyle \operatorname{D_{m0}^l}(\operatorname{R}(\overrightarrow{n})) = \sqrt{\frac{4 \pi}{2l + 1}} \operatorname{\Upsilon_l^m}(\overrightarrow{n}) , and we have E ( n ) = l = 0 m = l l L l m A l D m 0 l ( R ( n ) ) = l = 0 m = l l 4 π 2 l + 1 L l m A l Υ l m ( n ) \displaystyle \operatorname{E}(\overrightarrow{n}) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l L_l^m A_l \operatorname{D_{m0}^l}(\operatorname{R}(\overrightarrow{n})) = \sum_{l = 0}^{\infin} \sum_{m = -l}^l \sqrt{\frac{4 \pi}{2l + 1}} L_l^m A_l \operatorname{\Upsilon_l^m}(\overrightarrow{n}) .

1-3. Cubemap Texel Solid Angle

We merely use numerical quadrature rather than Monte Carlo integration to integrate over the cubemap. But it should be noted that the solid angle subtended by each texel of the cubemap is NOT the same. Let u and v be the texcoord of the cubemap. By "5.5.3 Integrals over Area" of PBRT Book V3 and "4.2.3 Integrals over Area" of PBR Book V4, we have d ω = d A cos θ r 2 = d A cos θ 1 r 2 = ( 1 ( 1 ) ) ( 1 ( 1 ) ) cubesize_u cubesize_v 1 1 2 + u 2 + v 2 1 1 2 + u 2 + v 2 = 1 cubesize_u cubesize_v 4 1 2 + u 2 + v 2 ( 1 2 + u 2 + v 2 ) \displaystyle d\omega = \frac{dA \cos \theta}{r^2} = dA \cdot \cos \theta \cdot \frac{1}{r^2} = \frac{(1 - (-1)) \cdot (1 - (-1))}{\text{cubesize\_u} \cdot \text{cubesize\_v}} \cdot \frac{1}{\sqrt{1^2 + u^2 +v^2}} \cdot \frac{1}{1^2 + u^2 +v^2} = \frac{1}{\text{cubesize\_u} \cdot \text{cubesize\_v}} \cdot \frac{4}{\sqrt{1^2 + u^2 +v^2} \cdot (1^2 + u^2 +v^2)} . Actually the pseudo code fWt = 4/(sqrt(fTmp)*fTmp) by "Projection from Cube Maps" of [Sloan 2008] is exactly the 4 1 2 + u 2 + v 2 ( 1 2 + u 2 + v 2 ) \displaystyle \frac{4}{\sqrt{1^2 + u^2 +v^2} \cdot (1^2 + u^2 +v^2)} . The common divisor 1 cubesize_u cubesize_v \displaystyle \frac{1}{\text{cubesize\_u} \cdot \text{cubesize\_v}} can be reduced, and thus is NOT calculated by [Sloan 2008]. The solid angle is calculated by SHProjectCubeMap in DirectXMath and DiffuseIrradianceCopyPS in UE4.

Here is the MATLAB code which verifies the meaning of "fWt = 4/(sqrt(fTmp)*fTmp)".

% retrieved by "textureSize(GLSL)" or "GetDimensions(HLSL)". cube_size_u = single(4096.0); cube_size_v = single(4096.0); [ index_u, index_v ] = meshgrid((single(0.0) : (cube_size_u - single(1.0))), (single(0.0) : (cube_size_v - single(1.0)))); u = (index_u + single(0.5)) ./ cube_size_u .* single(2.0) - single(1.0); v = (index_v + single(0.5)) ./ cube_size_u .* single(2.0) - single(1.0); % the common divisor "1/(cube_size_u*cube_size_v)" can be reduced, and thus is NOT calculated in the "fWt = 4/(sqrt(fTmp)*fTmp)". d_a = (single(1.0) - single(-1.0)) .* (single(1.0) - single(-1.0)) ./ cube_size_u ./ cube_size_v; r_2 = single(1.0) .* single(1.0) + single(u) .* single(u) + single(v) .* single(v); cos_theta = single(1.0) ./ sqrt(r_2); d_omega = single(d_a) .* single(cos_theta) ./ single(r_2); % "numerical_omega" and "analytic_omega" are expected to be the same. numerical_omega = sum(sum(d_omega)); analytical_omega = single(4.0) .* single(pi) .* single(1.0) .* single(1.0) / single(6.0); % output: "numerical:2.094395 analytic_omega:2.094395". printf("numerical:%f analytical:%f\n", numerical_omega, analytical_omega);

1-4. Clamped Cosine

By [Ramamoorthi 2001 B], 4 π 2 l + 1 A l \displaystyle \sqrt{\frac{4 \pi}{2l + 1}} A_l is constant and can be pre-integrated. For example, by "5.5.1 Integrals over Projected Solid Angle" of PBR Book V3 and "4.2.1 Integrals over Projected Solid Angle" of PBR Book V4, A 0 \displaystyle A_0 can pre-integrated as A 0 = S 2 ( cos θ ) + Υ 0 0 ( ω ) d ω = S 2 ( cos θ ) + 1 2 π d ω = 1 2 π S 2 ( cos θ ) + d ω = 1 2 π d ω = 1 2 π π \displaystyle A_0 = \int_{\mathrm{S}^2} (\cos \theta)^+ \operatorname{\Upsilon_0^0}(\overrightarrow{\omega}) \, d \overrightarrow{\omega} = \int_{\mathrm{S}^2} (\cos \theta)^+ \frac{1}{2 \sqrt{\pi}} \, d \overrightarrow{\omega} = \frac{1}{2 \sqrt{\pi}} \int_{\mathrm{S}^2} (\cos \theta)^+ \, d \overrightarrow{\omega} = \frac{1}{2 \sqrt{\pi}} \, d \overrightarrow{\omega^{\perp}} = \frac{1}{2 \sqrt{\pi}} \pi . These constants are calculated by CalcDiffuseTransferSH3 in UE4.

l 4 π 2 l + 1 \displaystyle \sqrt{\frac{4 \pi}{2l + 1}} A l \displaystyle A_l 4 π 2 l + 1 A l \displaystyle \sqrt{\frac{4 \pi}{2l + 1}} A_l
0 2 π \displaystyle 2 \sqrt{\pi} 1 2 π π \displaystyle \frac{1}{2 \sqrt{\pi}} \pi π \displaystyle \pi
1 2 π 3 \displaystyle \frac{2 \sqrt{\pi}}{\sqrt{3}} 3 2 π 2 π 3 \displaystyle \frac{\sqrt{3}}{2 \sqrt{\pi}} \frac{2\pi}{3} 2 π 3 \displaystyle \frac{2 \pi}{3}
2 2 π 5 \displaystyle \frac{2 \sqrt{\pi}}{\sqrt{5}} 5 2 π π 4 \displaystyle \frac{\sqrt{5}}{2 \sqrt{\pi}} \frac{\pi}{4} π 4 \displaystyle \frac{\pi}{4}

1-5. Form Factor

"Appendix A10" of [Sloan 2008] proposed a more efficient approach to reconstruct from SH basis than [Ramamoorthi 2001 B]. This approach is used by SampleSH9 in Unity3D and GetSkySHDiffuse in UE4.
However, it was form factor rather than irradiance that "Appendix A10" of [Sloan 2008] calculated. Although the terms irradiance and form factor may be interchangeably used, technically irradiance should NOT be divided by π \displaystyle \pi . This means that E ( n ) = π F ( n ) \displaystyle \operatorname{E}(\overrightarrow{n}) = \pi \operatorname{F}(\overrightarrow{n}) . This form factor is calculated by PackCoefficients in Unity3D, and SetupSkyIrradianceEnvironmentMapConstantsFromSkyIrradiance and ComputeSkyEnvMapDiffuseIrradianceCS in UE4.
And since the value reconstructed from SH basis is form factor rather than irradiance, it should be multiplied by albedo rather than Lambert BRDF. This multiplication is calculated by GetDiffuseOrDefaultColor in Unity3D and EnvBRDFApproxFullyRough in UE4.

fc value
fc0 1 π Υ 0 0 A 0 = 1 π 1 2 π π = 1 2 π \displaystyle \frac{1}{\pi} \operatorname{\Upsilon_0^0} A_0 = \frac{1}{\pi} \frac{1}{2 \sqrt{\pi}} \pi = \frac{1}{2 \sqrt{\pi}}
fc1 1 π Υ 1 0 A 1 = 1 π 3 2 π 2 π 3 = 3 3 π \displaystyle \frac{1}{\pi} \operatorname{\Upsilon_1^0} A_1 = \frac{1}{\pi} \frac{\sqrt{3}}{2 \sqrt{\pi}} \frac{2 \pi}{3} = \frac{\sqrt{3}}{3 \sqrt{\pi}}
fc2 1 π Υ 2 2 A 2 = 1 π 15 2 π π 4 = 15 8 π \displaystyle \frac{1}{\pi} \operatorname{\Upsilon_2^{-2}} A_2 = \frac{1}{\pi} \frac{\sqrt{15}}{2 \sqrt{\pi}} \frac{\pi}{4} = \frac{\sqrt{15}}{8 \sqrt{\pi}}
fc3 1 π ( Υ 2 0 ) A 2 = 1 π 5 4 π π 4 = 5 16 π \displaystyle \frac{1}{\pi} (-\operatorname{\Upsilon_2^0}) A_2 = \frac{1}{\pi} \frac{\sqrt{5}}{4 \sqrt{\pi}} \frac{\pi}{4} = \frac{\sqrt{5}}{16 \sqrt{\pi}}
0.3 * fc3 1 π Υ 2 0 A 2 = 1 π 3 5 4 π π 4 = 3 5 16 π \displaystyle \frac{1}{\pi} \operatorname{\Upsilon_2^0} A_2 = \frac{1}{\pi} \frac{3 \sqrt{5}}{4 \sqrt{\pi}} \frac{\pi}{4} = \frac{3 \sqrt{5}}{16 \sqrt{\pi}}
fc4 1 π Υ 2 2 A 2 = 1 π 15 4 π π 4 = 15 16 π \displaystyle \frac{1}{\pi} \operatorname{\Upsilon_2^2} A_2 = \frac{1}{\pi} \frac{\sqrt{15}}{4 \sqrt{\pi}} \frac{\pi}{4} = \frac{\sqrt{15}}{16 \sqrt{\pi}}

2. Specular Environment Lighting

Let L ( ω ) \displaystyle \operatorname{L}(\overrightarrow{\omega}) be the distant radiance distribution. Evidently, we have L o ( ω o ) = S 2 f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + d ω i = S 2 f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + d ω i S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i = LD ( ω o ) DFG ( ω o ) \displaystyle \operatorname{L_o}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \frac{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}}{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}} \cdot \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \operatorname{LD}(\overrightarrow{\omega_o}) \cdot \operatorname{DFG}(\overrightarrow{\omega_o}) where LD ( ω o ) = S 2 f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + d ω i S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i \displaystyle \operatorname{LD}(\overrightarrow{\omega_o}) = \frac{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}}{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}} and DFG ( ω o ) = S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i \operatorname{DFG}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} .

2-1. Monte Carlo Integration

2-1-1. PDF - NDF

Let ω h = ω i + ω o ω i + ω o \displaystyle \overrightarrow{\omega_h} = \frac{\overrightarrow{\omega_i} + \overrightarrow{\omega_o}}{\| \overrightarrow{\omega_i} + \overrightarrow{\omega_o} \|} be the half vector. By "Equation (5.6)" of PBRT-V3, "Figure 6" of [Walter 2007] and "Figure 14.4" of PBRT-V3, we have the relationship between d ω h \displaystyle d \overrightarrow{\omega_h} and d ω i \displaystyle d \overrightarrow{\omega_i} that d ω h = cos θ r 2 d A = ω i ω h ω i + ω o 2 d ω i = ω i ω h ω i + ( 2 ( ω i ω h ) ω h ω i ) 2 d ω o = ω i ω h 4 ( ω i ω h ) 2 ω h 2 d ω i = 1 4 ω i ω h d ω i \displaystyle d \overrightarrow{\omega_h} = \frac{\cos\theta}{r^2} d A = \frac{|\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|}{{\|\overrightarrow{\omega_i} + \overrightarrow{\omega_o}\|}^2} d \overrightarrow{\omega_i} = \frac{|\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|}{{\|\overrightarrow{\omega_i} + (2 (\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h})\overrightarrow{\omega_h} - \overrightarrow{\omega_i})\|}^2} d \overrightarrow{\omega_o} = \frac{|\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|}{4{(\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h})}^2 {\|\overrightarrow{\omega_h}\|}^2} d \overrightarrow{\omega_i} = \frac{1}{4 |\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|} d \overrightarrow{\omega_i} . Note that since the subtended area on the sphere surface remains the same, the d ω h \displaystyle d \overrightarrow{\omega_h} can be calculated even if the ω h \displaystyle \overrightarrow{\omega_h} is NOT normalized.

By "Equation (9)" of [Heitz 2014] and "Figure 8.15" of PBRT-V3, we have Ω D ( ω h ) ( cos θ h ) + d ω h = 1 \displaystyle \int_{\Omega} \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \, d \overrightarrow{\omega_h} = 1 . According to the relationship between d ω h \displaystyle d \overrightarrow{\omega_h} and d ω i \displaystyle d \overrightarrow{\omega_i} , we have Ω D ( ω h ) ( cos θ h ) + d ω h = Ω D ( ω h ) ( cos θ h ) + 1 4 ω i ω h d ω i = 1 \displaystyle \int_{\Omega} \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \, d \overrightarrow{\omega_h} = \int_{\Omega} \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \frac{1}{4 |\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|} \, d \overrightarrow{\omega_i} = 1 . Evidently, this normalized function can be used as the PDF p ( ω i ) = D ( ω h ) ( cos θ h ) + 1 4 ω i ω h \displaystyle \operatorname{p}(\overrightarrow{\omega_i}) = \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \frac{1}{4 |\overrightarrow{\omega_i} \cdot \overrightarrow{\omega_h}|} .

2-1-2. PDF - VNDF

Genuinely, although the NDF is the PDF used by UE4, the VNDF by [Heitz 2018] is the better alternative.

By "Equation (14)" of [Heitz 2014] and "Equation (8.12)" of PBRT-V3, we have Ω G 1 ( ω o , ω h ) ( ω o ω h ) + D ( ω h ) d ω h = cos θ o \displaystyle \int_{\Omega} \operatorname{G_1}(\overrightarrow{\omega_o}, \overrightarrow{\omega_h}) ( \overrightarrow{\omega_o} \cdot \overrightarrow{\omega_h} )^+ \operatorname{D}(\overrightarrow{\omega_h}) \, d \overrightarrow{\omega_h} = \cos \theta_o .

TODO:

2-1-3. Sampling Trowbridge-Reitz Distribution - NDF

For Beckmann–Spizzichino ("Equation (8.9)" of PBRT-V3) distribution, the derivation of the NDF sampling is provided by "Equation (14.1)" of PBRT-V3.

For isotropic Trowbridge-Reitz ("Equation (8.11)" of PBRT-V3) distribution, namely, GGX distribution, the NDF sampling can be analogously derived. Since the distribution is isotropic, we have p ( ϕ θ h ) = 1 2 π ϕ = 2 π ξ 2 \displaystyle \displaystyle \operatorname{p}(\phi | \theta_h) = \frac{1}{2 \pi} \Rightarrow \phi = 2 \pi \xi_2 . Since the PDF is p ( ω h ) = D ( ω h ) ( cos θ h ) + \displaystyle \operatorname{p}(\overrightarrow{\omega_h}) = \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ , by "13.5.3 Spherical Coordinates" of PBRT-V3, we have the marginal PDF p ( θ h ) = 0 2 π p ( θ h , ϕ ) d ϕ = 0 2 π p ( ω h ) sin θ h d ϕ = 0 2 π D ( ω h ) ( cos θ h ) + sin θ h d ϕ = 2 π D ( ω h ) ( cos θ h ) + sin θ h \displaystyle \operatorname{p}(\theta_h) = \int_0^{2 \pi} \operatorname{p}(\theta_h, \phi) \, d \phi = \int_0^{2 \pi} \operatorname{p}(\overrightarrow{\omega_h}) \sin \theta_h \, d \phi = \int_0^{2 \pi} \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \sin \theta_h \, d \phi = 2 \pi \operatorname{D}(\overrightarrow{\omega_h}) ( \cos \theta_h )^+ \sin \theta_h and the CDF P ( θ h ) = 0 θ h p ( θ h ) d θ h = ξ 1 \displaystyle \operatorname{P}(\theta_h) = \int_0^{\theta_h} \operatorname{p}(\theta'_h) \, d \theta'_h = \xi_1 . Fortunately, the inverse of the CDF is closed-form and we have tan 2 θ h = α 2 ξ 1 1 ξ 1 cos θ h = 1 1 + tan 2 θ h = 1 ξ 1 1 + ( α 2 1 ) ξ 1 \displaystyle \tan^2 \theta_h = \frac{\alpha^2 \xi_1}{1 - \xi_1} \Rightarrow \cos \theta_h = \frac{1}{\sqrt{1 + \tan^2 \theta_h}} = \sqrt{\frac{1 - \xi_1}{1 + (\alpha^2 - 1) \xi_1}} .

The NDF sampling is calculated by TrowbridgeReitzDistribution::Sample_wh in PBRT-V3, ImportanceSampleGGX in UE4 and SampleGGXDir in Unity3D.

2-1-4. Sampling Trowbridge-Reitz Distribution - VNDF

For Beckmann–Spizzichino ("Equation (8.9)" of PBRT-V3) distribution, the derivation of the VNDF sampling is provided by "Equation (14.2)" of PBRT-V3.

TODO:

2-1-5. Low-Discrepancy Sequence

By "20.3 Quasirandom Low-Discrepancy Sequences" of [Colbert 2007] and "13.8.2 Quasi Monte Carlo" of PBRT-V3, the low-discrepancy sequence is the better alternative than pseudo-random sequence to generate the ξ 1 \displaystyle \xi_1 and ξ 2 \displaystyle \xi_2 .

For example, the Hammersley sequence ("7.4.1 Hammersley and Halton Sequences" of PBRT-V3) is a typical low-discrepancy sequence.

The Hammersley sequence is calculated by Hammersley in UE4 and Hammersley2d in Unity3D.

2-2. DFG Term

By "Equation (9.9)" of Real-Time Rendering Fourth Edition, the DFG term is the HDR (Hemispherical Directional Reflectance) R ( ω o ) = S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i = S 2 f ( ω i , ω o ) ( ( 0 , 0 , 1 ) ω i ) + d ω i \displaystyle \operatorname{R}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\overrightarrow{(0,0,1)} \cdot \overrightarrow{\omega_i})^+ \, d \overrightarrow{\omega_i} . Since this integral can be calculated in the tangent space where the normal direction is (0, 0, 1), this integral is independent of the normal direction and can be determined by the view direction in tangent space alone.

And by "Equation (13.3)" of PBRT-V3, we have R ( ω o ) = S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i = 1 N i = 1 N f ( ω i , ω o ) ( cos θ i ) + p ( ω i , ω o ) \displaystyle \operatorname{R}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i} = \frac{1}{N} \sum_{i=1}^N \frac{\operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+}{\displaystyle \operatorname{p}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o})} . Evidently, D ( ω h ) \displaystyle \operatorname{D}(\overrightarrow{\omega_h}) exists in both f ( ω i , ω o ) \displaystyle \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) and p ( ω i , ω o ) \displaystyle \operatorname{p}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) , and thus D ( ω h ) \displaystyle \operatorname{D}(\overrightarrow{\omega_h}) can be omitted when calculating the integral.

Actually, by "Equation (9)" of [Karis 2013], the Fresnel term can be treated separately, and we have R ( ω o ) = S 2 [ F 0 + ( F 90 F 0 ) ( 1.0 ω o ω h ) 5 ] DV ( ω i , ω o ) d ω i = F 0 n R ( ω o ) + F 90 n G ( ω o ) \displaystyle \operatorname{R}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} [F_0 + (F_{90} - F_0) {(1.0 - \overrightarrow{\omega_o} \cdot \overrightarrow{\omega_h})}^5] \operatorname{DV}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \, d \overrightarrow{\omega_i} = F_0 \cdot \operatorname{n_R}(\overrightarrow{\omega_o}) + F_{90} \cdot \operatorname{n_G}(\overrightarrow{\omega_o}) where n R ( ω o ) = S 2 [ 1.0 ( 1.0 ω o ω h ) 5 ] DV ( ω i , ω o ) d ω i \displaystyle \operatorname{n_R}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} [1.0 - {(1.0 - \overrightarrow{\omega_o} \cdot \overrightarrow{\omega_h})}^5] \operatorname{DV}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \, d \overrightarrow{\omega_i} and n G ( ω o ) = S 2 ( 1.0 ω o ω h ) 5 DV ( ω i , ω o ) d ω i \displaystyle \operatorname{n_G}(\overrightarrow{\omega_o}) = \int_{\mathrm{S}^2} {(1.0 - \overrightarrow{\omega_o} \cdot \overrightarrow{\omega_h})}^5 \operatorname{DV}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \, d \overrightarrow{\omega_i} . Evidently, n R ( ω o ) \displaystyle \operatorname{n_R}(\overrightarrow{\omega_o}) and n G ( ω o ) \displaystyle \operatorname{n_G}(\overrightarrow{\omega_o}) can be stored in the LUT.

The DFG term is pre-integrated by InitializeFeatureLevelDependentTextures in UE4 and IntegrateGGXAndDisneyDiffuseFGD in Unity3D, and used by EnvBRDF in UE4 and GetPreIntegratedFGDGGXAndDisneyDiffuse in Unity3D.

2-3. LD Term

2-3-1. Split Integral Approximation

By "Equation (13.3)" of PBRT-V3, we have LD ( ω o ) = S 2 f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + d ω i S 2 f ( ω i , ω o ) ( cos θ i ) + d ω i = 1 N i = 1 N f ( ω i , ω o ) L i ( ω i ) ( cos θ i ) + p ( ω i , ω o ) 1 N i = 1 N f ( ω i , ω o ) ( cos θ i ) + p ( ω i , ω o ) = i = 1 N D F G L ( NdotL ) + 4 ( NdotL ) + ( NdotV ) + 4 ( LdotH ) + D ( NdotH ) + i = 1 N D F G ( NdotL ) + 4 ( NdotL ) + ( NdotV ) + 4 ( LdotH ) + D ( NdotH ) + = i = 1 N L F G ( LdotH ) + ( NdotV ) + ( NdotH ) + i = 1 N F G ( LdotH ) + ( NdotV ) + ( NdotH ) + = i = 1 N L Weight i = 1 N Weight \operatorname{LD}(\overrightarrow{\omega_o}) = \frac{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}}{\int_{\mathrm{S}^2} \operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+ \, d \overrightarrow{\omega_i}} = \frac{\frac{1}{N} \sum_{i=1}^N \frac{\operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) \operatorname{L_i}(\overrightarrow{\omega_i}) (\cos \theta_i)^+}{\displaystyle \operatorname{p}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o})}}{\frac{1}{N} \sum_{i=1}^N \frac{\operatorname{f}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o}) (\cos \theta_i)^+}{\displaystyle \operatorname{p}(\overrightarrow{\omega_i}, \overrightarrow{\omega_o})}} = \frac{\sum_{i=1}^N \frac{\text{D} \cdot \text{F} \cdot \text{G} \cdot \text{L} \cdot (\text{NdotL})^+}{4 \cdot (\text{NdotL})^+ \cdot (\text{NdotV})^+} \frac{4 \cdot (\text{LdotH})^+}{\text{D} \cdot (\text{NdotH})^+}}{\sum_{i=1}^N \frac{\text{D} \cdot \text{F} \cdot \text{G} \cdot (\text{NdotL})^+}{4 \cdot (\text{NdotL})^+ \cdot (\text{NdotV})^+} \frac{4 \cdot (\text{LdotH})^+}{\text{D} \cdot (\text{NdotH})^+}} = \frac{\sum_{i=1}^N \text{L} \frac{\text{F} \cdot \text{G} \cdot (\text{LdotH})^+}{(\text{NdotV})^+ \cdot (\text{NdotH})^+}}{\sum_{i=1}^N \frac{\text{F} \cdot \text{G} \cdot (\text{LdotH})^+}{(\text{NdotV})^+ \cdot (\text{NdotH})^+}} = \frac{\sum_{i=1}^N \text{L} \cdot \text{Weight}}{\sum_{i=1}^N \text{Weight}} where Weight = F G ( LdotH ) + ( NdotV ) + ( NdotH ) + \displaystyle \text{Weight} = \frac{\text{F} \cdot \text{G} \cdot (\text{LdotH})^+}{(\text{NdotV})^+ \cdot (\text{NdotH})^+} .

By "Equation (53)" of [Lagarde 2014], when L i ( ω i ) \displaystyle \operatorname{L_i}(\overrightarrow{\omega_i}) is constant, we have LD ( ω o ) = i = 1 N L Weight i = 1 N Weight = L i = 1 N Weight i = 1 N Weight = L \displaystyle \operatorname{LD}(\overrightarrow{\omega_o}) = \frac{\sum_{i=1}^N \text{L} \cdot \text{Weight}}{\sum_{i=1}^N \text{Weight}} = \frac{\text{L} \cdot \sum_{i=1}^N \text{Weight}}{\sum_{i=1}^N \text{Weight}} = \text{L} which does NOT depend on the Weight term. This means that when L i ( ω i ) \displaystyle \operatorname{L_i}(\overrightarrow{\omega_i}) is constant, no matter what Weight term we use, we will always have an exact match.

By [Karis 2013], assuming that the Weight term equals ( cos θ i ) + \displaystyle (\cos \theta_i)^+ , we have the split integral approximation LD ( ω o ) = i = 1 N L Weight i = 1 N Weight i = 1 N L ( NdotL ) + i = 1 N ( NdotL ) + \displaystyle \operatorname{LD}(\overrightarrow{\omega_o}) = \frac{\sum_{i=1}^N \text{L} \cdot \text{Weight}}{\sum_{i=1}^N \text{Weight}} \approx \frac{\sum_{i=1}^N \text{L} \cdot (\text{NdotL})^+}{\sum_{i=1}^N (\text{NdotL})^+} .

The LD term is pre-integrated by FilterCS in UE4 and IntegrateLD in Unity3D, and used by GetSkyLightReflection in UE4 and SampleEnvWithDistanceBaseRoughness in Unity3D.

2-3-2. Dimensions

Ideally, we should use three dimensions: N (world space), NdotV and roughness to look up the pre-integrated LD term.

By [Karis 2013], roughness is mapped to mip-level.

The mapping between roughness and mip-level is calculated by ComputeReflectionCaptureMipFromRoughness and ComputeReflectionCaptureRoughnessFromMip in UE4, and PerceptualRoughnessToMipmapLevel and MipmapLevelToPerceptualRoughness in Unity3D.

However, we do NOT have enough remaining dimensions to store both N (world space) and NdotV. By [Karis 2013], we assume "V = N" when pre-integrating the LD term, while the reflection direction R is used to look up the LD term when rendering. By "Figure 10.37" of Real-Time Rendering Fourth Edition, by [Lagarde 2014], the reflection direction is biased towards the normal direction to reduce the error generated by the non-clipped specular lobe.

The deviation is calculated by GetOffSpecularPeakReflectionDir in UE4 and GetSpecularDominantDir in Unity3D.

TODO: If we use the Paraboloid Map, perhaps we can use the 3D texture and provide one dimension for the NdotV. Thus, we can use both N (world space) and NdotV to look up the LD term.

2-3-3. Variance Reduction

By "20.4 Mipmap Filtered Samples" of [Colbert 2007], we use the mip-level sample_mip_level = max ( 0 , log ( d ω S d ω P ) ) \text{sample\_mip\_level} = \displaystyle \max(0, \log(\sqrt{\frac{d\overrightarrow{\omega_S}}{d\overrightarrow{\omega_P}}})) to sample the filtered L value from the distant radiance distribution to reduce the variance. The d ω S \displaystyle d\overrightarrow{\omega_S} is the solid angle subtended by the sample, and we have d ω S = 1 N 1 PDF \displaystyle d\overrightarrow{\omega_S} = \frac{1}{\text{N}} \cdot \frac{1}{\text{PDF}} . The d ω P \displaystyle d\overrightarrow{\omega_P} is the solid angle subtended by a single texel of the zeroth mip-level of the texture, and by "Projection from Cube Maps" of [Sloan 2008], we have d ω P = 1 cubesize_u cubesize_v 4 1 2 + u 2 + v 2 ( 1 2 + u 2 + v 2 ) \displaystyle d\overrightarrow{\omega_P} = \frac{1}{\text{cubesize\_u} \cdot \text{cubesize\_v}} \cdot \frac{4}{\sqrt{1^2 + u^2 +v^2} \cdot (1^2 + u^2 +v^2)} .

The d ω S \displaystyle d\overrightarrow{\omega_S} is calculated by SolidAngleSample in UE4 and omegaS in Unity3D. And the d ω P \displaystyle d\overrightarrow{\omega_P} is calculated by SolidAngleTexel in UE4 and invOmegaP in Unity3D.

References

[Ramamoorthi 2001 A] Ravi Ramamoorthi, Pat Hanrahan. "On the Relationship between Radiance and Irradiance: Determining the illumination from images of a convex Lambertian object." JOSA 2001.
[Ramamoorthi 2001 B] Ravi Ramamoorthi, Pat Hanrahan. "An Efficient Representation for Irradiance Environment Maps." SIGGRAPH 2001.
[Sloan 2002] Peter-Pike Sloan, Jan Kautz, John Snyder. "Precomputed Radiance Transfer for Real-Time Rendering in Dynamic, Low-Frequency Lighting Environments." SIGGRAPH 2002.
[Kautz 2002] Jan Kautz, Peter-Pike Sloan, John Snyder. "Fast, Arbitrary BRDF Shading for Low-Frequency Lighting Using Spherical Harmonics." EGWR 2002.
[Walter 2007] Bruce Walter, Stephen Marschner, Hongsong Li, Kenneth Torrance. "Microfacet Models for Refraction through Rough Surfaces." EGSR 2007.
[Colbert 2007] Mark Colbert, Jaroslav Krivanek. "GPU-Based Importance Sampling." GPU Gems 3.
[Sloan 2008] Peter-Pike Sloan. "Stupid Spherical Harmonics (SH) Tricks." GDC 2008.
[Karis 2013] Brian Karis. "Real Shading in Unreal Engine 4." SIGGRAPH 2013.
[Hable 2014] John Hable. "Simple and Fast Spherical Harmonic Rotation." Filmic Worlds Blog 2014.
[Lagarde 2014] Sebastian Lagarde, Charles Rousiers. "Moving Frostbite to PBR." SIGGRAPH 2014.
[Heitz 2014] Eric Heitz. "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs." JCGT 2014.
[Heitz 2018] Eric Heitz. "Sampling the GGX Distribution of Visible Normals." JCGT 2018.