<p>To start I'll assume you have a list of (x,y,z) points each with a r, g, b color that are the samples you want to approximate with the spherical harmonics.</p>

<p>To get the coefficients you make a matrix n x 9 $A$ where each row is the sequence $y_0(x,y,z), y_1^{-1}(x,y,z), y_1^{0}(x,y,z), y_1^{1}(x,y,z), y_2^{-2}(x,y,z), y_2^{-1}(x,y,z), y_2^{0}(x,y,z), y_2^{1}(x,y,z), y_2^{2}(x,y,z)$ of a point and also a n x 3 matrix $b$ with each corresponding row the color at that point.</p>

<p>Then you take a 9x3 matrix $x$ of the unknown coefficients (9 for each color). Then $Ax=b$ is the equation to solve. This equation will be overdetermined so you'll need to approximate the solution.</p>

<p>This means doing a <a href="https://en.wikipedia.org/wiki/Linear_regression" rel="nofollow noreferrer">linear regression</a> to find the coefficients that give the smallest error. This is well described in linear algebra.</p>

CC BY-SA 3.0
2017-04-15T02:26:50.430Z
I understand that I need a matrix (9 numbers) for each color. So I will need a matrix for red, a matrix for green, and a matrix for blue. However you are telling me these 9 numbers has to be y0,y−11,y01,y11,y−22,y−12,y02,y12,y22 but I don't understand how to calculate these matrix values. I don't understand what you mean by" nx3 matrix b with the color at that point?" What is "n" here? Do you mean just RGB values?
Blue Bug
CC BY-SA 3.0
2017-04-15T05:45:21.223Z
You don't need to do linear regression. Since SH form an orthonormal basis, each SH's coefficient will be equal to the inner product of the cubemap with the SH: the spherical integral of (cubemap * SH). Or in other words, sum (pixel color * SH evaluated at that pixel's direction vector * solid angle of the pixel) over all pixels in the cubemap.
Nathan Reed
CC BY-SA 3.0
2017-04-17T22:10:28.580Z
What do you mean by 9x3 matrix x of the unknown coefficients(9 for each color)? So there are three rows? And each row is all the same number that represents either color red or green or blue? Is my job then just multiplying matrix A to mat x to get matrix of 3x3 b?
Blue Bug
CC BY-SA 3.0
2017-04-14T12:47:58.287Z
2017-04-15T09:40:58.400Z
2017-04-15T09:40:58.400Z
ratchet freak
<p>So at start you have samples from your cube map. Each sample has color and normal (dir) at which you sampled that color.
This is how I do it. I use coeffs from this <a href="https://graphics.stanford.edu/papers/envmap/envmap.pdf" rel="nofollow noreferrer">paper</a> (the same you linked), there are values for the first 9 of them.</p>

<p><strong>So for constructing for each sample you:</strong></p>

<ul>
<li>Compute your SH basis using normal from sample</li>
</ul>



<pre><code>float Y00     = 0.282095;
float Y11     = 0.488603 * normal.x;
float Y10     = 0.488603 * normal.z;
float Y1_1    = 0.488603 * normal.y;
float Y21     = 1.092548 * normal.x*normal.z;
float Y2_1    = 1.092548 * normal.y*normal.z;
float Y2_2    = 1.092548 * normal.y*normal.x;
float Y20     = 0.946176 * normal.z * normal.z - 0.315392;
float Y22     = 0.546274 * (normal.x*normal.x - normal.y*normal.y);
</code></pre>

<ul>
<li>Then multiply these coeffs by your color (L)</li>
</ul>



<pre><code>vec3 L00   = L * Y00;
vec3 L11   = L * Y11;
vec3 L10   = L * Y10;
vec3 L1_1  = L * Y1_1;
vec3 L21   = L * Y21;
vec3 L2_1  = L * Y2_1;
vec3 L2_2  = L * Y2_2;
vec3 L20   = L * Y20;
vec3 L22   = L * Y22;
</code></pre>

<p>And thats it, you have your coeffs. Now, you can store them in some data structure. You accumulate each of them like:</p>

<pre><code>someArray[0] += L00;
someArray[1] += L11;
etc...
</code></pre>

<p>And you divide these accumulated coeffs by a number of samples;</p>

<p><strong>Then when reconstructing :</strong></p>

<ul>
<li>compute your SH basis one more time for normal at point of the scene.</li>
<li>for approximating diffuse irradiance at given point of scene,
convolution with cosine lobe is performed using normal from that point.
Convolution means, for each SH order, multiplication by $
   \hat{A}=[\pi, \frac{2}{3}\pi, \frac{\pi}{4}]$</li>
</ul>

<p>$\hat{A_0} = 3.141593$, 
$\hat{A_1} = 2.094395$, 
$\hat{A_2} = 0.785398$</p>

<ul>
<li>L coeffs are sampled from data structure.</li>
</ul>



<pre><code>vec3 color = A0*Y00*L00  
             + A1*Y1_1*L1_1 + A1*Y10*L10 + A1*Y11*L11 
             + A2*Y2_2*L2_2 + A2*Y2_1*L2_1 + A2*Y20*L20 + A2*Y21*L21 + A2*Y22*L22;
</code></pre>

<p><strong>Disclaimer:</strong> This basically works (for me) but I am not an expert and something might be missing or not perfect because this <strong>IS</strong> confusing topic...</p>

CC BY-SA 3.0
2017-04-17T21:37:52.423Z
Hi. Thank you for detailed instruction. It helps a lot to understand the paper. However I am wondering how you arrived to "cosine lobe in SH" are these numbers ratio given to you in the paper? If so I am not being able to find that section.
Blue Bug
CC BY-SA 3.0
2017-04-17T22:49:06.833Z
@BlueBug In diffuse lighting lambertian model ray is reflected at many angles rather than as in specular, in one direction. So, in order to approximate this and evaluate irradiance at given point the convolution on cosine lobe is performed - this means in case of SH - division by, for each of SH order 1, 2, 3 - [pi, (2/3)*pi, pi/4]. I hope it helps, check also [this](https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/) or [this](https://en.wikipedia.org/wiki/Lambert%27s_cosine_law)
mdkdy
CC BY-SA 3.0
2017-04-18T00:06:15.890Z
I meant not divison but multiplication, sorry.
mdkdy
CC BY-SA 3.0
2017-04-18T00:59:47.847Z
After reading your answer I edited my question to ask you with some description. I don't understand why you don't do the green part of the equation. Are you already doing it but then I am not being able to see what you are doing? Or is it that there are more than one way to make SH map?
Blue Bug
CC BY-SA 3.0
2017-04-18T20:04:41.240Z
Instead of weighting each cube map sample equally, it would be better to weight by the solid angle of each pixel. Otherwise, you'll over-weight the corners and under-weight the face centers.
Nathan Reed
CC BY-SA 3.0
2017-04-20T08:58:27.287Z
@NathanReed Where? During accumulation to the buffer?
mdkdy
CC BY-SA 3.0
2017-04-20T13:21:01.773Z
Right, when computing the SH coefficients from the cube map.
Nathan Reed
CC BY-SA 3.0
2017-04-20T14:17:59.650Z
@NathanReed Myself I am using pretty uniform poisson sampling to avoid biasing samples.
mdkdy
CC BY-SA 3.0
2017-04-15T11:40:06.890Z
2017-04-18T09:48:56.267Z
2017-04-18T09:48:56.267Z
mdkdy
<ul>
<li><a href="https://graphics.stanford.edu/papers/envmap/envmap.pdf" rel="nofollow noreferrer">envmap.pdf | An Efficient Representation for Irradiance Environment Maps</a></li>
<li><a href="http://xlgames-inc.github.io/posts/sphericalharmonics0/" rel="nofollow noreferrer">Spherical Harmonics and applications in real time graphics</a></li>
</ul>

<p>I am using Spherical Harmonics to turn reflective(mirror like) cube map to diffuse light cube map.</p>

<p>From what I understand for an image, I calculate 9 coefficient(for red green blue) that describes the color of the cube map.</p>

<p>The nine coefficients are this...</p>

<p><a href="https://i.sstatic.net/kmjyY.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/kmjyY.png" alt="enter image description here"></a></p>

<p>And when you visualize them they become...</p>

<p><a href="https://i.sstatic.net/oRvEP.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/oRvEP.png" alt="enter image description here"></a></p>

<p>Then I do something with these coefficients to get color of the cube map.</p>

<p>The part that I am not understanding is using an image to get that 9 coefficients. All the papers kinda assume that you somehow got that coefficient calculated because it is "easy".</p>

<p>I don't know how to do that calculation.</p>

<hr>

<p>Update</p>

<p>So while I were looking at <a href="http://simonstechblog.blogspot.com/2011/12/spherical-harmonic-lighting.html" rel="nofollow noreferrer">Spherical Harmonic Lighting | Simon's Tech Blog</a></p>

<p>I found this equation...
<a href="https://i.sstatic.net/ViYx1.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ViYx1.png" alt="enter image description here"></a></p>

<p>So now I know that the mysterious yellow part of the equation was "solid angle related". I do know how to do solid angle but I still don't understand how to do it.</p>

<spherical-harmonics>
Spherical Harmonics Diffuse CubeMap. How to get coefficients?
Blue Bug
# Spherical Harmonics Diffuse CubeMap. How to get coefficients?

(Asked by: username_0 on 2017-04-14)

* [envmap.pdf | An Efficient Representation for Irradiance Environment Maps](https://graphics.stanford.edu/papers/envmap/envmap.pdf)
* [Spherical Harmonics and applications in real time graphics](http://xlgames-inc.github.io/posts/sphericalharmonics0/)

I am using Spherical Harmonics to turn reflective(mirror like) cube map to diffuse light cube map.

From what I understand for an image, I calculate 9 coefficient(for red green username_0) that describes the color of the cube map.

The nine coefficients are this...

[![enter image description here](https://i.sstatic.net/kmjyY.png)](https://i.sstatic.net/kmjyY.png)

And when you visualize them they become...

[![enter image description here](https://i.sstatic.net/oRvEP.png)](https://i.sstatic.net/oRvEP.png)

Then I do something with these coefficients to get color of the cube map.

The part that I am not understanding is using an image to get that 9 coefficients. All the papers kinda assume that you somehow got that coefficient calculated because it is "easy".

I don't know how to do that calculation.

---

Update

So while I were looking at [Spherical Harmonic Lighting | Simon's Tech Blog](http://simonstechblog.blogspot.com/2011/12/spherical-harmonic-lighting.html)

I found this equation...
[![enter image description here](https://i.sstatic.net/ViYx1.png)](https://i.sstatic.net/ViYx1.png)

So now I know that the mysterious yellow part of the equation was "solid angle related". I do know how to do solid angle but I still don't understand how to do it.

**Tags:** spherical-harmonics


---

## 2 answers

### Answer by username_3 on 2017-04-15. Score: 4 | Accepted answer

So at start you have samples from your cube map. Each sample has color and normal (dir) at which you sampled that color.
This is how I do it. I use coeffs from this [paper](https://graphics.stanford.edu/papers/envmap/envmap.pdf) (the same you linked), there are values for the first 9 of them.

**So for constructing for each sample you:**

* Compute your SH basis using normal from sample

```
float Y00     = 0.282095;
float Y11     = 0.488603 * normal.x;
float Y10     = 0.488603 * normal.z;
float Y1_1    = 0.488603 * normal.y;
float Y21     = 1.092548 * normal.x*normal.z;
float Y2_1    = 1.092548 * normal.y*normal.z;
float Y2_2    = 1.092548 * normal.y*normal.x;
float Y20     = 0.946176 * normal.z * normal.z - 0.315392;
float Y22     = 0.546274 * (normal.x*normal.x - normal.y*normal.y);

```

* Then multiply these coeffs by your color (L)

```
vec3 L00   = L * Y00;
vec3 L11   = L * Y11;
vec3 L10   = L * Y10;
vec3 L1_1  = L * Y1_1;
vec3 L21   = L * Y21;
vec3 L2_1  = L * Y2_1;
vec3 L2_2  = L * Y2_2;
vec3 L20   = L * Y20;
vec3 L22   = L * Y22;

```

And thats it, you have your coeffs. Now, you can store them in some data structure. You accumulate each of them like:

```
someArray[0] += L00;
someArray[1] += L11;
etc...

```

And you divide these accumulated coeffs by a number of samples;

**Then when reconstructing :**

* compute your SH basis one more time for normal at point of the scene.
* for approximating diffuse irradiance at given point of scene,
  convolution with cosine lobe is performed using normal from that point.
  Convolution means, for each SH order, multiplication by $
  \hat{A}=[\pi, \frac{2}{3}\pi, \frac{\pi}{4}]$

$\hat{A\_0} = 3.141593$,
$\hat{A\_1} = 2.094395$,
$\hat{A\_2} = 0.785398$

* L coeffs are sampled from data structure.

```
vec3 color = A0*Y00*L00  
             + A1*Y1_1*L1_1 + A1*Y10*L10 + A1*Y11*L11 
             + A2*Y2_2*L2_2 + A2*Y2_1*L2_1 + A2*Y20*L20 + A2*Y21*L21 + A2*Y22*L22;

```

**Disclaimer:** This basically works (for me) but I am not an expert and something might be missing or not perfect because this **IS** confusing topic...

> **Comments:**
> **username_0**: Hi. Thank you for detailed instruction. It helps a lot to understand the paper. However I am wondering how you arrived to "cosine lobe in SH" are these numbers ratio given to you in the paper? If so I am not being able to find that section.  
> **username_3**: @username_0 In diffuse lighting lambertian model ray is reflected at many angles rather than as in specular, in one direction. So, in order to approximate this and evaluate irradiance at given point the convolution on cosine lobe is performed - this means in case of SH - division by, for each of SH order 1, 2, 3 - [pi, (2/3)*pi, pi/4]. I hope it helps, check also [this](https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/) or [this](https://en.wikipedia.org/wiki/Lambert%27s_cosine_law)  
> **username_3**: I meant not divison but multiplication, sorry.  
> **username_0**: After reading your answer I edited my question to ask you with some description. I don't understand why you don't do the green part of the equation. Are you already doing it but then I am not being able to see what you are doing? Or is it that there are more than one way to make SH map?  
> **username_2**: Instead of weighting each cube map sample equally, it would be better to weight by the solid angle of each pixel. Otherwise, you'll over-weight the corners and under-weight the face centers.  
> **username_3**: @username_2 Where? During accumulation to the buffer?  
> **username_2**: Right, when computing the SH coefficients from the cube map.  
> **username_3**: @username_2 Myself I am using pretty uniform poisson sampling to avoid biasing samples.  

---

### Answer by username_1 on 2017-04-14. Score: 1

To start I'll assume you have a list of (x,y,z) points each with a r, g, b color that are the samples you want to approximate with the spherical harmonics.

To get the coefficients you make a matrix n x 9 $A$ where each row is the sequence $y\_0(x,y,z), y\_1^{-1}(x,y,z), y\_1^{0}(x,y,z), y\_1^{1}(x,y,z), y\_2^{-2}(x,y,z), y\_2^{-1}(x,y,z), y\_2^{0}(x,y,z), y\_2^{1}(x,y,z), y\_2^{2}(x,y,z)$ of a point and also a n x 3 matrix $b$ with each corresponding row the color at that point.

Then you take a 9x3 matrix $x$ of the unknown coefficients (9 for each color). Then $Ax=b$ is the equation to solve. This equation will be overdetermined so you'll need to approximate the solution.

This means doing a [linear regression](https://en.wikipedia.org/wiki/Linear_regression) to find the coefficients that give the smallest error. This is well described in linear algebra.

> **Comments:**
> **username_0**: I understand that I need a matrix (9 numbers) for each color. So I will need a matrix for red, a matrix for green, and a matrix for username_0. However you are telling me these 9 numbers has to be y0,y−11,y01,y11,y−22,y−12,y02,y12,y22 but I don't understand how to calculate these matrix values. I don't understand what you mean by" nx3 matrix b with the color at that point?" What is "n" here? Do you mean just RGB values?  
> **username_2**: You don't need to do linear regression. Since SH form an orthonormal basis, each SH's coefficient will be equal to the inner product of the cubemap with the SH: the spherical integral of (cubemap * SH). Or in other words, sum (pixel color * SH evaluated at that pixel's direction vector * solid angle of the pixel) over all pixels in the cubemap.  
> **username_0**: What do you mean by 9x3 matrix x of the unknown coefficients(9 for each color)? So there are three rows? And each row is all the same number that represents either color red or green or username_0? Is my job then just multiplying matrix A to mat x to get matrix of 3x3 b?  

---

