Ambient And Directional Lighting In Spherical Harmonics
Stupid SH Tricks by Peter-Pike Sloan, released in 2008, is an excellent reference on spherical harmonics (SH). It covers many techniques for representing lighting as SH, including:
- Scaling SH for a directional light so that it matches when the normal exactly faces the light
- Extracting an ambient and directional light from environment lighting represented as SH
Extracting lighting from SH has different solutions depending on how you choose to represent your directional lights and whether you are working with L1 (4-term) or L2 (9-term) SH. This post works through the derivation for all these cases, hopefully improving clarity for anyone looking to implement it, and a shadertoy that demonstrates the results.
Results
If you just want to look at the shader code for the image above, then here is the link. The shadertoy shows polar plots of an ambient and directional light (blue line) vs the SH representation (red line) for the cases discussed below.
Definitions
This page follows the same conventions as Stupid SH Tricks. We write the spherical harmonic basis functions as $y_l^m(v)$ where $l$ is the order and $|m| \leq l$. Listing one function for each unique constant gives:
If a function $\Bf(v)$ is represented as a set of spherical harmonic coefficients $f_l^m$, it can be reconstructed as a weighted sum of the basis functions:
The spherical harmonic basis functions are orthonormal, integrating pairwise to 1 or 0 over the the sphere.
Using this orthonormal property, we can compute these coefficients by integrating the original function $f$ against each basis function over the sphere.
Spherical harmonics are a frequency-space representation, so convolution with a rotationally symmetric kernel is a multiplication operation on the coefficients. These multiplication factors are the same within each level of the coefficients, so for some kernel $\Bh$ are written as $h_l$.
If we use the notation $\Bh \star \Bf$ to apply the kernel $\Bh$ to $\Bf$, then these multiplication factors are applied as follows:
We will use $\Bh$ to represent a clamped cosine kernel, which represents the response of a diffuse surface to a lighting environment. For this kernel, the coefficients usually contain an additional factor of $1/\pi$, and for up to order 2 are:
This does not exactly reproduce a clamped cosine response, but has low error when using spherical harmonics of order 2 or above.
Ambient Light
The incoming light from an ambient light source $\Ba(v)$ is a constant function, so it has only one non-zero spherical coefficient $\DC{a}$.
We would like set this coefficient so that the light produces a response of 1 on a diffuse surface. Using the clamped cosine convolution $\Bh$, this implies that:
So
Directional Light
The incoming light from a directional light $\Bd_\omega(v)$ is from a single direction $\omega$. We represent this using a scaled delta function $\delta_\omega(v)$ as follows:
This delta function is only non-zero at $\omega$, and integrates to 1 over the sphere. It is useful to choose $\mu$ so that a diffuse surface oriented towards the light source has a response of 1.
The spherical harmonic coefficients $d_l^m$ can be computed as follows:
A response of 1 when facing the light source implies that:
For high order spherical harmonics, the value of $\mu$ converges to $\pi$. For lower order spherical harmonics with only a small number of terms, it is useful to pick a value of $\mu$ that matches exactly.
Order 1
The scale factor $\mu$ does not depend on $\omega$, so choosing the $z$ axis results in:
Order 2
The scale factor $\mu$ does not depend on $\omega$, so choosing the $z$ axis results in:
Least Squares Fit Ambient Plus Directional Light
Given a lighting environment that has already been convolved with a clamped cosine kernel, we wish to approximate it with an ambient and directional light.
Let us assume that the direction $\omega$ has already been picked, and add some notation for convolutions such that $\conv{\Bf}(v) = (\Bh \star \Bf)(v)$.
So given our pre-convolved lighting environment $\conv{\Be}(v)$, we wish to choose an ambient light strength $\LA$ and directional light strength $\LD$ that minimises the squared error:
We will make use of the following identity for functions represented by spherical harmonic coefficients:
Since the ambient light has only a single non-zero coefficient $\DC{a}$ we can fit the directional light strength $\LD$ using the remaining coefficients, then minimise the combined error in this first coefficient after $\LD$ is known.
Considering only terms where $l \neq 0$, this implies that the error from these terms is minimised when:
Once $\LD$ is known, we can solve for $\LA$ using the remaining coefficient:
The solution for $\LD$ depends on how many spherical harmonic coefficients are used for the directional light.
Order 1
For $\LD$, the denominator does not depend on $\omega$, so choosing the $z$ axis results in:
This lets us simplify $\LD$ to:
We can simplify this further by specifying if the directional light SH has been scaled to match exactly when facing the surface, which specifies if $\mu$ is $\DA$ (scaled to match) or $\pi$ (not scaled).
Multiplying out these two cases gives the following result for order 1 spherical harmonics, given a pre-convolved lighting environment $\conv{\Be}(v)$ and light direction $\omega$:
Order 2
For $\LD$, the denominator does not depend on $\omega$, so choosing the $z$ axis results in:
This lets us simplify $\LD$ to:
We can simplify this further by specifying if the directional light SH has been scaled to match exactly when facing the surface, which specifies if $\mu$ is $\DB$ (scaled to match) or $\pi$ (not scaled).
Multiplying out these two cases gives the following result for order 2 spherical harmonics, given a pre-convolved lighting environment $\conv{\Be}(v)$ and light direction $\omega$:
Example code that that builds SH for an ambient and directional light, and then re-extracts the direction, ambient light strength and directional light strength using these formulae can be found at this shadertoy.