Method
A key component of a rendering system is the camera model. Unfortunately, current camera models are highly simplified and not geometrically or radiometrically correct and thus are not sufficient for synthesizing images from physically-based rendering programs such as pbrt.
In this paper [1] the authors describe a physically-based camera model for computer graphics. More precisely, a physically-based camera model accurately computes the irradiance on the film given the incoming radiance from the scene. A camera is described as a lens system and film backplane. The lens system consists of a sequence of simple lens elements, stops and apertures. The camera simulation module computes the irradiance on the backplane from the scene radiances using distributed ray tracing. This is accomplished by a detailed simulation of the geometry of ray paths through the lens system, and by sampling the lens system such that the radiometry is computed accurately and efficiently. Because even the most complicated lenses have a relatively small number of elements, the simulation only increases the total rendering time slightly.
Physical lens systems. (telephoto, double gauss, wide angle, fisheye)
This is also the approach I have taken in this assignment. I modeled the lens as a collection of spherical lens elements and disc-shaped aperture stops. I shoot rays from the film plane towards the back element of the lens using a low discrepancy sampler and trace the ray as it progresses through the lens system, refracting on the individual lens component surfaces. Some rays 'die' because of total internal reflection, some of them are stopped because of the finite aperture of the lens components. This approach accounts for vignetting, the blocking of light by lens elements other than the aperture stop when a ray passes through the system at a large angle to the axis.
Note that I don't sample the exit pupil as described in the paper, but rather the backmost lens element. This approach is less efficient than shooting rays restricted to the exit pupil, because some of the rays will hit the aperture stop and terminate before they exit the front of the lens, but it doesn't pose a major problem, except for the wide angle lens, as described in the next section. I have used pbrt's ConcentricSampleDisk() function for converting two 1D uniform random samples into a uniform random sample on a disk. It uses Shirley's
Sampling is done without importance distribution. As described above, the rays are cast from points x in the pixel area toward points on the disk of the backmost lens component and the resulting values are weighted [1] by cos(θ)^2 * cos(θ')^2 / ||x' -x||^2 to produce the correct radiance integral to find the total irradiance at point x on the film plane. If we assume that the film plane is parallel to the lens system and that the exit pupil subtends a small solid angle from x, true in my experiments where I placed the film plane relatively far from the backmost lens component, this can be simplified to cos(θ)^4/filmdistance^2. I have not tried the alternative, much more complex approach of importance sampling, folding the same cos factor into the distribution of rays over solid angle, as the authors reported that it reduced noise by only about one percent in their experiments.
Implementation
I've extended pbrt with two new plugins, more specifically a LensComponent Shape plugin and a RealisticCamera Camera plugin.
First, I built an appropriate datastructure to store lens parameters described by tab-delimited .dat files, that describe lens types as given in Figure 1 of the Kolb[1] paper.
The LensComponent Shape plugin represents one spherical lens component in the lens stack. It is basically a simplified version of the Sphere Shape plugin with support for finite aperture, with additional advantage that it is more efficient because I was able to make use of knowledge of the ray direction and because I don't need any other information than the intersection point.
The aperture stop was modeled by a disc, provided by the Disc Shape plugin provided by pbrt.
The entire lens stack of is wrapped into a vector of Lens structs, holding the individual components exactly ordered by visibility from the film plane. This ordering is important, because this way there is no search required to find the closest surface in a given direction. The Lens struct holds a reference to the component (either spherical or aperture stop, the aperture diameter of the element, the relative refraction parameter and a boolean indicating if the lens component is concave or convex as seen from the film.
The camera class stores the distance from the film to the backmost lens component, the aperture diameter of the aperture stop (modifiable in the pbrt scene description file), the RasterToFilm and RasterToCamera Transforms, and the ordered list of Lens components.
In the GenerateRay() function, I first transform the film sample to camera space, and sample a point on the finite disc aperture of the backmost spherical lens component, using the two provided 1D low discrepancy samples. The ray is initialized with origin at the film sample and in the direction of the back component sample. In a simple for loop, I trace rays and compute intersection points with the lens components in camera space. This is where the exact ordering of the components is very useful. If there is intersection, I use Snell's law to compute the refracting direction, also taking into account total internal reflection. If there is no intersection or total internal reflection, I return a 'dead' ray from the GenerateRay() function by returning a ray that has its smallest hitpoint t larger than its largest t. Note that the LensComponent aswell as the Disc plugins report non-intersection when the ray doesn't hit inside the finite aperture, thus correctly accounting for vignetting. If the ray was able to traverse the entire stack of components without being blocked, the ray is transformed to world space and returned from the GenerateRay() function together with the appropriate cos(θ)^4/filmdistance^2 weighting factor.
Debugging
For debugging purposes, I needed a way to track the traversal of the rays through the lens system. TheRealisticCamera can write the intersection points of the rays with the lens components to a text file. Using a simple matlab script, I was able to have a quick visual representation of the lens system ray traversal in 2D and 3D, as is shown in the images below. Note that, in the 2D views, it seems as if the intersection points (in red) are not really intersecting on the sphere surface (not on a circle), but they really are. The confusion comes from the fact that the 2D orthogonal projection of a spherical surface is not a circle!
Matlab plots of the ray traversal through some of the lenses. In order: double gauss, telephoto and fisheye. The telephoto plot is a 3D view. The apparent 'regularity' of the grid points in this plot is due to the fact that I am not showing all cast rays, but a uniformly sampled subset. (click the images for a full sized version)
Realistic lens models
50 mm Double Gauss Lens
Double gauss, 128 (left) vs. 512 (right) samples/pixel.
250mm Telephoto Lens
250mm telephoto lens, cones vs. the bunny (512 samples/pixel).
16mm Fisheye Lens
16mm fisheye lens, 32 (left) vs. 512 (right) samples/pixel.
35mm Wide Angle Lens
25mm wide angle lens, 512 samples/pixel (left). The ray traversal on the right shows that a relatively large number of rays are blocked by the lens system.
Notice that the wide angle image is especially noisy. This can be explained by observing the traversal of rays. A large portion of the rays shot at the back lens component end up being blocked by the aperture stop and by the finite aperture of the other lenses, making the method less efficient and resulting in more noisy results. This is an example of a case where it would be useful to determine the exit pupil first and sampling that directly, instead of the backmost lens component. That way, we guarantee that the rays won't be stopped at the aperture stop or by other lens component apertures. Ofcourse, this won't stop the rays from being blocked by total internal reflection at the lens surfaces.
Depth of field experiments
Two views of the same scene, with the telephoto lens camera slightly rotated from one view to the other. Note that the bunny in the right image is (partly) in the plane of focus, whereas the bunnies on the right are not. The effect is particularily obvious in these images produced with the 250mm telephoto lens, even the bunny that is intersecting the focused world plane shows up blurry for some of its parts that are only slightly outside of this plane.
Test image and enlargement of the same image with film plane placed at 36.36 mm behind the backmost lens component.
Enlargements of the test image with film plane place at 36.15 mm, 36.36 mm and 36.60 mm behind the backmost lens component respectively. Note that the outer images are slightly more blurry than the middle one.
Aperture experiments
Comparison of images produced with varying aperture stop opening. On the left, fully open aperture stop for the double gauss lens (17.1mm), on the right, half open aperture stop.
Less light is admitted through the lens stack, so the exposure decreases, as can be seen from the images produced by my implementation. Note that the right image is also more noisy than the left one, because of the same phenomenon as observed for the wide angle lens. More rays are turned into dead rays by the aperture stop because I am sampling the back lens component instead of the exit pupil. A solution would be to either have more samples, or compute and sample the exit pupil.
References and code
The code can be found here. It includes the implementation of a Camera plugin in realistic.cpp, and the new Shape plugin in lenscomponent.cpp. Sample lens data files are provided. Finally, the matlab scripts showrays.m and showrays3.m produce the lens ray traversal figures such as above, the first is a 2D version, the latter is in full 3D. You can generate your own rays.mat file by setting the dumprays boolean to true in the scene description file.
- A Realistic Camera Model for Computer Graphics by Kolb, Mitchell, and Hanrahan. Computer Graphics (Proceedings of SIGGRAPH '95), ACM SIGGRAPH, 1995, pp. 317-324
- Discrepancy as a quality measure for sample distributions by Peter Shirley Eurographics '91 proceedings, pages 183-193, June 1991
- Stanford CS248 course page Useful hints for implementation and experiments



