Sheet 8: Radiosity
Exercise: Diffuse Global Illumination with Radiosity (25 points)
In this exercise you will implement the geometric core of a simple radiosity renderer.
The application already creates a Cornell-box scene, tessellates the objects, displays
the computation progress, solves the linear radiosity system, and renders the result.
Your task is to complete the missing code in Scene.cpp and
RadiositySolver.cpp.
Radiosity assumes purely diffuse surfaces. Instead of following individual camera rays as in path tracing, it computes how light energy is exchanged between surface patches. The radiosity equation from the lecture is:
B_i is the outgoing radiosity of patch i,
B_ie is emitted light, ρi
is diffuse reflectance, and Fij is the form factor
describing how strongly patch j contributes to patch i.
Task 1: Create Surface Patches (7 points)
Complete Scene::createPatches. Radiosity works on surface patches, and
in this exercise every triangle of the tessellated scene becomes one
RadiosityPatch.
For every object in sceneObjects:
- Get the unpacked triangle mesh with
object->getMesh().unpack(). - Read the triangle vertex coordinates from
mesh.getVertices(). - Create one
RadiosityPatchfor each triangle. - Store the triangle vertices in
patch.a,patch.b, andpatch.c. - Compute the patch center as the average of the three vertices.
- Compute the patch normal and area with the provided helper functions.
- Copy reflectance and emission from the object's material.
- Initialize
patch.radiositywithpatch.emission. - Store only non-degenerate patches with positive area.
If this task is implemented correctly, the progress view should show the scene geometry while the form-factor computation runs.
Task 2: Estimate Form Factors (10 points)
Complete formFactorEstimate in RadiositySolver.cpp.
The lecture derives the form factor as an integral over two patch areas:
In the lecture, this integral is approximated using a hemicube. In this exercise we use a simpler center-to-center estimate instead. This is less accurate for large patches, but it is compact, easy to implement, and good enough once the geometry is tessellated into reasonably small patches.
Here ci and cj are the patch centers.
The factor Aj appears because the integral over the emitting
patch is replaced by one sample at its center. In our code,
receiver is patch i and emitter is patch
j.
Implement the estimate as follows:
- Compute the vector from
receiver.centertoemitter.center. - Compute the squared distance and return zero if it is zero.
- Normalize the vector to get the direction from receiver to emitter.
- Compute
cos(theta_i)with the receiver normal. - Compute
cos(theta_j)with the emitter normal and the opposite direction. - Return zero if either patch faces away from the other.
- Return the center-to-center form-factor estimate.
Task 3: Visibility Between Patches (8 points)
Complete RadiositySolver::visible. The visibility term
V tells us whether two patches can exchange light directly:
We again use a center-to-center approximation. Cast one ray from the center of one
patch toward the center of the other patch. Start the ray slightly away from the first
patch using visibilityEpsilon, otherwise numerical precision may make the
ray immediately hit the patch it starts from.
The patches are visible if the scene intersection is empty, or if the closest hit is farther away than the target center. If another object is hit before the target center, the two patches are occluded and the form factor should not contribute.
Reference Solution
Left mouse drag rotate, R reset rotation, S toggle flat/smoothed radiosity after the solve finished
During form-factor computation, green patches have already been processed.