Comparing Two Global Illumination Methods

After completing a path tracing render of the Cornell Box recently, I thought about an interesting experiment.  Since it’s a fully diffuse scene, it could be rendered using finite element radiosity, and the two results could be compared, helping to validate and sanity check both approaches.

In path tracing, an entire wall of the Cornell Box can be one single square polygon.  But in radiosity, the illumination is calculated per polygon (or ‘patch’).

I added code to subdivide meshes, either by iteratively subdividing some number of times, or by subdividing until every polygon is under some maximum area.

The Cornell Box divided into patches for radiosity - lores version

The Cornell Box divided into patches for radiosity – lores version.

Ultimately, I chose to start with around 1000 patches.

The image shows The Cornell Box divided into patches for radiosity by coloring each small patch a different flat color.

The Cornell Box divided into patches for radiosity.

Then, code was added to convert meshes to the Radiosity data structures: entities and patches.  The result using around 1000 patches (3 subdivisions) and 32-pixel hemicubes is already quite encouraging!

The Cornell Box rendered using 1000 radiosity patches.

The Cornell Box rendered using 1000 radiosity patches and 32 pixel hemicube resolution.

There are a few classic artifacts of radiosity visible in the image above.  First, the edges and corners of the room are brighter than they are in path tracing, due to the fact that we’re evaluating the lighting in the center of a nearby patch rather than inside the corner.  Second, the shadows of the boxes don’t line up with the corners of the box perfectly.  This is especially visible on the smaller box.  Third, if you look carefully, you can pick out the Gouraud style shading artifacts inherent in interpolating the lighting from vertices across the polygons.

Increasing the patch count to around 11,000 helps to greatly reduce these artifacts!  Below, you can see path tracing on the left and radiosity on the right.

Path Tracing and Radiosity Compared- Attempt 1

Path Tracing and Radiosity Compared- Attempt 1

This is an encouraging result, but I noticed that the front face of the tall cube is uniformly brighter in radiosity than it is in path tracing.  This turned out to be a tricky problem to debug, since the lighting code in each approach is completely separate.  After a few unsuccessful attempts to debug the issue in this scene, I moved on to a simpler scene.  You might recall the “emmision” test scene from the Utah Global Illumination Test Scenes from a past post in this blog.  Here’s the result of rendering that scene as-is with radiosity.

"Emmision" scene rendered with Radiosity but no subdivision.

“Emmision” scene rendered with Radiosity but no subdivision.

The super flat look is a reminder we’re only calculating the lighting per patch in radiosity.  So the next step is to find a subdivision amount that’s reasonable.

Three levels of subdivision compared in radiosity renders of the "emission" test scene.

Three levels of subdivision compared in radiosity renders of the “emission” test scene.

After choosing subdivision to max area of 200, it’s time to render a recent path tracing render of the same scene and compare.  The good news is that the difference is visible here as well!  The radiosity version seems to have expanded highlights.  The light falls on the ground in a slightly bigger pattern.

Path tracing on the left, and radiosity on the right.

Path tracing on the left, and radiosity on the right.

To comapare pixel values, it’s useful to turn off interpolation in the radiosity version.  I need to compare exact patch values to the same exact (patch center) location in the path tracing version.

Path tracinfg on the left and flat-shaded radiosity on the right.

Path tracinfg on the left and flat-shaded radiosity on the right.

At this point it’s worth noting that it was very tempting to chalk this difference up to some quirk of integration using these different methods with non-infinite segmentation.  I’m happy to say though that the problem was found!  Path tracing ended up being the culprit, which surprised me.  I spent quite an amount of time stepping through the radiosity code before deciding the check the path tracing.  The issue ended up being a 10 year old “test” code snippet I was using to test a fresnel effect.  I never removed it back then, and it ended up biting me now.  I’m glad I didn’t chalk this up to some unknowable quirk.  Removing that term imnmediately brought the two results into allignment.  Here’s the fixed comparison for the emission scene:

A fixed comparison showing path tracing on the left and radiosity on the right.

A fixed comparison showing path tracing on the left and radiosity on the right.

And here’s the same fix applied to the Cornell Box.  A much better match!

A fixed comparison of the Cornell Box rendered in path tracing on the left and radiosity on the right.

A fixed comparison of the Cornell Box rendered in path tracing on the left and radiosity on the right.

2 thoughts on “Comparing Two Global Illumination Methods

  1. This is an interesting read! I was also suffering from a rendering artifact recently, and spent a great deal of time (5 days) debugging it which is really painful…
    Congratulations on finding the bug!

    1. Thank you for reading! Yes, some of these bugs can be very subtle and difficult to track down, but it’s so satisfying once the problem is fixed!

Leave a Reply to Jason Cancel reply

Your email address will not be published. Required fields are marked *