# Is using Spherical Harmonics still viable as a technique nowadays?

I've been implementing spherical harmonics in my Engine for learning purpose.

I was wondering if Spherical Harmonics are still used in modern engine or if they moved on to the more simple cubemaps or pre-convolved environment map with PBR and IBL (e.g in UE4) or any other technique for performance and good visual purpose ? What is the technique with the best performance/good visual ratio compared to SH ?

• Wow... I haven't thought about Spherical Harmonics since physics gradschool. In the late 90s.
– Almo
Oct 25 '16 at 13:34
• Haha, I see. I'm trying many techniques to learn ;) Oct 25 '16 at 13:35
• :D It might be the right thing here; I don't really know!
– Almo
Oct 25 '16 at 13:37
• I use them for my ambient lighting. Build a grid of probs-> Bake cube map to SH data-> pull out active SH data per frame-> Use tile based deferred(2000 SH probs) to render SH data using world normal. I can make an answer if you like and go into more detail. I think there is a paper about FarCry 4 ambient lighting to I used for my implementation, not 100% the same as I don't use volume textures Oct 26 '16 at 0:08
• That would be interesting if you could detail that in an answer and also explain why using that technique instead of another Oct 26 '16 at 6:17

Ok so first up the way I use my Spherical Harmonics is to build a grid of probe points along the top of the terrain\objects, I offset the y value of the probe so that when I capture a cubemap of the location I get all 6 faces filled.

I render the cubemap at 16x16 or 32x32 pixels, you don't need lots of resolution because u only want to capture small amounts of color. eg: for ambient lighting from what I can see after getting this up and running as long as u are getting green from the ground, blue from the sky and brown\gray for the mountains it looks good.

Once I have my probe grid I then convert each of the cubemaps into 3rd order Spherical Harmonic that gives me 9 vector3 color values.

The Spherical Harmonics are loaded into an octree for CPU culling and then passed of to my tilebased deferred compute shader to do finer per tile culling, once I have my Spherical Harmonics list on the GPU I just render them like lights, sampling from the Spherical Harmonics using the world normal and adding the result to my ambient light term.

The only slow part of all of this is building the probe grid and computing the Spherical Harmonics from cubemaps so I do it all offline and just load the octree on start up.

I'm using this because its the cheapest\easiest to implement fake Global Illumination(ambient light) so if you mix it with a per frame global dynamic cubemap you end up with really nice ambient lighting.

// 'sphericalHarmonicBase' is the lighting environment projected onto SH (3rd order in this case),
// and 'n' is the surface normal
float3 ProjectOntoSH9(float3 n, float3 sphericalHarmonicBase[9])
{
float3 result = 0.0f;

// Cosine kernel
const float A0 = 1.0f;
const float A1 = 2.0f / 3.0f;
const float A2 = 0.25f;

// Band 0
result += sphericalHarmonicBase[0] * 0.282095f * A0;

// Band 1
result += sphericalHarmonicBase[1] * 0.488603f * n.y * A1;
result += sphericalHarmonicBase[2] * 0.488603f * n.z * A1;
result += sphericalHarmonicBase[3] * 0.488603f * n.x * A1;

// Band 2
result += sphericalHarmonicBase[4] * 1.092548f * n.x * n.y * A2;
result += sphericalHarmonicBase[5] * 1.092548f * n.y * n.z * A2;
result += sphericalHarmonicBase[6] * 0.315392f * (3.0f * n.z * n.z - 1.0f) * A2;
result += sphericalHarmonicBase[7] * 1.092548f * n.x * n.z * A2;
result += sphericalHarmonicBase[8] * 0.546274f * (n.x * n.x - n.y * n.y) * A2;

// Clamp to zero

return result;
}

Ambientcolor += ProjectOntoSH9(normalW, SH);


Just the ambient light(SH):

Render output:

I still have more tweaking to do but for now I'm happy with how it looks.

As for roughness and stuff like that because you are only modifying the ambient term you just do you specular and diffuse light the way u want, I have materials set up in my engine once again the compute shader does the work of selecting the right material based off a uint material ID texture.

• Thanks for your answer. Something that could be possible is to compute probes and project them to spherical harmonics for ambient light and then prefilter them to compute specular lighting using UE4's way to bake GGX. Also using Oren-Nayar for diffuse. I guess that would be very good looking, physically-based and fast (I hope). Oct 28 '16 at 13:59
• Or, for the specular, I think that it could be interesting to prefilter the cubemap using UE4's method and maybe then project it to SH and save texture fetching time. Just a thought, maybe I'm wrong. Oct 28 '16 at 14:06
• I your like your idea, I'm still playing with my lighting as its one of the more fun things to do. I'm slowly working on a system that will use compute shaders to convert the cube maps to SH. I could also do some prefiltering and fun things like that. Oct 30 '16 at 20:03