<p>I'm trying to complete a look-up table for an energy-conserving variation of microfacet GGX as implemented here: <a href="https://patapom.com/blog/BRDF/MSBRDFEnergyCompensation/" rel="nofollow noreferrer">https://patapom.com/blog/BRDF/MSBRDFEnergyCompensation/</a></p>

<p>I have a (pretty standard) GGX form of the microfacet equation and my white furnace test behaves similar to what is shown elsewhere (i.e., it loses energy as roughness increases).</p>

<p>However, when I attempt to integrate the brdf and store the total energy in a texture, I get results that are inverse to my expectation - higher roughness yields more total energy in the integral. Some code below (this is done in a compute shader):</p>

<pre><code>float evalSum = 0.0;
const float theta_i = 0.05;
const float phi_i = 0.05;
for (float phiWi = 0.0; phiWi &lt; PI2; phiWi += phi_i)
{
    for (float NoL = 0.0; NoL &lt; 1.0; NoL += theta_i)
    {
        float nohA = 1.0 + NoL * NoV + (1.0 - NoV * NoV) * (1.0 - NoL * NoL) * cos(phiWi);
        float NoH = (NoL + NoV) / sqrt(2.0 * nohA);

        float D = Fs.eNDF(NoH, roughness);
        float G = Fs.eGS(NoV, NoL, roughness);
        float Fr = D * G;

        evalSum += Fr * NoL;
    }   
}

outBuf[idx] = evalSum * phi_i * theta_i;
</code></pre>

<p>Here is my texture output:
<a href="https://i.sstatic.net/Oi3iT.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Oi3iT.png" alt="LUT"></a></p>

<p>I'm expecting something more like this:
<a href="https://i.sstatic.net/SvxNN.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/SvxNN.png" alt="energycomp"></a></p>

<p>As the Y axis goes down, roughness increases, and as the X axis goes to the right, <code>NoV</code> (N dot V) increases. Total energy increases with roughness and I also get a strange valley to the energy which I wasn't expecting.</p>

<p>Here's the two GGX terms:</p>

<pre><code>float getNDF(const float NoH, float linearRoughness)
{
    float a2 = linearRoughness * linearRoughness;
    float b = NoH * NoH * (a2 - 1.0) + 1.0;

    return a2 / (PI * (b * b));
}

float getGS(const float NoV, const float NoL, const float linearRoughness)
{
    float a2 = linearRoughness * linearRoughness;
    float G_V = NoV + sqrt((NoV - NoV * a2) * NoV + a2);
    float G_L = NoL + sqrt((NoL - NoL * a2) * NoL + a2);
    return rcp(G_V * G_L);
}
</code></pre>

<p>Pretty stumped here. I must be doing the integral wrong somehow because the in-engine renders look correct - the brdf code seems straightforward. Any ideas on why my LUT is not producing the expected result?</p>

CC BY-SA 4.0
2019-05-14T08:51:58.753Z
I probably won't find the answer, I find your abbreviations a bit hard to read. However, I noitced you calculating `float Fr = D * G;` but never using it. Perhaps you forgot something?
Tare
CC BY-SA 4.0
2019-05-15T01:11:11.910Z
Thanks Tare, that's just an artifact of me trying to debug the code. I'll edit the post.
polyrhythm
CC BY-SA 4.0
2019-05-15T15:40:06.743Z
@polyrhythm I second that, just because dolt researchers like to use abhorrent abbreviations doesn't mean *you* have to.   There's honestly no reason you can't name things properly here.  Your names are misleading as well, NoL to me would have translated to "NormalOfLight" not "N dot L", regardless *I would have just named it what it was* (and no, N dot L is not an appropriate name, what is N? What is L?, what does the combination of the two represent? That's how you name these things.
Krupip
CC BY-SA 4.0
2019-05-16T01:22:08.347Z
Thanks for your comment! I think my abbreviations are pretty industry-standard, though. A quick google search turns up a ton of high quality codebases using similar nomenclature, here is an example: https://github.com/google/filament/blob/master/shaders/src/brdf.fs

I have never seen `NoL` to mean "normal of light"...
polyrhythm
<brdf><microfacet>
Microfacet GGX not integrating as expected
polyrhythm
# Microfacet GGX not integrating as expected

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

I'm trying to complete a look-up table for an energy-conserving variation of microfacet GGX as implemented here: <https://patapom.com/blog/BRDF/MSBRDFEnergyCompensation/>

I have a (pretty standard) GGX form of the microfacet equation and my white furnace test behaves similar to what is shown elsewhere (i.e., it loses energy as roughness increases).

However, when I attempt to integrate the brdf and store the total energy in a texture, I get results that are inverse to my expectation - higher roughness yields more total energy in the integral. Some code below (this is done in a compute shader):

```
float evalSum = 0.0;
const float theta_i = 0.05;
const float phi_i = 0.05;
for (float phiWi = 0.0; phiWi < PI2; phiWi += phi_i)
{
    for (float NoL = 0.0; NoL < 1.0; NoL += theta_i)
    {
        float nohA = 1.0 + NoL * NoV + (1.0 - NoV * NoV) * (1.0 - NoL * NoL) * cos(phiWi);
        float NoH = (NoL + NoV) / sqrt(2.0 * nohA);

        float D = Fs.eNDF(NoH, roughness);
        float G = Fs.eGS(NoV, NoL, roughness);
        float Fr = D * G;

        evalSum += Fr * NoL;
    }   
}

outBuf[idx] = evalSum * phi_i * theta_i;

```

Here is my texture output:
[![LUT](https://i.sstatic.net/Oi3iT.png)](https://i.sstatic.net/Oi3iT.png)

I'm expecting something more like this:
[![energycomp](https://i.sstatic.net/SvxNN.png)](https://i.sstatic.net/SvxNN.png)

As the Y axis goes down, roughness increases, and as the X axis goes to the right, `NoV` (N dot V) increases. Total energy increases with roughness and I also get a strange valley to the energy which I wasn't expecting.

Here's the two GGX terms:

```
float getNDF(const float NoH, float linearRoughness)
{
    float a2 = linearRoughness * linearRoughness;
    float b = NoH * NoH * (a2 - 1.0) + 1.0;

    return a2 / (PI * (b * b));
}

float getGS(const float NoV, const float NoL, const float linearRoughness)
{
    float a2 = linearRoughness * linearRoughness;
    float G_V = NoV + sqrt((NoV - NoV * a2) * NoV + a2);
    float G_L = NoL + sqrt((NoL - NoL * a2) * NoL + a2);
    return rcp(G_V * G_L);
}

```

Pretty stumped here. I must be doing the integral wrong somehow because the in-engine renders look correct - the brdf code seems straightforward. Any ideas on why my LUT is not producing the expected result?

**Tags:** brdf, microfacet

> **Comments:**
> **username_1**: I probably won't find the answer, I find your abbreviations a bit hard to read. However, I noitced you calculating `float Fr = D * G;` but never using it. Perhaps you forgot something?  
> **username_0**: Thanks username_1, that's just an artifact of me trying to debug the code. I'll edit the post.  
> **username_2**: @username_0 I second that, just because dolt researchers like to use abhorrent abbreviations doesn't mean *you* have to.   There's honestly no reason you can't name things properly here.  Your names are misleading as well, NoL to me would have translated to "NormalOfLight" not "N dot L", regardless *I would have just named it what it was* (and no, N dot L is not an appropriate name, what is N? What is L?, what does the combination of the two represent? That's how you name these things.  
> **username_0**: Thanks for your comment! I think my abbreviations are pretty industry-standard, though. A quick google search turns up a ton of high quality codebases using similar nomenclature, here is an example: https://github.com/google/filament/blob/master/shaders/src/brdf.fs  I have never seen `NoL` to mean "normal of light"...  

---

## 0 answers

