<p>I am implementing a pathtracer with both indirect and direct light sampling at each intersection (I believe the &quot;direct light sampling&quot; part is also referred to as &quot;next event estimation&quot;). I am trying to compute both direct-diffuse and direct-specular contributions of the light sources.</p>
<p>For that, I use a normalized Phong BRDF (formula taken from <a href="http://www.farbrausch.de/%7Efg/stuff/phong.pdf" rel="nofollow noreferrer">here</a>), in which the contribution of each light source at an intersection is defined as (pseudo-code) :</p>
<pre><code>directLighting = diffuse() + specular() / (intersection.location - light.location).lengthSquared();


diffuse() {
    normalization = 1.0f / PI;
    return material.metal ? Color::BLACK :
                            lightDotN * lightIntensity * lightColor * material.albedo * normalization;
}


specular() {
    if (observerDotReflected &lt;= 0.0f) {
        return Color::BLACK;
    }

    normalization = (material.smoothness + 1.0f) / (2.0f * PI);
    return (observerDotReflected ^ material.smoothness) * lightIntensity * lightColor *
           (material.metal ? material.albedo : material.specularity) * normalization;
}
</code></pre>
<p>This works well as long as I have pretty rough objects in my scene (below, a rough metallic sphere with <code>smoothness = 25.0f</code>, and a rough diffuse sphere with <code>smoothness = 2.0f</code>).
<a href="https://i.sstatic.net/N4S8X.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/N4S8X.png" alt="clean" /></a></p>
<p>However, as soon as I introduce a very smooth and reflective object (below, a metallic sphere with <code>smoothness = 10'000.0f</code>), two problems appear : the specular lobe on the sphere is very ugly (we can see the individual points that resulted in non-zero specular contribution), and hot pixels/fireflies appear everywhere in the scene.
<a href="https://i.sstatic.net/ojuqM.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ojuqM.png" alt="fireflies" /></a></p>
<p>I think I understand why these exist : when the smoothness is high, the specular Phong BRDF returns ~0 almost all the time (when <code>observerDotReflected</code> is not very close to 1), but sometimes returns extremely bright values, which cause fireflies at other points in the scene when they are the result of an indirect bounce.</p>
<p>Note that the same effect appears whether I use point lights, or sphere lights (with a non-zero volume that I randomly sample).</p>
<p>Is there a conventional way to solve this problem ? I have seen <a href="https://computergraphics.stackexchange.com/a/5153/16243">this answer</a> where the author indicates that for mirror-like specular surfaces (i.e. smoothness -&gt; infinity), you should not directly sample specular lighting, but rather rely on indirect bounces intersecting light objects. Is this the only way to go about direct specular lighting ? Are there other solutions to this variance problem ?</p>

CC BY-SA 4.0
2021-04-26T01:41:48.700Z
What about multiple importance sampling (MIS)?
Hubble
CC BY-SA 4.0
2021-04-26T09:58:49.520Z
@Hubble I have read about MIS a few times in posts and articles, but it seemed like a very complicated and elaborate thing for me at the time. Do you by any chance have links to good resources for learning about it and implementing it ?
Ewaren
CC BY-SA 4.0
2021-04-26T14:12:06.037Z
You can look at [Section 13.10.1 of PBRT](https://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/Importance_Sampling). It's usually not too difficult to implement once you have a sampling strategy for your emitter and BRDF.
Hubble
CC BY-SA 4.0
2021-04-26T15:43:36.770Z
Thank you for the guidance. I have resorted to only computing direct-diffuse contributions for now, and handling specular contributions solely via indirect bounces, and it seems to work pretty well. I am having trouble sampling sphere lights and normalizing them properly however, but I will create another question for that.
Ewaren
CC BY-SA 4.0
2021-04-27T00:48:36.193Z
You could look into post-processing effects like median-filter to get rid of this noise. However do remember that this is just for displaying. https://research.dreamworks.com/wp-content/uploads/2018/08/fireflies-edited.pdf
gallickgunner
CC BY-SA 4.0
2021-04-27T14:38:24.273Z
The specular on the reflective material looks like its going into orbit numerically if that is the case then samples that randomly hit the specular highlight will not be valid and the fireflies are the result. I have seen this happen many times and my suggestion is to ignore the fireflies root cause the specular and the fireflies will take care of themselves. The main reason specular becomes numerically unstable is a division by a value near zero produces an large value that well out of range after the exponent call. you might try clamp(abs(observerDotReflected), 0.1,1.0) as a hack.
pmw1234
CC BY-SA 4.0
2021-04-27T20:40:45.040Z
@pmw1234 I have read about this trick of clamping the radiance value for specular reflections somewhere, but they mentioned it also introduces bias, which I'm not sure I want. As I said above, although a bit more complicated, I have found that sampling diffuse only via Next Event Estimation, and leaving specular for the naive path tracing contributions works pretty good.
Ewaren
<raytracing><pathtracing>
Path tracing : fireflies/hot pixels when directly sampling lights
Ewaren
# Path tracing : fireflies/hot pixels when directly sampling lights

(Asked by: username_0 on 2021-04-24)

I am implementing a pathtracer with both indirect and direct light sampling at each intersection (I believe the "direct light sampling" part is also referred to as "next event estimation"). I am trying to compute both direct-diffuse and direct-specular contributions of the light sources.

For that, I use a normalized Phong BRDF (formula taken from [here](http://www.farbrausch.de/%7Efg/stuff/phong.pdf)), in which the contribution of each light source at an intersection is defined as (pseudo-code) :

```
directLighting = diffuse() + specular() / (intersection.location - light.location).lengthSquared();

diffuse() {
    normalization = 1.0f / PI;
    return material.metal ? Color::BLACK :
                            lightDotN * lightIntensity * lightColor * material.albedo * normalization;
}

specular() {
    if (observerDotReflected <= 0.0f) {
        return Color::BLACK;
    }

    normalization = (material.smoothness + 1.0f) / (2.0f * PI);
    return (observerDotReflected ^ material.smoothness) * lightIntensity * lightColor *
           (material.metal ? material.albedo : material.specularity) * normalization;
}

```

This works well as long as I have pretty rough objects in my scene (below, a rough metallic sphere with `smoothness = 25.0f`, and a rough diffuse sphere with `smoothness = 2.0f`).
[![clean](https://i.sstatic.net/N4S8X.png)](https://i.sstatic.net/N4S8X.png)

However, as soon as I introduce a very smooth and reflective object (below, a metallic sphere with `smoothness = 10'000.0f`), two problems appear : the specular lobe on the sphere is very ugly (we can see the individual points that resulted in non-zero specular contribution), and hot pixels/fireflies appear everywhere in the scene.
[![fireflies](https://i.sstatic.net/ojuqM.png)](https://i.sstatic.net/ojuqM.png)

I think I understand why these exist : when the smoothness is high, the specular Phong BRDF returns ~0 almost all the time (when `observerDotReflected` is not very close to 1), but sometimes returns extremely bright values, which cause fireflies at other points in the scene when they are the result of an indirect bounce.

Note that the same effect appears whether I use point lights, or sphere lights (with a non-zero volume that I randomly sample).

Is there a conventional way to solve this problem ? I have seen [this answer](https://computergraphics.stackexchange.com/a/5153/16243) where the author indicates that for mirror-like specular surfaces (i.e. smoothness -> infinity), you should not directly sample specular lighting, but rather rely on indirect bounces intersecting light objects. Is this the only way to go about direct specular lighting ? Are there other solutions to this variance problem ?

**Tags:** raytracing, pathtracing

> **Comments:**
> **username_1**: What about multiple importance sampling (MIS)?  
> **username_0**: @username_1 I have read about MIS a few times in posts and articles, but it seemed like a very complicated and elaborate thing for me at the time. Do you by any chance have links to good resources for learning about it and implementing it ?  
> **username_1**: You can look at [Section 13.10.1 of PBRT](https://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/Importance_Sampling). It's usually not too difficult to implement once you have a sampling strategy for your emitter and BRDF.  
> **username_0**: Thank you for the guidance. I have resorted to only computing direct-diffuse contributions for now, and handling specular contributions solely via indirect bounces, and it seems to work pretty well. I am having trouble sampling sphere lights and normalizing them properly however, but I will create another question for that.  
> **username_2**: You could look into post-processing effects like median-filter to get rid of this noise. However do remember that this is just for displaying. https://research.dreamworks.com/wp-content/uploads/2018/08/fireflies-edited.pdf  
> **username_3**: The specular on the reflective material looks like its going into orbit numerically if that is the case then samples that randomly hit the specular highlight will not be valid and the fireflies are the result. I have seen this happen many times and my suggestion is to ignore the fireflies root cause the specular and the fireflies will take care of themselves. The main reason specular becomes numerically unstable is a division by a value near zero produces an large value that well out of range after the exponent call. you might try clamp(abs(observerDotReflected), 0.1,1.0) as a hack.  
> **username_0**: @username_3 I have read about this trick of clamping the radiance value for specular reflections somewhere, but they mentioned it also introduces bias, which I'm not sure I want. As I said above, although a bit more complicated, I have found that sampling diffuse only via Next Event Estimation, and leaving specular for the naive path tracing contributions works pretty good.  

---

## 0 answers

