Sunday, April 9, 2017

Assignment 4: Reflections and Refractions

Ray tracing is good at simulating refraction and reflection of light by its nature. One of the first things we have to consider to simulate reflective and refractive materials is that we have to shoot rays beside the primary and shadow rays. After primary rays, if we detect any refractive or reflective surface, we should generate new rays based on the physics of light.

A perfect specular surface reflects the incoming light in a certain direction. Although perfect specular surfaces are hard to find in nature, not sure if it is impossible, they are implemented in every ray tracer since they are the starting point for simulating other reflective surfaces. On the other hand, when the light interacts with a refractive surface, some of the photons are reflected while some others are refracted depending on the incident angle of light. This effect can be easily seen from the picture of a lake below.
As you can see, in the pixels near the right-bottom corner of the image, we can easily see the transparent nature of water. The reason is that the incident angle is smaller. However, as the view direction is getting to be perpendicular to the surface normal, incident angle is getting larger and therefore photons are getting mostly reflected. Fresnel equations explain this behaviour and based on these equations, we can compute which proportion of photons will be reflected or refracted. Furthermore, Schlick’s approximation is a well-known approximation of the Fresnel equations, which can be used to decrease the computation time. Also, Snell's law helps us to compute the direction of a refracted light. Finally, by means of the Beer's law, we can compute the attenuation of the light traveling through the medium. This document clearly explains aforementioned equations and laws except Beer's law.

Let us see the scenes we should render for this assignment.
output of cornellbox_glass.xml
kernel execution time: 31.1 milliseconds

output of horse_and_glass_mug.xml
kernel execution time: 571 milliseconds

output of glass_plates.xml
kernel execution time: 55.8 milliseconds

output of killeroo_glass.xml
kernel execution time: 531 milliseconds

output of killeroo_half_mirror.xml
kernel execution time: 82.5 milliseconds

output of killeroo_mirror.xml
kernel execution time: 82.5 milliseconds
Lessons learned:
  1. Rendering times are higly increased for the scenes which include refractive materials. Of course this is an expected outcome, however, the biggest reason for slowdown is the usage of stack which is used to recursively trace all the rays generated by these materials. Even without recursion, that is, just defining a stack of 2 kb in every thread and not touching it, my ray tracer slows down by 2x. A workaround to this problem is as follows: instead of generating two rays after light-refractive surface interaction, we generate one ray but we choose whether to refract or reflect the ray by means of Fresnel equations or Schlick's approximation and a uniform random number generator. The problem is that if we take just one sample for each pixel, the output might look incorrect. Therefore, we should take as many samples as possible for each pixel since the output converges to the expected output with infinitely many samples. For these reasons, I postponed the implementation of this approach to the next assignment where I will implement multisampling. After implementing this approach, every ray-surface interaction will be able to generate at most one ray so that I get rid of the stack.

No comments:

Post a Comment