<blockquote>
<p>1)What is the V vector? How did they compute that</p>
</blockquote>
<p>It's the vector toward the camera (view vector), i.e. direction of the reflected ray. The lookup table they're building is parameterized in terms of NdotV, so they are working backward from NdotV to obtain a corresponding V vector. For purposes of doing this integration it doesn't matter what N and V are exactly, just that they have the correct NdotV. So, just to make things concrete, they assume that <span class="math-container">$N = (0,0,1)$</span> and V is aligned with the positive x-axis (i.e. in the positive xz half-plane). Then you have <span class="math-container">$V = (\sin θ, 0, \cos θ)$</span> where θ is the angle from N to V (this is just the equation for a circular arc from z down to x). Now <span class="math-container">$N \cdot V = \cos θ$</span>, so by a standard trig identity <span class="math-container">$\sin θ = \sqrt{1 - \cos^2 θ} = \sqrt{1 - (N \cdot V)^2}$</span>.</p>
<blockquote>
<p>2)Why have they assumed N=(0,0,1)?</p>
</blockquote>
<p>This whole thing is a pre-integration of the BRDF alone, it doesn't depend on any scene or lighting environment. So it doesn't matter where the BRDF is or how it is oriented in space, only the relative orientation between the N, L, and V vectors is important. So just for the sake of convenience they have chosen to fix N = (0, 0, 1), let V vary only in the xz half-plane as mentioned above, and let L vary over the whole hemisphere. To put it another way, they have chosen to set the coordinate system to be aligned with N and V.</p>
<blockquote>
<p>3)why is NDotL=max(L.z,0)? How did they simplifying a dot product to an min/max Operation same question I have for NDotH</p>
</blockquote>
<p>Since N = (0, 0, 1), dotting N with any vector just takes the z component of that vector. <span class="math-container">$N \cdot L = 0L_x + 0L_y + 1L_z = L_z$</span>. (This is why it's convenient to assume a coordinate system in which N = (0, 0, 1).) Taking the max with 0 clamps it to the upper hemisphere, otherwise the dot product would go negative if the vector happens to be pointing below the hemisphere. This clamp is a standard thing to do when dealing with opaque BRDFs to avoid accidentally getting unwanted negative values in your calculations— although it is not really necessary here since they check <code>if (NdotL &gt; 0.0)</code> immediately afterward.</p>
<blockquote>
<p>4)G_Vis=GVDoth/(NDotHNDotL) why the division by (NDOTH*NDOTL)? that was nowhere in the equation.</p>
</blockquote>
<p>It is a standard part of the microfacet BRDF formulation:
<span class="math-container">$$
f_r(p, w_i, w_o) = \frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}
$$</span>
Note that <span class="math-container">$\omega_o = V$</span>, and <span class="math-container">$\omega_i = L$</span>, these are just different notations/names for the incoming and outgoing light vectors.
However I think there is a typo in the code, the denominator should contain NdotV rather than NdotH. I am also not sure why there is a multiplication by VdotH in the numerator, or where the factor of 4 went, but perhaps they have accounted for it elsewhere. I would probably double-check the BRDF equations here against some other sources as I don't think it's entirely correct.</p>
<blockquote>
<p>5)what is vector L? it looks like they have reflected vector V about H to get this but why?</p>
</blockquote>
<p>As noted, L is the vector toward the incoming light. H is the &quot;half-angle&quot; vector exactly halfway between L and V, so reflecting V around H will give you L, or vice versa. The significance of H is that in microfacet BRDFs, it is the normal vector of those microfacets that are &quot;active&quot; for a given L and V. So, to importance-sample a BRDF, we sample a random normal vector from the NDF, and use that as H. Since H and V are specified, we then calculate L from those.</p>

CC BY-SA 4.0
2021-04-04T18:49:48.140Z
2021-04-04T18:49:48.140Z
Nathan Reed
<p><strong>I recommend to ignore my post (however I consider papers that I've sent valueable) and read post of Nathan Reed, which is much better in explaining this problem!</strong></p>
<p>I'm still a junior when it comes to computer graphics so you may want to take my opinion with a grain of salt:</p>
<p>To start with - I used to learn/implement stuff using website that you've sent (OpenGL) and I don't recommend that. After few months of learning I knew barely anything. Then I start reading original papers and implementing them on my own to better understand PBR, what N * G * F means in Cook-Torrance shading model and I got much better understanding of basics. I was recommend by many graphics programmers to avoid tutorial pages and straight read and implement papers. In case if you don't understand something in the paper you're reading, you found paper on subject that you don't understand and read about it.</p>
<p>1). As I said - avoid this site or use only to get interesting papers - here are original notes from [Karis2013] UE4 presentation - <a href="https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf" rel="nofollow noreferrer">https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf</a> ; Please notice comment &quot;/sin&quot; &quot;/cos&quot; in listing at page 7 and usage of <em>Pythagorean trigonometric identity</em>. Maybe it's position on the hemishpere, I don't really want to dig in, I'm sorry. But I would recommend checking Epic Games repository on Github if you want to see how they're using it.</p>
<p>2.) In the same paper [Karis2013] there is listing at the page 4. and function <strong>ImportanceSampleGGX</strong>. It uses N to determine orientation of the world and returns either float3(0,0,1) or float3(1,0,0) based on N.z value.</p>
<p>3).
<span class="math-container">$$N = (0, 0, 1)$$</span>
<span class="math-container">$$L = (x, y, z)$$</span>
<span class="math-container">$$ dot(N, L) = (0 * x, 0 * y, 1 * z) = (0, 0, z) = L.z$$</span></p>
<p>4).
<a href="http://jcgt.org/published/0003/02/03/paper.pdf#page=30" rel="nofollow noreferrer">http://jcgt.org/published/0003/02/03/paper.pdf#page=30</a></p>
<p><a href="http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html" rel="nofollow noreferrer">http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html</a></p>
<p><a href="https://www.microsoft.com/en-us/research/wp-content/uploads/1977/01/p192-blinn.pdf" rel="nofollow noreferrer">https://www.microsoft.com/en-us/research/wp-content/uploads/1977/01/p192-blinn.pdf</a></p>
<p>These links might be helpful to understand BRDF better. Why there are strange division? I don't know, it's probably due to optimization, I don't know what NDF is being used. However, what happens here is you're multiplying D and G component, so you can do split multiplication with Fresnel. It doesn't matter how you write it. You can just create function NDF_GGX(...) and multiply it by G, add pdf and it'll work the same.
You can take a look at modern UE4 code - <a href="https://github.com/EpicGames/UnrealEngine/blob/2bf1a5b83a7076a0fd275887b373f8ec9e99d431/Engine/Shaders/Private/AmbientCubemapComposite.usf#L255" rel="nofollow noreferrer">https://github.com/EpicGames/UnrealEngine/blob/2bf1a5b83a7076a0fd275887b373f8ec9e99d431/Engine/Shaders/Private/AmbientCubemapComposite.usf#L255</a> to understand it better. That's why I'm saying to write your own code. I would say that [Karis2013] is omitting a lot of code and uses many optimizations without saying WHY.</p>
<p>5). It's just light direction. When you already calculated V and H, it is easy to get L by using reflection. Take a look at the picture here - <a href="https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model#Description" rel="nofollow noreferrer">https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model#Description</a></p>

CC BY-SA 4.0
2021-04-01T18:42:11.127Z
2021-04-05T11:01:01.613Z
2021-04-05T11:01:01.613Z
DirectX_Programmer
<p>As for question 4, i am also confused when i read the same article, after googling, i find this article well explained <a href="https://schuttejoe.github.io/post/ggximportancesamplingpart1/" rel="nofollow noreferrer">Importance Sampling techniques for GGX</a></p>

CC BY-SA 4.0
2021-12-31T15:40:25.480Z
Please do not post "link-only" answers. The Link might expire in the future rendering your answer useless to others. If you have the time, summarize the key statements of your source and keep the link as further reference.
wychmaster
CC BY-SA 4.0
2021-12-27T03:26:30.863Z
2021-12-27T03:26:30.863Z
leolu
<p><a href="https://learnopengl.com/PBR/IBL/Specular-IBL" rel="nofollow noreferrer">This</a> is the website I am learning from.</p>
<p>In the specular part of IBL this is the split sum approximation</p>
<p><a href="https://i.sstatic.net/YhB0C.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/YhB0C.jpg" alt="enter image description here" /></a></p>
<p>Now the left part of the equation I have asked in  <a href="https://computergraphics.stackexchange.com/questions/10659/pbr-understanding-importance-sampling/10663#10663">This</a> post and I have understood everything now this question is about the right part.</p>
<p>On simplifying the right part of the equation with the procedure shown in the website we get this</p>
<p><a href="https://i.sstatic.net/WiOBt.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/WiOBt.jpg" alt="enter image description here" /></a></p>
<p>And on translating this to code we get this</p>
<p><a href="https://i.sstatic.net/zb0ZG.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/zb0ZG.jpg" alt="enter image description here" /></a></p>
<p>I have so many questions about this code.</p>
<p>1)What is the V vector? How did they compute that</p>
<p>2)Why have they assumed N=(0,0,1)?</p>
<p>3)why is NDotL=max(L.z,0)? How did they simplifying a dot product to an min/max Operation same question I have for NDotH</p>
<p>4)G_Vis=G<em>VDoth/(NDotH</em>NDotL) why the division by (NDOTH*NDOTL)? that was nowhere in the equation.</p>
<p>5)what is vector L? it looks like they have reflected vector V about H to get this but why?</p>
<p>These are just some of the questions I have come up with so far but if there are any other important parts I should not know about A general explanation on how they derived this code would be appreciated</p>

<pbr><specular><integral><ibl>
PBR : Understanding the right part of Split sum integration of specular IBL
Sync it
# PBR : Understanding the right part of Split sum integration of specular IBL

(Asked by: username_0 on 2021-03-31)

[This](https://learnopengl.com/PBR/IBL/Specular-IBL) is the website I am learning from.

In the specular part of IBL this is the split sum approximation

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

Now the left part of the equation I have asked in [This](https://computergraphics.stackexchange.com/questions/10659/pbr-understanding-importance-sampling/10663#10663) post and I have understood everything now this question is about the right part.

On simplifying the right part of the equation with the procedure shown in the website we get this

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

And on translating this to code we get this

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

I have so many questions about this code.

1)What is the V vector? How did they compute that

2)Why have they assumed N=(0,0,1)?

3)why is NDotL=max(L.z,0)? How did they simplifying a dot product to an min/max Operation same question I have for NDotH

4)G\_Vis=G*VDoth/(NDotH*NDotL) why the division by (NDOTH\*NDOTL)? that was nowhere in the equation.

5)what is vector L? it looks like they have reflected vector V about H to get this but why?

These are just some of the questions I have come up with so far but if there are any other important parts I should not know about A general explanation on how they derived this code would be appreciated

**Tags:** pbr, specular, integral, ibl


---

## 3 answers

### Answer by username_1 on 2021-04-04. Score: 3 | Accepted answer

> 1)What is the V vector? How did they compute that

It's the vector toward the camera (view vector), i.e. direction of the reflected ray. The lookup table they're building is parameterized in terms of NdotV, so they are working backward from NdotV to obtain a corresponding V vector. For purposes of doing this integration it doesn't matter what N and V are exactly, just that they have the correct NdotV. So, just to make things concrete, they assume that $N = (0,0,1)$ and V is aligned with the positive x-axis (i.e. in the positive xz half-plane). Then you have $V = (\sin θ, 0, \cos θ)$ where θ is the angle from N to V (this is just the equation for a circular arc from z down to x). Now $N \cdot V = \cos θ$, so by a standard trig identity $\sin θ = \sqrt{1 - \cos^2 θ} = \sqrt{1 - (N \cdot V)^2}$.

> 2)Why have they assumed N=(0,0,1)?

This whole thing is a pre-integration of the BRDF alone, it doesn't depend on any scene or lighting environment. So it doesn't matter where the BRDF is or how it is oriented in space, only the relative orientation between the N, L, and V vectors is important. So just for the sake of convenience they have chosen to fix N = (0, 0, 1), let V vary only in the xz half-plane as mentioned above, and let L vary over the whole hemisphere. To put it another way, they have chosen to set the coordinate system to be aligned with N and V.

> 3)why is NDotL=max(L.z,0)? How did they simplifying a dot product to an min/max Operation same question I have for NDotH

Since N = (0, 0, 1), dotting N with any vector just takes the z component of that vector. $N \cdot L = 0L\_x + 0L\_y + 1L\_z = L\_z$. (This is why it's convenient to assume a coordinate system in which N = (0, 0, 1).) Taking the max with 0 clamps it to the upper hemisphere, otherwise the dot product would go negative if the vector happens to be pointing below the hemisphere. This clamp is a standard thing to do when dealing with opaque BRDFs to avoid accidentally getting unwanted negative values in your calculations— although it is not really necessary here since they check `if (NdotL > 0.0)` immediately afterward.

> 4)G\_Vis=GVDoth/(NDotHNDotL) why the division by (NDOTH\*NDOTL)? that was nowhere in the equation.

It is a standard part of the microfacet BRDF formulation:
$$
f\_r(p, w\_i, w\_o) = \frac{DFG}{4(\omega\_o \cdot n)(\omega\_i \cdot n)}
$$
Note that $\omega\_o = V$, and $\omega\_i = L$, these are just different notations/names for the incoming and outgoing light vectors.
However I think there is a typo in the code, the denominator should contain NdotV rather than NdotH. I am also not sure why there is a multiplication by VdotH in the numerator, or where the factor of 4 went, but perhaps they have accounted for it elsewhere. I would probably double-check the BRDF equations here against some other sources as I don't think it's entirely correct.

> 5)what is vector L? it looks like they have reflected vector V about H to get this but why?

As noted, L is the vector toward the incoming light. H is the "half-angle" vector exactly halfway between L and V, so reflecting V around H will give you L, or vice versa. The significance of H is that in microfacet BRDFs, it is the normal vector of those microfacets that are "active" for a given L and V. So, to importance-sample a BRDF, we sample a random normal vector from the NDF, and use that as H. Since H and V are specified, we then calculate L from those.


---

### Answer by username_2 on 2021-04-01. Score: 1

**I recommend to ignore my post (however I consider papers that I've sent valueable) and read post of username_1 username_1, which is much better in explaining this problem!**

I'm still a junior when it comes to computer graphics so you may want to take my opinion with a grain of salt:

To start with - I used to learn/implement stuff using website that you've sent (OpenGL) and I don't recommend that. After few months of learning I knew barely anything. Then I start reading original papers and implementing them on my own to better understand PBR, what N \* G \* F means in Cook-Torrance shading model and I got much better understanding of basics. I was recommend by many graphics programmers to avoid tutorial pages and straight read and implement papers. In case if you don't understand something in the paper you're reading, you found paper on subject that you don't understand and read about it.

1). As I said - avoid this site or use only to get interesting papers - here are original notes from [Karis2013] UE4 presentation - <https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf> ; Please notice comment "/sin" "/cos" in listing at page 7 and usage of *Pythagorean trigonometric identity*. Maybe it's position on the hemishpere, I don't really want to dig in, I'm sorry. But I would recommend checking Epic Games repository on Github if you want to see how they're using it.

2.) In the same paper [Karis2013] there is listing at the page 4. and function **ImportanceSampleGGX**. It uses N to determine orientation of the world and returns either float3(0,0,1) or float3(1,0,0) based on N.z value.

3).
$$N = (0, 0, 1)$$
$$L = (x, y, z)$$
$$ dot(N, L) = (0 \* x, 0 \* y, 1 \* z) = (0, 0, z) = L.z$$

4).
<http://jcgt.org/published/0003/02/03/paper.pdf#page=30>

<http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html>

<https://www.microsoft.com/en-us/research/wp-content/uploads/1977/01/p192-blinn.pdf>

These links might be helpful to understand BRDF better. Why there are strange division? I don't know, it's probably due to optimization, I don't know what NDF is being used. However, what happens here is you're multiplying D and G component, so you can do split multiplication with Fresnel. It doesn't matter how you write it. You can just create function NDF\_GGX(...) and multiply it by G, add pdf and it'll work the same.
You can take a look at modern UE4 code - <https://github.com/EpicGames/UnrealEngine/blob/2bf1a5b83a7076a0fd275887b373f8ec9e99d431/Engine/Shaders/Private/AmbientCubemapComposite.usf#L255> to understand it better. That's why I'm saying to write your own code. I would say that [Karis2013] is omitting a lot of code and uses many optimizations without saying WHY.

5). It's just light direction. When you already calculated V and H, it is easy to get L by using reflection. Take a look at the picture here - <https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model#Description>


---

### Answer by username_3 on 2021-12-27. Score: 0

As for question 4, i am also confused when i read the same article, after googling, i find this article well explained [Importance Sampling techniques for GGX](https://schuttejoe.github.io/post/ggximportancesamplingpart1/)

> **Comments:**
> **username_4**: Please do not post "link-only" answers. The Link might expire in the future rendering your answer useless to others. If you have the time, summarize the key statements of your source and keep the link as further reference.  

---

