<p>According to <a href="https://learnopengl.com/PBR/Theory" rel="nofollow noreferrer">learnopengl.com</a>, the term <span class="math-container">$G(l, v, n)$</span> in the Cook-Torrance Specular BRDF can be written as</p>
<p><span class="math-container">$$
G=\frac{n \cdot v}{(n \cdot v)(1-k)+k} \cdot \frac{n \cdot l}{(n \cdot l)(1-k)+k}
$$</span></p>
<p>and this is the specular term of the Cook-Torrance BRDF</p>
<p><span class="math-container">$$
f=\frac{FGD}{4(n \cdot l)(n \cdot v)}
$$</span></p>
<p>we can see that both <span class="math-container">$f$</span> and <span class="math-container">$G$</span> have <span class="math-container">$n \cdot v$</span> and <span class="math-container">$n \cdot l$</span> terms that cancel each other out. When <span class="math-container">$n \cdot v$</span> becomes really small and approaches 0 we get a <span class="math-container">$0/0$</span> situation which is what causes artifacts at grazing angles due to floating point precision errors near 0.</p>
<h2>Solution</h2>
<p>The problem can be solved by canceling the terms <span class="math-container">$n \cdot v$</span> and <span class="math-container">$n \cdot l$</span> in <span class="math-container">$f$</span> and <span class="math-container">$G$</span>. The new specular Cook-Torrance BRDF becomes</p>
<p><span class="math-container">$$
f=\frac{FGD}{4}
$$</span></p>
<p>where</p>
<p><span class="math-container">$$
G=\frac{1}{(n \cdot v)(1-k)+k} \cdot \frac{1}{(n \cdot l)(1-k)+k}
$$</span></p>

CC BY-SA 4.0
2023-10-30T08:03:59.733Z
2023-10-30T08:03:59.733Z
TheCoder5550
<p>I am currently experiencing a very obvious artifact that occurs when looking at objects on very grazing angles</p>

<p>Here is a picture of the artifact:
<a href="https://i.sstatic.net/ZNQL3.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ZNQL3.png" alt="artifact"></a></p>

<p>I noticed that the issue was coming from my implementation of Cook-Torrance's Specular BRDF. </p>

<p>Here is the equation for the Cook-Torrance Specular BRDF: 
<a href="https://i.sstatic.net/0wcIZ.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/0wcIZ.jpg" alt="Cook-Torrance Specular BRDF"></a></p>

<p>More specifically, calculating the denominator is causing the issue:</p>

<pre><code>float denominator = 4 * max(dot(viewDir, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001;  // Prevents any division by zero
</code></pre>

<p>When I change the calculation of dot(viewDir, normal) to dot(halfway, normal), the artifact disappears:</p>

<pre><code>float denominator = 4 * max(dot(halfway, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001;  // Prevents any division by zero
</code></pre>

<p>But this equation is no longer correct. I was wondering if anyone knows why my implementation causes these artifacts?</p>

<p>If you want to see my fragment shader you can find the code here:</p>

<p><a href="https://github.com/Ershany/Arcane-Engine/blob/WIP_PBR/Arcane%20Engine%20Core/src/shaders/pbr_model.frag" rel="nofollow noreferrer">https://github.com/Ershany/Arcane-Engine/blob/WIP_PBR/Arcane%20Engine%20Core/src/shaders/pbr_model.frag</a></p>

<p>Thank you!</p>

CC BY-SA 4.0
2018-10-09T06:36:20.143Z
Have you tried calculating the TBN in the fragment shader? When calculating it in the vertex shader, OpenGL will linearly interpolate the matrix for use in the fragment shader and that might cause the artifacts. Do make sure that you normalize the tangent, bitangent and normal in the fragment shader before using them (again because of  the linear interpolation).
bram0101
CC BY-SA 4.0
2018-10-09T13:55:42.450Z
Yes I tried to do this in the fragment shader and normalized the vectors before, and I still get these strange artifacts
Brady Jessup
CC BY-SA 4.0
2018-10-10T14:34:14.327Z
Tangents are multiplied by the model matrix, as they dont suffer from non-uniform scale disortion as normal vector do. Also, you do need a vertex normal and a normal vector extracted from the normal map, however, I see you are applying the normalization (`normalize(normal * 2.0f - 1.0f)`) to the same vector you used to create the TBN matrix
Nadir
CC BY-SA 4.0
2018-10-10T16:51:49.270Z
I thought the tangents and bitangents would also suffer from possibly being non-orthogonal to each other if scaled non-uniformly. Also I edited my fragment shader code above to showcase that I am actually sampling the normal from the normal map. My bad!
Brady Jessup
CC BY-SA 4.0
2018-10-11T04:35:56.500Z
Have you identified which part of the code generates the color of the artifact? Have you tried to reduce your shader to a minimal reproduce case? I wouldn't be surprised if it was due to either a normal facing away from light, or a nearly 0 but negative parameter to a `pow()` function.
Julien Guertault
CC BY-SA 4.0
2018-11-08T20:29:52.047Z
@JulienGuertault I finally figured out where it was located. It is in my specular term of my BRDF. Now the question is, why is it causing this. And why does no one else run into these issues :)
Brady Jessup
CC BY-SA 4.0
2018-11-09T08:17:02.243Z
Are you using HDR? You might be burning the image by overflowing the colors
Nadir
CC BY-SA 4.0
2018-11-09T11:34:13.013Z
@Nadir Yes my render targets are using HDR. They are using RGBA16F
Brady Jessup
<brdf><specular><normal-mapping><artifacts>
Normal Artifacts On Grazing Angles
Brady Jessup
# Normal Artifacts On Grazing Angles

(Asked by: username_0 on 2018-10-09)

I am currently experiencing a very obvious artifact that occurs when looking at objects on very grazing angles

Here is a picture of the artifact:
[![artifact](https://i.sstatic.net/ZNQL3.png)](https://i.sstatic.net/ZNQL3.png)

I noticed that the issue was coming from my implementation of Cook-Torrance's Specular BRDF.

Here is the equation for the Cook-Torrance Specular BRDF:
[![Cook-Torrance Specular BRDF](https://i.sstatic.net/0wcIZ.jpg)](https://i.sstatic.net/0wcIZ.jpg)

More specifically, calculating the denominator is causing the issue:

```
float denominator = 4 * max(dot(viewDir, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001;  // Prevents any division by zero

```

When I change the calculation of dot(viewDir, normal) to dot(halfway, normal), the artifact disappears:

```
float denominator = 4 * max(dot(halfway, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001;  // Prevents any division by zero

```

But this equation is no longer correct. I was wondering if anyone knows why my implementation causes these artifacts?

If you want to see my fragment shader you can find the code here:

<https://github.com/Ershany/Arcane-Engine/blob/WIP_PBR/Arcane%20Engine%20Core/src/shaders/pbr_model.frag>

Thank you!

**Tags:** brdf, specular, normal-mapping, artifacts

> **Comments:**
> **username_1**: Have you tried calculating the TBN in the fragment shader? When calculating it in the vertex shader, OpenGL will linearly interpolate the matrix for use in the fragment shader and that might cause the artifacts. Do make sure that you normalize the tangent, bitangent and normal in the fragment shader before using them (again because of  the linear interpolation).  
> **username_0**: Yes I tried to do this in the fragment shader and normalized the vectors before, and I still get these strange artifacts  
> **username_2**: Tangents are multiplied by the model matrix, as they dont suffer from non-uniform scale disortion as normal vector do. Also, you do need a vertex normal and a normal vector extracted from the normal map, however, I see you are applying the normalization (`normalize(normal * 2.0f - 1.0f)`) to the same vector you used to create the TBN matrix  
> **username_0**: I thought the tangents and bitangents would also suffer from possibly being non-orthogonal to each other if scaled non-uniformly. Also I edited my fragment shader code above to showcase that I am actually sampling the normal from the normal map. My bad!  
> **username_3**: Have you identified which part of the code generates the color of the artifact? Have you tried to reduce your shader to a minimal reproduce case? I wouldn't be surprised if it was due to either a normal facing away from light, or a nearly 0 but negative parameter to a `pow()` function.  
> **username_0**: @username_3 I finally figured out where it was located. It is in my specular term of my BRDF. Now the question is, why is it causing this. And why does no one else run into these issues :)  
> **username_2**: Are you using HDR? You might be burning the image by overflowing the colors  
> **username_0**: @username_2 Yes my render targets are using HDR. They are using RGBA16F  

---

## 1 answers

### Answer by username_4 on 2023-10-30. Score: 1

According to [learnopengl.com](https://learnopengl.com/PBR/Theory), the term $G(l, v, n)$ in the Cook-Torrance Specular BRDF can be written as

$$
G=\frac{n \cdot v}{(n \cdot v)(1-k)+k} \cdot \frac{n \cdot l}{(n \cdot l)(1-k)+k}
$$

and this is the specular term of the Cook-Torrance BRDF

$$
f=\frac{FGD}{4(n \cdot l)(n \cdot v)}
$$

we can see that both $f$ and $G$ have $n \cdot v$ and $n \cdot l$ terms that cancel each other out. When $n \cdot v$ becomes really small and approaches 0 we get a $0/0$ situation which is what causes artifacts at grazing angles due to floating point precision errors near 0.

## Solution

The problem can be solved by canceling the terms $n \cdot v$ and $n \cdot l$ in $f$ and $G$. The new specular Cook-Torrance BRDF becomes

$$
f=\frac{FGD}{4}
$$

where

$$
G=\frac{1}{(n \cdot v)(1-k)+k} \cdot \frac{1}{(n \cdot l)(1-k)+k}
$$


---

