<p>There is a great paper from 2006 on this topic, <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.183.3579&amp;rep=rep1&amp;type=pdf" rel="nofollow noreferrer">Filter Importance Sampling</a>. They propose your method 2, study the properties, and come out generally in favor of it. They claim that this method gives smoother rendering results because it weights all samples that contribute to a pixel equally, thereby reducing variance in the final pixel values. This makes some sense, as it's a general maxim in Monte Carlo rendering that importance-sampling will give lower variance than weighted samples.</p>
<p>Method 2 also has the advantage of being slightly easier to parallelize because each pixel's computations are independent of all other pixels, while in method 1, sample results are shared across neighboring pixels (and therefore have to be synchronized/communicated somehow when pixels are parallelized across multiple processors). For the same reason, it's easier to do adaptive sampling (more samples in high-variance areas of the image) with method 2 than method 1.</p>
<p>In the paper, they also experimented with a Mitchell filter, sampling from abs() of the filter and then weighting each sample with either +1 or −1, like @trichoplax suggested. But this ended up actually increasing the variance and being worse than method 1, so they conclude that method 2 is only usable for positive filters.</p>
<p>That being said, the results from this paper may not be universally applicable, and it may be somewhat scene-dependent which sampling method is better. I wrote <a href="https://www.reedbeta.com/blog/antialiasing-to-splat-or-not/" rel="nofollow noreferrer">a blog post investigating this question</a> independently in 2014, using a synthetic &quot;image function&quot; rather than full rendering, and found method 1 to give more visually pleasing results due to smoothing high-contrast edges more nicely. Benedikt Bitterli also commented on that post reporting a similar issue with his renderer (excess high-frequency noise around light sources when using method 2). Beyond that, I found the main difference between the methods was the frequency of the resulting noise: method 2 gives higher-frequency, &quot;pixel-sized&quot; noise, while method 1 gives noise &quot;grains&quot; that are 2-3 pixels across, but the amplitude of noise was similar for both, so which kind of noise looks less bad is probably a matter of personal preference.</p>

CC BY-SA 3.0
2016-03-03T15:54:38.817Z
Thanks! These are great resources. So, in the end, there are 3 methods? 1. Generate and Weigh with splatting 2. Generate and Weigh without splatting 3. Generate in the Shape of a Filter
RichieSams
CC BY-SA 3.0
2016-03-03T15:57:59.273Z
Do you know of any papers, blogs, etc. that explore how to parallelize Generate and Weight *with* splatting? Off the top of my head, you could have a mutex per tile, or make each pixel atomic.
RichieSams
CC BY-SA 3.0
2016-03-03T18:20:25.620Z
@RichieSams I don't know why you'd use "generate and weigh without splatting", actually—that seems like it would be worse in any case than filter importance sampling. I was assuming that "generate and weigh" implies splatting. As for parallelization of splatting, off the top of my head, one way would be to split the image into tiles, but give each tile a 2‒3 pixel border to catch splats that cross the tile edge. Then in a final pass, additively composite the bordered tiles together into the final image.
Nathan Reed
CC BY-SA 4.0
2016-03-03T04:59:18.810Z
2021-12-02T22:39:11.037Z
2021-12-02T22:39:11.037Z
Nathan Reed
<p>In ray tracing / path tracing, one of the simplest way to anti-alias the image is to supersample the pixel values and average the results. IE. instead of shooting every sample through the center of the pixel, you offset the samples by some amount.</p>

<p>In searching around the internet, I've found two somewhat different methods to do this:</p>

<ol>
<li>Generate samples however you want and weigh the result with a filter

<ul>
<li>One example is <a href="https://github.com/mmp/pbrt-v3/blob/master/src/core/film.h#L114" rel="noreferrer">PBRT</a></li>
</ul></li>
<li>Generate the samples with a distribution equal to the shape of a filter

<ul>
<li>Two examples are <a href="http://www.kevinbeason.com/smallpt/" rel="noreferrer">smallpt</a> and <a href="https://computergraphics.stackexchange.com/users/79/benedikt-bitterli">Benedikt Bitterli</a>'s <a href="https://github.com/tunabrain/tungsten/blob/master/src/core/cameras/ReconstructionFilter.hpp" rel="noreferrer">Tungsten Renderer</a> </li>
</ul></li>
</ol>

<p><br/></p>

<p><strong>Generate and Weigh</strong></p>

<p>The basic process is:</p>

<ol>
<li>Create samples however you want (randomly, stratified, low-discrepancy sequences, etc.) </li>
<li>Offset the camera ray using two samples (x and y)</li>
<li>Render the scene with the ray</li>
<li>Calculate a weight using a filter function and the distance of the sample in reference to the pixel center. For example, Box Filter, Tent Filter, Gaussian Filter, etc.)
<a href="https://i.sstatic.net/gz7Bg.png" rel="noreferrer"><img src="https://i.sstatic.net/gz7Bg.png" alt="Filter Shapes"></a></li>
<li>Apply the weight to the color from the render</li>
</ol>

<p><br/></p>

<p><strong>Generate in the shape of a filter</strong></p>

<p>The basic premise is to use <a href="https://en.wikipedia.org/wiki/Inverse_transform_sampling" rel="noreferrer">Inverse Transform Sampling</a> to create samples that are distributed according to the shape of a filter. For example a histogram of a samples distributed in the shape of a Gaussian would be:<br/>
<a href="https://i.sstatic.net/7pGFS.png" rel="noreferrer"><img src="https://i.sstatic.net/7pGFS.png" alt="Gaussian Histogram"></a></p>

<p>This can either be done exactly, or by binning the function into a discrete pdf/cdf. <a href="http://www.kevinbeason.com/smallpt/" rel="noreferrer">smallpt</a> uses the exact inverse cdf of a tent filter. Examples of binning method can be found <a href="https://gist.github.com/RichieSams/ce2ca2a201227c1de543" rel="noreferrer">here</a></p>

<p><br/></p>

<p><strong>Questions</strong></p>

<p>What are the pros and cons of each method? And why would you use one over the other? I can think of a few things:</p>

<p>Generate and Weigh seems to be the most robust, allowing any combination of any sampling method with any filter. However, it requires you to track the weights in the ImageBuffer and then do a final resolve.</p>

<p>Generate in the Shape of a Filter can only support positive filter shapes (ie. no Mitchell, Catmull Rom, or Lanczos), since you can not have a negative pdf. But, as mentioned above, it's easier to implement, since you don't need to track any weights.</p>

<p>Though, in the end, I guess you can think of method 2 as a simplification of method 1, since it's essentially using an implicit Box Filter weight.</p>

CC BY-SA 3.0
2016-03-02T20:02:08.893Z
Just thinking aloud... Could you model the negative part of a filter separately to generate two sets of samples, one to be treated as positive and the other as negative? Would this allow arbitrary filters for your second approach (generate in the shape of a filter)?
trichoplax is on Codidact now
CC BY-SA 3.0
2016-03-02T20:47:44.223Z
Maybe? Lemme fiddle with it for a bit
RichieSams
CC BY-SA 3.0
2016-03-02T22:31:26.867Z
Ok, if you track the zeros of the function, you can abs() the output into the pdf. Then when sampling, you can check if you're negative. Sample code here: https://gist.github.com/RichieSams/aa7e71a0fb4720c8cb41
RichieSams
<raytracing><antialiasing><pathtracing><filtering><supersampling>
Anti-aliasing / Filtering in Ray Tracing
RichieSams
# Anti-aliasing / Filtering in Ray Tracing

(Asked by: username_0 on 2016-03-02)

In ray tracing / path tracing, one of the simplest way to anti-alias the image is to supersample the pixel values and average the results. IE. instead of shooting every sample through the center of the pixel, you offset the samples by some amount.

In searching around the internet, I've found two somewhat different methods to do this:

1. Generate samples however you want and weigh the result with a filter
   * One example is [PBRT](https://github.com/mmp/pbrt-v3/blob/master/src/core/film.h#L114)
2. Generate the samples with a distribution equal to the shape of a filter
   * Two examples are [smallpt](http://www.kevinbeason.com/smallpt/) and [Benedikt Bitterli](https://computergraphics.stackexchange.com/users/79/benedikt-bitterli)'s [Tungsten Renderer](https://github.com/tunabrain/tungsten/blob/master/src/core/cameras/ReconstructionFilter.hpp)

**Generate and Weigh**

The basic process is:

1. Create samples however you want (randomly, stratified, low-discrepancy sequences, etc.)
2. Offset the camera ray using two samples (x and y)
3. Render the scene with the ray
4. Calculate a weight using a filter function and the distance of the sample in reference to the pixel center. For example, Box Filter, Tent Filter, Gaussian Filter, etc.)
   [![Filter Shapes](https://i.sstatic.net/gz7Bg.png)](https://i.sstatic.net/gz7Bg.png)
5. Apply the weight to the color from the render

**Generate in the shape of a filter**

The basic premise is to use [Inverse Transform Sampling](https://en.wikipedia.org/wiki/Inverse_transform_sampling) to create samples that are distributed according to the shape of a filter. For example a histogram of a samples distributed in the shape of a Gaussian would be:  
[![Gaussian Histogram](https://i.sstatic.net/7pGFS.png)](https://i.sstatic.net/7pGFS.png)

This can either be done exactly, or by binning the function into a discrete pdf/cdf. [smallpt](http://www.kevinbeason.com/smallpt/) uses the exact inverse cdf of a tent filter. Examples of binning method can be found [here](https://gist.github.com/username_0/ce2ca2a201227c1de543)

**Questions**

What are the pros and cons of each method? And why would you use one over the other? I can think of a few things:

Generate and Weigh seems to be the most robust, allowing any combination of any sampling method with any filter. However, it requires you to track the weights in the ImageBuffer and then do a final resolve.

Generate in the Shape of a Filter can only support positive filter shapes (ie. no Mitchell, Catmull Rom, or Lanczos), since you can not have a negative pdf. But, as mentioned above, it's easier to implement, since you don't need to track any weights.

Though, in the end, I guess you can think of method 2 as a simplification of method 1, since it's essentially using an implicit Box Filter weight.

**Tags:** raytracing, antialiasing, pathtracing, filtering, supersampling

> **Comments:**
> **username_1**: Just thinking aloud... Could you model the negative part of a filter separately to generate two sets of samples, one to be treated as positive and the other as negative? Would this allow arbitrary filters for your second approach (generate in the shape of a filter)?  
> **username_0**: Maybe? Lemme fiddle with it for a bit  
> **username_0**: Ok, if you track the zeros of the function, you can abs() the output into the pdf. Then when sampling, you can check if you're negative. Sample code here: https://gist.github.com/username_0/aa7e71a0fb4720c8cb41  

---

## 1 answers

### Answer by username_2 on 2016-03-03. Score: 12 | Accepted answer

There is a great paper from 2006 on this topic, [Filter Importance Sampling](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.183.3579&rep=rep1&type=pdf). They propose your method 2, study the properties, and come out generally in favor of it. They claim that this method gives smoother rendering results because it weights all samples that contribute to a pixel equally, thereby reducing variance in the final pixel values. This makes some sense, as it's a general maxim in Monte Carlo rendering that importance-sampling will give lower variance than weighted samples.

Method 2 also has the advantage of being slightly easier to parallelize because each pixel's computations are independent of all other pixels, while in method 1, sample results are shared across neighboring pixels (and therefore have to be synchronized/communicated somehow when pixels are parallelized across multiple processors). For the same reason, it's easier to do adaptive sampling (more samples in high-variance areas of the image) with method 2 than method 1.

In the paper, they also experimented with a Mitchell filter, sampling from abs() of the filter and then weighting each sample with either +1 or −1, like @username_1 suggested. But this ended up actually increasing the variance and being worse than method 1, so they conclude that method 2 is only usable for positive filters.

That being said, the results from this paper may not be universally applicable, and it may be somewhat scene-dependent which sampling method is better. I wrote [a blog post investigating this question](https://www.reedbeta.com/blog/antialiasing-to-splat-or-not/) independently in 2014, using a synthetic "image function" rather than full rendering, and found method 1 to give more visually pleasing results due to smoothing high-contrast edges more nicely. Benedikt Bitterli also commented on that post reporting a similar issue with his renderer (excess high-frequency noise around light sources when using method 2). Beyond that, I found the main difference between the methods was the frequency of the resulting noise: method 2 gives higher-frequency, "pixel-sized" noise, while method 1 gives noise "grains" that are 2-3 pixels across, but the amplitude of noise was similar for both, so which kind of noise looks less bad is probably a matter of personal preference.

> **Comments:**
> **username_0**: Thanks! These are great resources. So, in the end, there are 3 methods? 1. Generate and Weigh with splatting 2. Generate and Weigh without splatting 3. Generate in the Shape of a Filter  
> **username_0**: Do you know of any papers, blogs, etc. that explore how to parallelize Generate and Weight *with* splatting? Off the top of my head, you could have a mutex per tile, or make each pixel atomic.  
> **username_2**: @username_0 I don't know why you'd use "generate and weigh without splatting", actually—that seems like it would be worse in any case than filter importance sampling. I was assuming that "generate and weigh" implies splatting. As for parallelization of splatting, off the top of my head, one way would be to split the image into tiles, but give each tile a 2‒3 pixel border to catch splats that cross the tile edge. Then in a final pass, additively composite the bordered tiles together into the final image.  

---

