ray_t::trace()
routine to spawn a transmission ray
(meaning, for example,
ray_t *transmission = new ray_t(hit,t,dis);
)
for any object intersected that has alpha > 0
.
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).
(n1/n2)(u - cosθ1N) - cosθ2Nwhere
model_t::find_closest()
),
alpha
value is > 0
(in other words
only when the ray encounters a transparent object).
color = ((1.0 - alpha) * color) + (alpha * transmitted_color);
where transmitted_color
is the transparent color set
by the transmission ray (don't forget to clamp the color to
[0,1] range).
cbox.txt
given below, your ray tracer should
now render the image below of a transparent sphere.
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 cbox.txt
file and
be able to write it out.
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:
closest_dist
to
INFINITY
instead of to -1
obj==last_obj ||
evaluation from the
initial call to obj->hits()
—the current
object should only be skipped if the returned
dist < 0
(0.00001 < dist) && (dist < closest_dist)
(the distance to the intersection point must be non-zero)
vec_t::refract(const vec_t& n, double n_t) const
function that refracts the given (e.g., this
)
vector about n
with n2 = nt.
Writing a
vec_t::reflect(const vec_t& n) const
function for reflection is also a good idea, where the resultant
reflection vector is
u - 2.0(u·N)N.
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
).
t1
is returned, then we are exiting the
sphere.
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 5, return (prune this ray as it has already
bounced too many times).
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:
R = R0 + (1-R0)(1-cosθ)5Blending is then done by using 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.
cbox.txt
file used to generate the above image is:
camera cam
{
pixeldim 512 384
worlddim 5.12 3.84
viewpoint 2.56 2 5
}
light top
{
location 2.56 3.80 -1.5
emissivity 1 1 1
}
material gray
{
ambient 3 3 3
diffuse .9 .9 .9
}
material green
{
ambient 0 5 0
diffuse 0 .5 0
}
material salamander
{
ambient 3 2 2
diffuse .9 .9 .9
}
material slate
{
ambient 2 1.8 3
diffuse .9 .9 .9
}
material transparent
{
ambient 3 3 3
diffuse .1 .1 .1
specular .9 .9 .9
alpha .9
ior 1.83
}
material chrome
{
ambient 3 3 3
diffuse .1 .1 .1
specular .9 .9 .9
}
plane backwall
{
material gray
normal 0 0 1
point 0 0 -5
}
plane leftwall
{
material salamander
normal 1 0 0
point 0 0 0
}
plane rightwall
{
material slate
normal -1 0 0
point 5.12 0 0
}
plane ceiling
{
material gray
normal 0 -1 0
point 0 3.84 0
}
plane floor
{
material gray
normal 0 1 0
point 0 -0.2 0
}
sphere left
{
material chrome
center 1.25 .75 -4
radius .9
}
sphere right
{
material transparent
center 3.7 .7 -2.3
radius .9
}
tar.gz
archive of your asg##/ directory, including:
README
file containing
Makefile
.h
headers and .cpp
source)
make clean
before tar
)
handin
notes