Assignment 3: Importance Sampling From an HDR Light Source
Due: Tuesday, Apr 15 2008 at 11:59pm
Physically based rendering often uses High Dynamic Range (HDR) textured light sources to create photorealistic rendering effects. This requires computing an integral over the light source, and the integral is numerically evaluated using Monte Carlo sampling. If the light source is uniform, a simple uniform (area-preserving) sampling on the light source is good enough. However, when HDR textures are used, the simple uniform sampling is no longer efficient -- it converges very slowly and requires a lot of samples to produce a noise-free image. In this case, you will need to implement importance sampling
, which can significantly reduce the variance of the estimate and improve rendering quality.
As we discussed in class, importance sampling is implemeted by drawing samples that are distributed according to an importance function. The importance function typically comes from one or more components in the rendering equation. The closer the importance function is to the underlying function being integrated, the smaller variance you will get in rendering. Unfortunately not all functions can be importance sampled, especially those that have no analytic integrals, which is often the case we care about.
In this assignment, you will experiment with a simple method to importance sample according to the light source itself. Here the light source is a rectangular area light, the radiance of which is defined by an HDR texture. A naive implementation is provided to you already, which draws uniform samples from the rectangle. This ignores the spatially varying radiance and produces images that are extremely noisy. Your task is to implement an importance sampling scheme to draws samples in proportion to the radiance
defined by the light source texture. This way, regions of the light source that have high radiance (hence contribute most to the illumination) will get more samples statistically. The result is significantly reduced noise and faster convergence speed.
In addition, from this assignment you will learn to create an HDR image of your own, and use it in rendering.
Step 1: Download the starter code and scenes
Click the link below to download a zip file containing the starter code, several test scene files and textures:
You should unzip and copy the source code to their corresponding folders in your
Understanding the starter code
Look through the files and make sure you understand the basic code structure and interface functions. Two new plugins are added. The first plugin is a
), which defines a rectangle shape of size
width x height
. It is always centered at the origin with a normal pointing upward (0, 0, 1), but in the scene file you can define arbitrary transformation to move it around. You shouldn't need to modify this part of the code.
The second plugin is a
) which defines a rectangular, textured light source. It takes the following parameters from the scene file:
nsamples: The number of stochastic samples used to sample the light source. This is the same to any other light source.
height: The physical size of the light source. In
CreateLight function, these two parameters are used to construct a rectangle shape representing the light source.
mapname: Specifies an
.exr image texture file that defines the radiance of the light source.
You only need to make changes to
. Just so you know, the coding work for this assignment is significantly shorter than previous assignments. If you do it correctly, you shouldn't need to write more than 50 lines of code.
Running the Test Scenes
A naive implementation is provided to you: it draws uniform samples (in terms of area) on the rectangle. Compile the programs and run
on the test scene
. You will notice that it actually does a pretty good job already. The reason is because the radiance texture
is already fairly smooth, so a uniform sampling scheme is good enough. Now, run the program on any of the other test scenes, notice how noisy the renderings become. By default, all scenes use 8 pixel samples and 8 light source samples. In order to produce noise-free images with the naive implementation, you will need a lot of samples. However, once you have importance sampling implemented, the image quality will be substantially improved under the same number of samples. The following compares the two:
naive (8 pixelsamples) importance (8 pixelsamples) naive (8 pixelsamples) importance (8 pixelsamples)
Step 2: Implementation
Your task is to implement an importance sampling scheme that draw samples in proportion to the radiance
(more precisely, the luminance of
) defined by the radiance texture. In this case, the luminance of
acts as an importance function: more samples will be distributed where
is higher, and less samples are distributed where it's lower.
pbrt uses the
Spectrum class to represent RGB color. The member function
Spectrum::y() returns the luminance of the color.
- Read Section 15.6 of the book, and look at other light source classes (such as
infinitesample.cpp) to understand the interface functions such as
Sample_L (there are several versions, but you only need to work on one of them, as indicated in the code).
infinitesample.cpp has already implemented an importance sampling scheme for spherical environment map. This is very similar to what you need to do here. As a result, you can reuse portions of the data structure and code from that file.
- As a sanity check, your sampling scheme should fall back to area uniform sampling when the light source texture is constant. In particular, if you use
killeroo-fake.pbrt as a test scene, the importance sampled rendering should look similar to the naive implementation. If it's rather worse, something is wrong with your code.
- The probability that a sample appears at
(u,v) should obviously be proportional to
- Pay special attention to the probabilities (
pdf) that you return. Incorrectly calculated probabilities will cause large errors in rendering.
- Some lighting textures (like
stpeters.exr) have very strong radiance contrast that can cause trouble in rendering. This is because a few pixels may have such high radiance values that all stochastic samples tend to go over there. To avoid the problem, try to use a blurred version of
L(u,v) (for example, with a box filter) as importance function, to filter out anomaly pixels.
Step 3: Make Your Own HDR Texture!
Isn't it fun to create your own HDR texture and use it in rendering? With proper tools, such as
it is quite easy to do so (the latest version of Adobe Photoshop also supports creating HDR images). The basic procedure involves taking a series of pictures, each with a different shutter speed, and composite them into a single floating point image.
As a second part of the assignment is, you are to create at least one HDR image of your own and apply it in your rendering. You will need a camera to take still images toward the same scene. The scene should have interesting high dynamic range effects. So point your camera at a window where there are outdoor lights, or an indoor scene with some strong lights included. To avoid camera shaking, you probably need a tripod, or fix the camera on a stable table top. Next, adjust the shutter speed (at 1 or 2 stops interval) and take a sequence of pictures. You need to take enough pictures such that both the brightest and darkest parts of your scene are correctly exposed in at least one pictures that you've taken. Usually you need at least 5 images to cover the entire range of radiance.
Once you've taken the images, you can use
to assemble them into a single HDR. First go to http://www.hdrshop.com/
and download the free version (v1) of the software (Note: this software is for Windows only
), then follow the instructions (Step 1-3 on the "Tutorials" page) to learn how to make an HDR. There is no need to apply any image transformation (like what Step 4 discusses about).
The next step is to save the HDR you created into
format and use it in rendering. Since
format, you will need a converter. If you don't have a proper converter, search for "hdr to exr" in google and find a free tool to use. Finally, open any
test scenes included in this assignment, and substitute the
file on the line where the light source is defined with your own
file. Render it and see how the result looks!
This part is worth 1 point of the grading.
For this assignment, you should pack the following files in a single
file and email it to firstname.lastname@example.org
- Your modified
- One image (in EXR format) for each of the 6 scene provided. In testing your code, you can use the default settings (8 pixelsamples); however, you must submit final quality renderings, by using the number of
pixelsamples indicated in each scene file.
- An HDR image that you've created (in EXR format), along with an image rendered using the HDR as the image-based light source (pick any available scene you like).
There is no 691MM only portion for this assignment.
This assignment will be graded on a
scale. Partial grades (such as 3.5) will be given based on partially complete implementation.
0: Little or no work was done.
1: Significant effort was put into the assignment, but the importance sampling scheme does not work or produces images that are wrong or significantly noiser than even the naive implementation.
2: The importance sampling scheme largely works; most part of the rendering is smooth, but there are considerable amount of very bright, noisy pixels.
3: All requirements met. Images are smooth and significantly better than the naive implementation, no or very few noticeable bright pixels.
4: Made an HDR image of your own, and produced a rendering using it. This 1 point is separate from the above, so even if your important sampling completely does not work, you can still secure 1 point if you've completed this step.