struct SphericalHarmonics
Spherical Harmonics are kinda like Fourier, but on a sphere. That doesn’t mean terribly much to me, and could be wrong, but check out here for more details about how Spherical Harmonics work in this context!
However, the more practical thing is, SH can be a function that describes a value over the surface of a sphere! This is particularly useful for lighting, since you can basically store the lighting information for a space in this value! This is often used for lightmap data, or a light probe grid, but StereoKit just uses a single SH for the entire scene. It’s a gross oversimplification, but looks quite good, and is really fast! That’s extremely great when you’re trying to hit 60fps, or even 144fps.
StereoKit’s SH format at a glance, both for this CPU side struct, and for the GPU side representation:
| Choice | SphericalHarmonics struct | Shader constants |
|---|---|---|
| Basis phase | No Condon-Shortley phase | Same |
| Normalization | Orthonormal, constants at eval time | Constants pre-baked |
| Domain | Radiance, no cosine lobe | Irradiance, lobe baked in |
| Packing | Bands ascending, RGB per coefficient | 7 Vec4s, dot-product form |
This struct is the CPU side format! Math and imports happen
here, and StereoKit converts it to the baked shader form once per
lighting change. With no phase factor, all basis signs are
positive, so a light from above lands as a positive coefficient2
(the linear y term), and the linear band points toward the
brightest region. Watch out when importing coefficients from
elsewhere as many libraries (ARCore, DirectXMath) include the phase
factor, flipping the odd terms (coefficients 2, 4, 6, and 8)
relative to this. If imported lighting shows up rotated 180
degrees, with up reading as down, negate those four!
Instance Fields and Properties
| Vec3 coefficient1 | Band 0, the constant/ambient term. |
| Vec3 coefficient2 | Band 1, the linear y term. |
| Vec3 coefficient3 | Band 1, the linear z term. |
| Vec3 coefficient4 | Band 1, the linear x term. |
| Vec3 coefficient5 | Band 2, the xy term. |
| Vec3 coefficient6 | Band 2, the yz term. |
| Vec3 coefficient7 | Band 2, the 3z^2-1 term. |
| Vec3 coefficient8 | Band 2, the xz term. |
| Vec3 coefficient9 | Band 2, the x^2-y^2 term. |
| SHLight DominantLight | The dominant directional light in this lighting data, the same derivation Lighting.MainLight uses! The direction is normalized, and the color is the projection matched directional component: the light you could remove from this SH, or add back on top of it. |
| Vec3 DominantLightDirection | The direction the dominant light is traveling, pointing away from the light source, the opposite of SHLight.directionTo. |
| Vec3 DominantLightDirectionTo | The direction toward the strongest light source in this lighting data, following the same convention as SHLight.directionTo. The value is normalized, and sampling the light’s color is sh.Sample(sh.DominantLightDirectionTo). |
Instance Methods
| SphericalHarmonics | Creates a SphericalHarmonic from an array of coefficients. Useful for loading stored data! |
| Add | Adds a ‘directional light’ to the lighting approximation. This can be used to bake a multiple light setup, or accumulate light from a field of points. |
| Brightness | Scales all the SphericalHarmonic’s coefficients! This behaves as if you’re modifying the brightness of the lighting this object represents. |
| Sample | Look up the color information in a particular direction: the irradiance for a surface whose normal faces that way. |
| SubtractLight | Removes a directional light from this lighting data, clamped to the light actually present so the result stays physical. Pairs with DominantLight for splitting the dominant light out of an SH, the way Lighting.MainLight does. |
| ToArray | Converts the SphericalHarmonic into an array of coefficients 9 long. Useful for storing calculated data! |
Static Methods
| FromLights | Creates a SphericalHarmonics approximation of the irradiance given from a set of directional lights! |
Found an issue with these docs, or have some additional questions? Create an Issue on Github!