<p>I am implementing a GGX BRDF, this is the formula I used is from:<a href="https://schuttejoe.github.io/post/ggximportancesamplingpart1/" rel="nofollow noreferrer">https://schuttejoe.github.io/post/ggximportancesamplingpart1/</a>
<a href="https://i.sstatic.net/2rZhq.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/2rZhq.png" alt="enter image description here"></a></p>

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

<p>And this is my implementation:</p>

<pre><code>float BRDF(float3 viewDir, float roughness, float3 normal, float3 Li) {
            float3 halfDir = normalize(Li + viewDir);
            float nl = saturate(dot(normal, Li));
            float nh = saturate(dot(normal, halfDir));

            half lv = saturate(dot(Li, viewDir));
            half lh = saturate(dot(Li, halfDir));
            half nv = abs(dot(normal, viewDir));

            float a2 = roughness * roughness;
            float G2 = SmithGGXMaskingShadowing(nl, nv, a2);

            float D = GGX(nh, roughness);
            return G2 * D /(4 * abs(nv) * abs(nl));
        }


float SmithGGXMaskingShadowing(float NdotL, float NdotV, float a2)
        {

            float denomA = NdotV * sqrt(a2 + (1.0f - a2) * NdotL * NdotL);
            float denomB = NdotL * sqrt(a2 + (1.0f - a2) * NdotV * NdotV);

            return 2.0f * NdotL * NdotV / (denomA + denomB);
        }

float GGX(float NdotH, float a) {
            float a2 = sqr(a);
            return a2 / (UNITY_PI * sqr(sqr(NdotH) * (a2 - 1) + 1));
        }
</code></pre>

<p>I assume the fresnel term is constant: 1. However, I found that my BRDF sometimes give me number greater than 1.</p>

CC BY-SA 4.0
2019-03-07T07:44:29.337Z
Shouldn't the return value be a float3? Also, why do you assume fresnel to be constant 1? That would only be true for an incident angle of $90°$. Have a look at Natty Hoffman's Siggraph Physically Based Shading Course, he displays some Fresnel values plotted for different angles (p. 15) https://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf
Tare
CC BY-SA 4.0
2019-03-07T10:59:04.963Z
You are confusing brdf with probabilities.
https://gamedev.stackexchange.com/questions/62438/ggx-specular-brdf-is-way-over-1

https://www.gamedev.net/forums/topic/257668-brdf-range----greater-than-01-/
gallickgunner
CC BY-SA 4.0
2019-03-07T12:30:15.377Z
A brdf can be larger than $1$ and be energy conserving. Consider the ideal specular reflection/refraction brdf which can be considered to go to infinity at a single point. It's the integral of the brdf multiplied by the cosine for all directions that needs to be $\leq 1$.
lightxbulb
CC BY-SA 4.0
2019-03-07T15:07:28.020Z
Thank you very much. I understand now. If I do importance sampling on brdf, then my brdf/pdf can rescale my value back to [0,1] right? But if I do importance sampling on the light source, my brdf/pdf can still has some value greater than 1 because the pdf is the pdf of sampling my light source, not the pdf of sampling brdf. Am I correct?
TIANLUN ZHU
<brdf><pbr><ggx>
GGX BRDF is greater than 1?
TIANLUN ZHU
# GGX BRDF is greater than 1?

(Asked by: username_0 on 2019-03-07)

I am implementing a GGX BRDF, this is the formula I used is from:<https://schuttejoe.github.io/post/ggximportancesamplingpart1/>
[![enter image description here](https://i.sstatic.net/2rZhq.png)](https://i.sstatic.net/2rZhq.png)

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

And this is my implementation:

```
float BRDF(float3 viewDir, float roughness, float3 normal, float3 Li) {
            float3 halfDir = normalize(Li + viewDir);
            float nl = saturate(dot(normal, Li));
            float nh = saturate(dot(normal, halfDir));

            half lv = saturate(dot(Li, viewDir));
            half lh = saturate(dot(Li, halfDir));
            half nv = abs(dot(normal, viewDir));

            float a2 = roughness * roughness;
            float G2 = SmithGGXMaskingShadowing(nl, nv, a2);

            float D = GGX(nh, roughness);
            return G2 * D /(4 * abs(nv) * abs(nl));
        }

float SmithGGXMaskingShadowing(float NdotL, float NdotV, float a2)
        {

            float denomA = NdotV * sqrt(a2 + (1.0f - a2) * NdotL * NdotL);
            float denomB = NdotL * sqrt(a2 + (1.0f - a2) * NdotV * NdotV);

            return 2.0f * NdotL * NdotV / (denomA + denomB);
        }

float GGX(float NdotH, float a) {
            float a2 = sqr(a);
            return a2 / (UNITY_PI * sqr(sqr(NdotH) * (a2 - 1) + 1));
        }

```

I assume the fresnel term is constant: 1. However, I found that my BRDF sometimes give me number greater than 1.

**Tags:** brdf, pbr, ggx

> **Comments:**
> **username_1**: Shouldn't the return value be a float3? Also, why do you assume fresnel to be constant 1? That would only be true for an incident angle of $90°$. Have a look at Natty Hoffman's Siggraph Physically Based Shading Course, he displays some Fresnel values plotted for different angles (p. 15) https://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf  
> **username_2**: You are confusing brdf with probabilities. https://gamedev.stackexchange.com/questions/62438/ggx-specular-brdf-is-way-over-1  https://www.gamedev.net/forums/topic/257668-brdf-range----greater-than-01-/  
> **username_3**: A brdf can be larger than $1$ and be energy conserving. Consider the ideal specular reflection/refraction brdf which can be considered to go to infinity at a single point. It's the integral of the brdf multiplied by the cosine for all directions that needs to be $\leq 1$.  
> **username_0**: Thank you very much. I understand now. If I do importance sampling on brdf, then my brdf/pdf can rescale my value back to [0,1] right? But if I do importance sampling on the light source, my brdf/pdf can still has some value greater than 1 because the pdf is the pdf of sampling my light source, not the pdf of sampling brdf. Am I correct?  

---

## 0 answers

