- Using your parallelized ray tracer, rewrite your
`ray_t::trace()`

routine to spawn a transmission ray for any object intersected that has`alpha > 0`

. - Transmission rays, unlike reflection rays which bounce off the object
surface, cross into the object, refracting as they do so, according
to Snell's Law,
which states that
*n*sin(_{1}*θ*_{1}) =*n*sin(_{2}*θ*_{2}) where*n*is the_{1}*index of refraction*of medium 1 w.r.t. vacuum and*n*is the_{2}*index of refraction*of medium 2 w.r.t. vacuum. An index of refraction, or`ior = 1.000293`

models air, while an index of refraction of`1.337`

models the vitreous humor—the liquid inside the human eye (see the list of refractive indices for others). - The angle of refraction of the transmission ray, assuming
__incoming__normalized direction(the ray direction), is calcuated as:**u**(n

where_{1}/n_{2})(**u**- cos*θ*_{1}**N**) - cos*θ*_{2}**N**is the normal at the intersection point (which you get from your**N**`model_t::find_closest()`

),`cos`is*θ*_{1},**u**·**N**`cos`is*θ*_{2}`sqrt(1 - ((n`_{1}/n_{2})^{2}(1 - (**u**·**N**)^{2})))

`n`and never change it if we assume the scene is immersed in air._{1}= 1.000293 - A transmission ray is spawned in much the same way as a reflection
ray, except that it is only done if the intersected object's
`alpha`

value is`> 0`

(in other words only when the ray encounters a transparent object). - Take care to refract the ray about a properly signed surface normal,
i.e., if
(the incoming ray direction**u**·**N**< 0points into the object) then refract the ray about**u**with**N**`n`otherwise (the incoming ray direction_{2}points out of the object) refract the ray about**u**with**-N**`1/n`._{2} - Blend the resultant color via the traditional compositing
(linear interpolation) equation:

wherecolor = ((1.0 - alpha) * color) + (alpha * transmitted_color);

`transmitted_color`

is the transparent color set by the transmission ray (don't forget to clamp the color to`[0,1]`range). - With the
`model.txt`

given below, your ray tracer should now render the image below, of a transparent sphere with the same refractive index as the human eye's vitreous humor.

no TIR, no

`t1``t1`but no TIR (oops!)TIR but no

`t1`no reflection?

(doesn't seem right, I forget how I got this, sorry)final image

with Schlick's approximation

- Rewrite your
`material_t`

to handle processing material properties`alpha`

(a single`float`

value) and`ior`

(also a single`float`

value). Make sure that your`material_t`

class provides queries that return these values, e.g.,`getalpha()`

and`getior()`

, which will behave similarly to`getspec()`

for example, but will return single`float`

values instead of`vec_t`

vectors. Before doing anything on this assignment, make sure that you can successfully process the input`model.txt`

file and be able to write it out. - The old
`model_t::find_closest()`

routine won't work anymore because its initial design assumed that a ray would hit any given object only once (and reflect). Clearly this won't work for transparent objects that have volume, through which the transparent ray needs to exit, once it has penetrated it. This means, particularly for transparent spheres, that the ray will hit the sphere twice, and so the`find_closest()`

routine needs to be rewritten:- initialize the local variable
`closest_dist`

to`INFINITY`

instead of to`-1`

- remove the
`obj==last_obj ||`

evaluation from the initial call to`obj->hits()`

—the current object should only be skipped if the returned`dist < 0`

- only record the closest distance, object, hit point, and normal
if
`(0.00001 < dist) && (dist < closest_dist)`

(the distance to the intersection point must be non-zero)

- initialize the local variable
- Because the refracted ray is refracted either about
or**N**, it is convenient to write a**-N**

function that refracts the given (e.g.,vec_t::refract(const vec_t& n, double n_t) const

`this`

) vector about`n`

with`n`. Writing a_{2}= n_{t}

function for reflection is also a good idea, where the resultant reflection vector isvec_t::reflect(const vec_t& n) const

.**u**- 2.0(**u**·**N**)**N** - When calculating refraction, if the expression inside the radical
is less than
`0`, i.e., if`1 - ((n`then the refraction angle is_{1}/n_{2})^{2}(1 - (**u**·**N**)^{2})) < 0*critical*and the ray does not refract, but reflects internally. This is known as total internal reflection, or TIR. When this happens, simply reflect the ray about.**N** - When a ray enters a transparent sphere, the sphere's
`hits`

routine should now calculate both roots of the quadratic equation and return the smaller of the two, unless the smaller of the two is less than`0.00001`

in which case the larger should be returned. Instead of just calculating`t`

now calculate`t0 = (-b - sqrt(d))/(2.0*a); t1 = (-b + sqrt(d))/(2.0*a);`

and return`t0`

if it is smaller than`t1`

unless it is behind the ray position (i.e., unless`t0`

is negative, but due to round-off error we test whether it smaller than`0.00001`

).

Note that if`t1`

is returned, then we are exiting the sphere. - The above calculation of
`t1`

can in turn lead to infinite loops where rays can get stuck in a region close to the sphere surface. To prevent this, rewrite`ray_t::trace()`

to include an additional integer argument,`bounce`

which you test immediately as you enter the routine—if it is larger than say 10, return (prune this ray as it has already bounced too many times).

- If you implement both
`vec_t::reflect()`

and`vec_t::refract()`

functions, then you can try implementing Pete Shirley's solution (see §10.7) which uses Schlick's approximation to the Fresnel equations for light transport (both reflection and refraction of light may occur at the surface interface where refractive indices differ). In this case two rays are spawned when intersecting a transparent surface: a reflection and a transmission ray. The result is linearly interpolated via the`R`

parameter:Blending is then done by usingR = R

_{0}+ (1-R_{0})(1-cos*θ*)^{5}`R`as the linear interpolant between the reflected and transmitted colors, then this resultant color is used just as the transmitted color was blended with the surface color above.

- The
`model.txt`

file used to generate the above image is:camera cam1 { pixeldim 640 480 worlddim 8 6 viewpoint 4 3 6 } light centerback { location 3 4 -1 emissivity 1 1 1 } light backleft { location 1 1 0 emissivity 1 1 1 } light topright { location 6 4 1 emissivity 1 1 1 } material green { ambient 0 5 0 } material red { ambient 5 0 0 diffuse .7 .7 .7 specular .3 .3 .3 } material blue { ambient 0 0 5 diffuse .2 .2 .2 specular .8 .8 .8 } material cyan { ambient 0 4 5 diffuse .2 .2 .2 specular .8 .8 .8 alpha .4 ior 1.337 } material yellow { ambient 5 4 0 diffuse .7 .7 .7 specular .3 .3 .3 } plane leftwall { material green normal 3 0 1 point 0 0 0 } plane rightwall { material yellow normal -3 0 1 point 8 0 0 } material gray { ambient 2 2 2 } plane floor { material gray normal 0 1 0 point 0 -0.2 0 } sphere upperright { material red center 6 4 -2 radius 2 } sphere central { material blue center 2 2 -2 radius 1.3 } sphere vitreous { material cyan center 4.3 2.3 -1 radius 2.3 }

`tar.gz`

archive of your asg##/ directory, including:
- A
`README`

file containing- Course id--section no
- Name
- Lab description
- Brief solution description (e.g., program design, description of algorithm, etc., however appropriate).
- Lessons learned, identified interesting features of your program
- Any special usage instructions

`Makefile`

- source code (
`.h`

headers and`.cpp`

source) ~~object code~~(do a`make clean`

before`tar`

)

`handin`

notes