<p>I'm reading through <a href="https://learnopengl.com/PBR/IBL/Specular-IBL" rel="nofollow noreferrer">this article</a>, and more specifically I'm trying to derive the equation that would explain the implementation the following shader (still in the same article):</p>

<pre><code>#version 330 core
out vec4 FragColor;
in vec3 localPos;

uniform samplerCube environmentMap;
uniform float roughness;

const float PI = 3.14159265359;

float RadicalInverse_VdC(uint bits);
vec2 Hammersley(uint i, uint N);
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness);

void main()
{       
    vec3 N = normalize(localPos);    
    vec3 R = N;
    vec3 V = R;

    const uint SAMPLE_COUNT = 1024u;
    float totalWeight = 0.0;   
    vec3 prefilteredColor = vec3(0.0);     
    for(uint i = 0u; i &lt; SAMPLE_COUNT; ++i)
    {
        vec2 Xi = Hammersley(i, SAMPLE_COUNT);
        vec3 H  = ImportanceSampleGGX(Xi, N, roughness);
        vec3 L  = normalize(2.0 * dot(V, H) * H - V);

        float NdotL = max(dot(N, L), 0.0);
        if(NdotL &gt; 0.0)
        {
            prefilteredColor += texture(environmentMap, L).rgb * NdotL;
            totalWeight      += NdotL;
        }
    }
    prefilteredColor = prefilteredColor / totalWeight;

    FragColor = vec4(prefilteredColor, 1.0);
}  
</code></pre>

<p>Which is my understanding suppose to implement the computation of the integral</p>

<p><span class="math-container">$$
I = \int_{\Omega} L(\omega_i)d\omega_i
$$</span></p>

<p>However I'm not entirely sure since <code>NdotL</code> is also used in the computation so I might be wrong.</p>

<p>It seems to me the idea is given <span class="math-container">$N$</span> to sample a random halfway vector <span class="math-container">$H$</span>, and based on this we can construct, by reflection, the light direction vector <span class="math-container">$L$</span>, which would be random as well by construction. The article also mentions that <span class="math-container">$H$</span> is sampled from a normal distribution.</p>

<p>But anyway suppose I have samples <span class="math-container">$H^{1} ,\ldots, H^{N}$</span> and therefore <span class="math-container">$L^{1},\ldots, L^{N}$</span> samples, the latter I suppose would define <span class="math-container">$\omega_{i}^{1} \ldots, \omega_{i}^{N}$</span> (solid angles).</p>

<p>By importance sampling </p>

<p><span class="math-container">$$
I \approx \frac{1}{N} \sum_{j=1}^{N} \frac{L(\omega_i^{j})}{pdf(\omega_i^{j})} \;\;\;\; (1)
$$</span></p>

<p>If what I wrote is correct than I don't know where the dot product and the normalization factor</p>

<p><span class="math-container">$$
W = \sum_{j=1}^{N} N\cdot L^{j}
$$</span></p>

<p>comes from, namely how do I go from <span class="math-container">$(1)$</span> to</p>

<p><span class="math-container">$$
I \approx 
\frac{\sum_{j=1}^{N}L(\omega_i^{j}) N \cdot L^{j}}
{\sum_{j=1}^{N} N \cdot L^{j}}
$$</span></p>

<p><strong>Update</strong>: I'm pretty sure many of you know this already, but the shader above is for a pre-filtered environment map. Which means in this context the actual integral should be given by</p>

<p><span class="math-container">$$
I(N) = \int_{\Omega} L(\omega_i) N \cdot L d\omega
$$</span></p>

<p>This explains the factor <span class="math-container">$N \cdot L$</span> in the shader, the distribution function used is the GGX distribution, I assume plugging this stuff together might give me the formula.</p>

<p>Just updating because it might give a better clue.</p>

CC BY-SA 4.0
2019-05-24T22:15:54.390Z
Looks wrong honestly, you cannot get to (1) by importance sampling in any sane manner that I can think of. They are using ggx sampling and do not divide by the pdf, but rather by some sum. Now if they are using a biased estimator of some form, then that's another matter, but I do not believe this was mentioned in the article. I am inclined to believe it's just wrong, try contacting the author.
lightxbulb
CC BY-SA 4.0
2019-05-24T22:27:16.127Z
They do mention in the article they divide on purpose for the total sum though.
user8469759
CC BY-SA 4.0
2019-05-24T22:28:07.873Z
Also if you, like me, think it's wrong... What would be the right montecarlo estimator then?
user8469759
CC BY-SA 4.0
2019-05-24T22:57:52.483Z
The shader is a cut and paste of the one shown at page 6 here: https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf .
user8469759
CC BY-SA 4.0
2019-05-25T04:42:24.577Z
"As shown in the code below, we have found weighting by coslk achieves better results1. 1This weighting is not present in Equation 7, which is left in a simpler form" - from the article you linked. They have not provided a reasoning beyond "achieves better results". Or at least I cannot find the part where they formally motivate this.
lightxbulb
CC BY-SA 4.0
2019-05-25T04:51:31.330Z
As for the correct estimator (not split sum) and code, you can find it just above the copy pasted part in the self shadow article you linked, in the Image based lighting section. Note that what they are estimating is not even  L weighted by some cosine term, since they do not divide by the GGX's importance sampling pdf, then it's implicitly in the estimated integral.
lightxbulb
CC BY-SA 4.0
2019-05-26T12:25:47.520Z
I meant the "correct estimator" for the factor in question in the split and sum.
user8469759
CC BY-SA 4.0
2019-05-27T07:41:21.290Z
It's also in the article, you can see it where they split the sums, they just don't write code for it.
lightxbulb
CC BY-SA 4.0
2019-05-29T10:20:25.930Z
Well anyway, I'd really like to get in touch with the author of that shader, but I can't find any e-mail address. I'm not either sure that was actually published in some scientific paper.
user8469759
CC BY-SA 4.0
2019-05-30T10:56:59.407Z
Don't think too hard about it. A large part of real-time techniques have no physical basis and were usually tweaked by hand. You can regard the weighting as some kind of biased estimator I believe, but I don't believe it will make much sense physically even if I write out the analytical formulation.
lightxbulb
CC BY-SA 4.0
2019-05-30T10:58:51.840Z
What do you mean with biased estimator?
user8469759
CC BY-SA 4.0
2019-05-31T17:04:24.177Z
An estimator with non-zero bias. Look up bias of an estimator, it's a math term.
lightxbulb
<algorithm><lighting><mathematics><importance-sampling>
Pre-filtered environment map, deriving the equation
user8469759
# Pre-filtered environment map, deriving the equation

(Asked by: username_0 on 2019-05-16)

I'm reading through [this article](https://learnopengl.com/PBR/IBL/Specular-IBL), and more specifically I'm trying to derive the equation that would explain the implementation the following shader (still in the same article):

```
#version 330 core
out vec4 FragColor;
in vec3 localPos;

uniform samplerCube environmentMap;
uniform float roughness;

const float PI = 3.14159265359;

float RadicalInverse_VdC(uint bits);
vec2 Hammersley(uint i, uint N);
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness);

void main()
{       
    vec3 N = normalize(localPos);    
    vec3 R = N;
    vec3 V = R;

    const uint SAMPLE_COUNT = 1024u;
    float totalWeight = 0.0;   
    vec3 prefilteredColor = vec3(0.0);     
    for(uint i = 0u; i < SAMPLE_COUNT; ++i)
    {
        vec2 Xi = Hammersley(i, SAMPLE_COUNT);
        vec3 H  = ImportanceSampleGGX(Xi, N, roughness);
        vec3 L  = normalize(2.0 * dot(V, H) * H - V);

        float NdotL = max(dot(N, L), 0.0);
        if(NdotL > 0.0)
        {
            prefilteredColor += texture(environmentMap, L).rgb * NdotL;
            totalWeight      += NdotL;
        }
    }
    prefilteredColor = prefilteredColor / totalWeight;

    FragColor = vec4(prefilteredColor, 1.0);
}  

```

Which is my understanding suppose to implement the computation of the integral

$$
I = \int\_{\Omega} L(\omega\_i)d\omega\_i
$$

However I'm not entirely sure since `NdotL` is also used in the computation so I might be wrong.

It seems to me the idea is given $N$ to sample a random halfway vector $H$, and based on this we can construct, by reflection, the light direction vector $L$, which would be random as well by construction. The article also mentions that $H$ is sampled from a normal distribution.

But anyway suppose I have samples $H^{1} ,\ldots, H^{N}$ and therefore $L^{1},\ldots, L^{N}$ samples, the latter I suppose would define $\omega\_{i}^{1} \ldots, \omega\_{i}^{N}$ (solid angles).

By importance sampling

$$
I \approx \frac{1}{N} \sum\_{j=1}^{N} \frac{L(\omega\_i^{j})}{pdf(\omega\_i^{j})} \;\;\;\; (1)
$$

If what I wrote is correct than I don't know where the dot product and the normalization factor

$$
W = \sum\_{j=1}^{N} N\cdot L^{j}
$$

comes from, namely how do I go from $(1)$ to

$$
I \approx
\frac{\sum\_{j=1}^{N}L(\omega\_i^{j}) N \cdot L^{j}}
{\sum\_{j=1}^{N} N \cdot L^{j}}
$$

**Update**: I'm pretty sure many of you know this already, but the shader above is for a pre-filtered environment map. Which means in this context the actual integral should be given by

$$
I(N) = \int\_{\Omega} L(\omega\_i) N \cdot L d\omega
$$

This explains the factor $N \cdot L$ in the shader, the distribution function used is the GGX distribution, I assume plugging this stuff together might give me the formula.

Just updating because it might give a better clue.

**Tags:** algorithm, lighting, mathematics, importance-sampling

> **Comments:**
> **username_1**: Looks wrong honestly, you cannot get to (1) by importance sampling in any sane manner that I can think of. They are using ggx sampling and do not divide by the pdf, but rather by some sum. Now if they are using a biased estimator of some form, then that's another matter, but I do not believe this was mentioned in the article. I am inclined to believe it's just wrong, try contacting the author.  
> **username_0**: They do mention in the article they divide on purpose for the total sum though.  
> **username_0**: Also if you, like me, think it's wrong... What would be the right montecarlo estimator then?  
> **username_0**: The shader is a cut and paste of the one shown at page 6 here: https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf .  
> **username_1**: "As shown in the code below, we have found weighting by coslk achieves better results1. 1This weighting is not present in Equation 7, which is left in a simpler form" - from the article you linked. They have not provided a reasoning beyond "achieves better results". Or at least I cannot find the part where they formally motivate this.  
> **username_1**: As for the correct estimator (not split sum) and code, you can find it just above the copy pasted part in the self shadow article you linked, in the Image based lighting section. Note that what they are estimating is not even  L weighted by some cosine term, since they do not divide by the GGX's importance sampling pdf, then it's implicitly in the estimated integral.  
> **username_0**: I meant the "correct estimator" for the factor in question in the split and sum.  
> **username_1**: It's also in the article, you can see it where they split the sums, they just don't write code for it.  
> **username_0**: Well anyway, I'd really like to get in touch with the author of that shader, but I can't find any e-mail address. I'm not either sure that was actually published in some scientific paper.  
> **username_1**: Don't think too hard about it. A large part of real-time techniques have no physical basis and were usually tweaked by hand. You can regard the weighting as some kind of biased estimator I believe, but I don't believe it will make much sense physically even if I write out the analytical formulation.  
> **username_0**: What do you mean with biased estimator?  
> **username_1**: An estimator with non-zero bias. Look up bias of an estimator, it's a math term.  

---

## 0 answers

