This is another simple diff compared to the last experiment. All I’m adding is the ability to create mirrored surfaces.
Mirrored surfaces require the ability to recursively render the scene from different viewpoints.
To capture this ability, I add a new type that represents a function that can render a scene, given
Ray, and produce a
Material type also changes to take this function as a parameter:
The various functions that already exist within the
Material module change accordingly to pass
this parameter around, or to ignore it.
Since many of the reflective surfaces I want to represent won’t be fully reflective, I need a way
of scaling different materials. For this, I added the
(Although thinking about it, I haven’t been very consistent here. All the core material functions take a scaling factor as a parameter, but the
addMaterialsfunction doesn’t. I should probably have removed the scaling factor from all of them, and left the scaling to the above function.)
With that refactoring in place, I can now write the actual
reflectiveMaterial function. It
calculates the reflected ray from the surface, and then uses the recursive function supplied to
calculate the light being reflected:
Of course, with any recursive algorithm, I have to make sure that the recursion terminates after
a set number of iterations. To support this, I modify the
4 is the maximum number of times light is allowed to bounce within the scene. In
normal situations, this is perfectly acceptable – it’s unlikely to show artifacts unless the
scene contains mirrors that face each other.
renderRayRecursive is defined as follows:
If the limit is exceeded, simply return no light, otherwise calculate the intersection and render as usual. Notice that the recursive render function is pased to the material, but with a reflection counter one less than before.
The end result is an image that looks as follows:
Code is in Github, if you want to take a look.