Implementation & how it works

How specular surfaces work:

In ray tracing the image is drawn by tracing rays sent from the camera. If a ray intercepts  an object in the scene that objects color will be drawn on the screen. Specular surfaces is achieved by making the ray reflect from the objects and return the color from other objects it intersects . The reflections will stop either if a ray doesn't hit any object or if a predetermined reflection count is meet.[1]

Implementation

The rays sent from the camera is reflected around the normal of the surfaces using the following formulas.[2]




where u is the rays direction and n is the surfaces normal.
The only cases considered are when the ray is going towards a surface which is why u is negative in the projection and positive in the reflection.  In order to only get rays that are going towards a surface the dot product between n and u must be negative.[2] This is checked in the ClosestIntersection function before the above calculations.

If a light ray sent from the camera and hits a specular surface its reflection in that surface is calculated. It then continues it paths until the amount of total reflections is met or if it doesn't hit any surfaces. For each time the ray hits a surface it adds that surfaces color to a total sum. When the ray has stopped, the color sum is put on the screen as that pixels color.

This result is showing the Cornell room with one hundred reflections.


The view from the side with one reflection. The right wall of the room is invisible since only the surfaces facing the camera are drawn.




The image is confusing when all surfaces are specular. Only the right, left and back walls are made reflective to make the scene make more sense. This is done by only allowing reflections on surfaces that are reflective and to stop a ray when it hits a non-reflective surface.
To create non-reflective surfaces, all surfaces is given an attribute to tell if it is reflective or not. Before reflections are calculated for rays sent from the camera it is controlled that that surface is reflective or not. When a ray hits a non-reflective surface the amount of reflections that are left are multiplied to the non-reflective surfaces color and divided by the amount of reflections. Instead of adding color for each reflection the color is only added when the ray hits an non-reflective surface. This makes the reflective surfaces behave like mirrors[1].




Result

The boxes in the reflections all have the same color intensity, as can be seen in the image. To create the illusion of mirrors the light intensity of the boxes should decrease the more times they are reflected[3]. This is achieved by storing the length each ray travels, compounding through all reflections. The color intensity of each object the ray hit is multiplied by a variable that is inversely proportional to the distance the ray has traveled.



This makes the mirror tunnel become darker further down.

References:

[1] Christopher Peters, KTH Royal Institute of Technology, Introduction to computer graphics and interaction Raytracing,

https://www.kth.se/social/files/55142a41f276542e889f1e74/DH2323%20DGI15%20Raytracing.pdf
[2]Bogvad, R & Vaderlind, P,  2014, Linjär algebra grundkurs 4th edition,
pp.189-192, Matematiska instutionen Stocholms universitet.

[3]Tomas, Akenine-Möller., Eric, Haines and Nathaniel Hoffman. Real Time Rendering. 3rd ed. Wellesley: AK Peters ltd, 2008. Page 389.