Volumetrics in this ray tracer are implemented as an extension to Solid. This choice was made to be able to localize the volumetric effect where it would be most impressive without impacting performance outside the region. This implementation consists of two parts: the integrator (RayMarchIntegrator in raymarch.cpp) and the volumes (rt/volumes/). The Intersection structure was extended to allow a pointer to a Volume object and a method to determine if the Intersection represents an intersection with a volume.
The implementation largely follows the slides presented in class. Some notable decisions made were to use a fixed number of march points for rays as opposed to a fixed march step size and to specify the attenuation and inscattering values using std::function objects. The fixed number of march points made the implementation easier to use, but results in better approximation of the volume effects on the edges of round volumes. Requiring a specified march step size would be less flexible in terms of scene construction, but would result in better performance and more even approximation of the volume. Using a std::function object to specify attenuation and inscattering was an excellent idea taken the implementation of this engine's motion blur system and stands up exceptionally well in retrospect. This allows the scene designer to make quick changes without recompiling engine components.
The volume regions implementated were: SphereVolume, EllipsoidVolume, and AABBVolume. Of these, the SphereVolume and EllipsoidVolume are fully tested, with the EllipsoidVolume being the volume finally used in the scene. The EllipsoidVolume was added after observing that the SphereVolume resulted in a lot of excess coverage of the image which wasted performance. The AABBVolume was never fully tested and may not function correctly.
The largest challenge encountered with the volumetrics system was the need to support high frequency interactions in the volume. This was caused by the desired scene having a volumetric region in the path of the window shadows. The solution to this problem will be presented in the next section.
An image of the window shadows intersecting an ellipsoid volume region prior to solving the aliasing problem is shown to the left (5 samples per pixel, 15 march points per ray). The working theory on this effect is that highly deterministic march points combined with the volume surface curvature results in banding from the high frequency content of the window shadows. It was found that in order to eliminate this effect by brute force over 60 march points per ray would be needed. This exceeded what was thought to be reasonable.
To the right is an image of the window shadows intersecting an ellipsoid volume region after implementing a solution (again, 5 samples per pixel, 15 march points per ray). The solution that was used to remove this aliasing problem was spatial dithering along the ray when computing march points. This uses the distributed ray tracing concept to trade aliasing for noise, which is more tolerable to the human visual system and can be integrated out by increasing the number of samples similar to the ground shadow of the window. Some ghosting of the window can stil be observed near the surface of the volume, but this is mitigated by higher volume march points. In iteration preceeding the final render, 30 march points was found to be sufficient to avoid this undesirable effect.